From 6be0453210dbb0f4fd2438fba64df273fcedd124 Mon Sep 17 00:00:00 2001 From: Leo Li Date: Fri, 19 Jul 2024 12:44:01 -0400 Subject: [PATCH 01/26] Add the readme for sample app codes, and update the code-sample page (#6059) * feat: add the readme for sample app codes, and modify the code-sample page to include bookstore app * fix: fix the wrong link * fix: add a note box to mention all 3 parts of knative are being convered in bookstore tutorial --- .../eventing/bookstore-sample-app/README.md | 38 ++++++++++++++++ .../bookstore-sample-app/solution/README.md | 45 +++++++++++++++++++ .../bookstore-sample-app/start/README.md | 26 +++++++++++ docs/samples/README.md | 4 ++ 4 files changed, 113 insertions(+) create mode 100644 code-samples/eventing/bookstore-sample-app/README.md create mode 100644 code-samples/eventing/bookstore-sample-app/solution/README.md create mode 100644 code-samples/eventing/bookstore-sample-app/start/README.md diff --git a/code-samples/eventing/bookstore-sample-app/README.md b/code-samples/eventing/bookstore-sample-app/README.md new file mode 100644 index 00000000000..21a4b18b0ed --- /dev/null +++ b/code-samples/eventing/bookstore-sample-app/README.md @@ -0,0 +1,38 @@ +# Knative Bookstore Code Samples + +This folder contains code samples for the Knative Bookstore tutorial, an end-to-end sample application demonstrating Knative's capabilities in building an event-driven architecture. + +## Tutorial + +For a comprehensive guide on building this application and learning about Knative, please visit the [Knative Bookstore Tutorial](https://knative.dev/bookstore/page-0/welcome-knative-bookstore-tutorial/). + +This tutorial covers: +- Setting up your environment +- Implementing event-driven architecture with Knative +- Deploying and connecting various microservices +- Integrating machine learning models +- Connecting to external services like Slack + +Whether you're new to Knative or looking to deepen your understanding, this tutorial provides valuable insights into building scalable, event-driven applications. + +## Contents + +The files are organized into two main folders: + +1. **/start**: Contains the initial code structure and base files to begin the tutorial. + +2. **/solution**: Includes the complete, fully implemented version of the Knative Bookstore application. + +For more details on the directory structure and contents of each folder, please refer to their respective README files: + +- [Start README](start/README.md) +- [Solution README](solution/README.md) + +## Getting Started + +1. Clone this repository +2. Navigate to the `/start` directory to begin the tutorial +3. Follow the Knative Bookstore Tutorial for step-by-step instructions +4. Refer to the `/solution` directory if you need to check the final implementation + +Happy coding! \ No newline at end of file diff --git a/code-samples/eventing/bookstore-sample-app/solution/README.md b/code-samples/eventing/bookstore-sample-app/solution/README.md new file mode 100644 index 00000000000..a156417957a --- /dev/null +++ b/code-samples/eventing/bookstore-sample-app/solution/README.md @@ -0,0 +1,45 @@ + +# Knative Bookstore Tutorial - Solution Directory + +Welcome to the solution directory of the Knative Bookstore tutorial. This directory contains the fully implemented version of the event-driven bookstore application using Knative. + +You can find the tutorial for this solution [here](https://knative.dev/bookstore/page-0/welcome-knative-bookstore-tutorial/). + +## Directory Structure + +Here's an overview of the components in the solution: + +- `bad-word-filter/`: Knative Function for filtering out inappropriate content +- `db-service/`: Database service for storing book reviews and comments +- `frontend/`: User interface for the bookstore application built with Next.js +- `node-server/`: Node.js server for handling backend operations +- `sentiment-analysis-app/`: Knative Function for analyzing the sentiment of book reviews +- `sequence/`: Knative Sequence setup for orchestrating workflows +- `slack-sink/`: Integration with Slack for notifications with Apache Camel + +## Additional Files + +- `setup.sh`: Script for setting up the required services including installing Knative, frontend, and backend node-server +- `solution.sh`: Script for installing everything, deploying the entire solution. **It includes the setup script as well.** + +## Running the Solution + +1. Have a running Kubernetes cluster. +2. Install all the prerequisites and deploy the entire solution using the `solution.sh` script: + ``` + ./solution.sh + ``` +If you encountered any permission issues, run the following command: + ``` + chmod +x solution.sh + ``` + +## Next Steps + +- Explore each component to understand how they work together in an event-driven architecture. +- Compare this solution with your own implementation if you've completed the tutorial. +- Experiment with modifying or extending the solution to add new features. + +## Need Help? + +If you encounter any issues or have questions about the solution, refer to the main tutorial documentation or reach out to the Knative community for support. \ No newline at end of file diff --git a/code-samples/eventing/bookstore-sample-app/start/README.md b/code-samples/eventing/bookstore-sample-app/start/README.md new file mode 100644 index 00000000000..70f8107d4b2 --- /dev/null +++ b/code-samples/eventing/bookstore-sample-app/start/README.md @@ -0,0 +1,26 @@ +# Knative Bookstore Tutorial - Start Directory + +Welcome to the starting point of the Knative Bookstore tutorial. This directory contains the initial setup and base files for building your event-driven bookstore application using Knative. + +## Directory Structure + +Here's an overview of the components you'll be working with: + +- `db-service/`: Database service for storing book reviews and comments +- `frontend/`: User interface for the bookstore application built with Next.js +- `node-server/`: Node.js server for handling backend operations +- `sequence/`: Knative Sequence setup for orchestrating workflows +- `slack-sink/`: Integration with Slack for notifications with Apache Camel +- `setup.sh`: Script for setting up the required services including installing Knative, frontend, and backend node-server +## Getting Started + +1. Familiarize yourself with the directory structure above. +2. Each subdirectory contains starter code and placeholders for the services you'll be building. +3. Follow the [Knative Bookstore Tutorial](https://knative.dev/bookstore/page-0/welcome-knative-bookstore-tutorial/) for step-by-step instructions on how to implement each component. +4. As you progress through the tutorial, you'll be adding code and configurations to these directories. + +Remember, this is just the starting point. By the end of the tutorial, you'll have a fully functional event-driven bookstore application. + +## Need Help? + +If you encounter any issues or have questions, refer to the main tutorial documentation or reach out to the Knative community for support. \ No newline at end of file diff --git a/docs/samples/README.md b/docs/samples/README.md index 74f8c96dc31..cf5a4540274 100755 --- a/docs/samples/README.md +++ b/docs/samples/README.md @@ -9,6 +9,10 @@ Knative code samples that are actively tested and maintained by Knative working - [Eventing and Eventing Sources code samples](eventing.md) - [Serving code samples](serving.md) +- [E2E Sample Application - Knative Bookstore](https://github.com/knative/docs/tree/main/code-samples/eventing/bookstore-sample-app) + +!!! tip + E2E Sample Application - Knative Bookstore is a sample application that demonstrates how to use all part of Knative: **Eventing, Serving, and Function**, to build a simple bookstore application. ## Community owned samples From 1bf25436c152ec03961f543f3bc8a931ad21cce0 Mon Sep 17 00:00:00 2001 From: Dilip Gowda Bhagavan <110233170+dilipgb@users.noreply.github.com> Date: Sun, 21 Jul 2024 19:19:20 +0530 Subject: [PATCH 02/26] add documentation for running knative on IBM s390x/IBM ppc64le platforms (#6043) * added documentation to configure network for s390x * adding authentication details for redhat catalog * chore: updated review comments * corrected allignment * corrected alignment * fix indentations * Apply suggestions from code review Co-authored-by: David Hadas * corrected intendetion in file * correct allignment in file * Update docs/install/yaml-install/serving/install-serving-with-yaml-on-IBM-Z-and-IBM-P.md --------- Co-authored-by: David Hadas --- ...ll-serving-with-yaml-on-IBM-Z-and-IBM-P.md | 22 +++++++++++++++++++ .../serving/install-serving-with-yaml.md | 4 ++++ 2 files changed, 26 insertions(+) create mode 100644 docs/install/yaml-install/serving/install-serving-with-yaml-on-IBM-Z-and-IBM-P.md diff --git a/docs/install/yaml-install/serving/install-serving-with-yaml-on-IBM-Z-and-IBM-P.md b/docs/install/yaml-install/serving/install-serving-with-yaml-on-IBM-Z-and-IBM-P.md new file mode 100644 index 00000000000..345b2e5af9b --- /dev/null +++ b/docs/install/yaml-install/serving/install-serving-with-yaml-on-IBM-Z-and-IBM-P.md @@ -0,0 +1,22 @@ +# Install a networking layer on IBM Z and IBM Power platforms + +This additional step is required for installing the Kourier networking layer on IBM Z and IBM Power platforms. + +Once you completed installing Kourier, patch the envoy image as described below. Use the envoy image included as part of the [RedHat Maistra](https://maistra.io/) distribution. Maistra is an opinionated distribution of Istio designed to work with OpenShift and is supported on IBM Z and IBM Power platforms. + +1. Find the image name to use: + 1. Access the [redhat catalog](https://catalog.redhat.com/software/containers/openshift-service-mesh/proxyv2-rhel8/5d2cda455a134672890f640a) + 2. Choose the appropriate architecture (ppc64le/s390x) from the architecture drop down. + 3. Choose the latest tag from the list of available tags at the tag dropdown. + 4. Click on the "get this image" tab and copy the image name. For example: `registry.redhat.io/openshift-service-mesh/proxyv2-rhel8@sha256:ced904...` + +2. Patch the **3scale-kourier-gateway** deployment in **kourier-system** namespace with latest available image using **kubectl** as shown below. + + ```bash + kubectl patch deployment 3scale-kourier-gateway -n kourier-system -p \ + '{"spec":{"template":{"spec":{"containers":[{"name":"kourier-gateway" "image":""}]}}}}' + ``` + +!!! note + 1. If there are authentication issues, create [redhat developer account](developers.redhat.com/register) to pull images from redhat catalog. + 2. Please refer to the page to [configure pull secrets](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#add-imagepullsecrets-to-a-service-account) \ No newline at end of file diff --git a/docs/install/yaml-install/serving/install-serving-with-yaml.md b/docs/install/yaml-install/serving/install-serving-with-yaml.md index 3d9b45a1817..044f341f5f2 100644 --- a/docs/install/yaml-install/serving/install-serving-with-yaml.md +++ b/docs/install/yaml-install/serving/install-serving-with-yaml.md @@ -29,6 +29,10 @@ To install the Knative Serving component: The following tabs expand to show instructions for installing a networking layer. Follow the procedure for the networking layer of your choice: +!!! note + **Only Kourier network plugin supported for IBM Z and IBM Power platform.** + Follow the below steps to install Kourier. Post installation, patch the envoy image based on RedHat Maistra as described in [this link](./install-serving-with-yaml-on-IBM-Z-and-IBM-P.md). + From d8db1f82409a63ded699c606c07c197327e09587 Mon Sep 17 00:00:00 2001 From: Knative Automation Date: Mon, 22 Jul 2024 04:06:58 -0400 Subject: [PATCH 03/26] upgrade to latest dependencies (#6063) bumping knative.dev/hack 1133b37...b979959: > b979959 Update community files (# 387) > 0914314 Update community files (# 384) > 3b6d644 Update community files (# 383) > 68e3bfb Update community files (# 382) > abdcdea Update community files (# 380) > 9f6c92e Update community files (# 379) Signed-off-by: Knative Automation --- go.mod | 2 +- go.sum | 4 ++-- vendor/modules.txt | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 3001f6bca72..577042ca69b 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( google.golang.org/grpc v1.36.0 gopkg.in/go-playground/webhooks.v3 v3.13.0 gopkg.in/yaml.v2 v2.3.0 - knative.dev/hack v0.0.0-20240404013450-1133b37da8d7 + knative.dev/hack v0.0.0-20240704013904-b9799599afcf ) require ( diff --git a/go.sum b/go.sum index 2b2066209ef..d77e752e739 100644 --- a/go.sum +++ b/go.sum @@ -519,8 +519,8 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.5 h1:nI5egYTGJakVyOryqLs1cQO5dO0ksin5XXs2pspk75k= honnef.co/go/tools v0.0.1-2020.1.5/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -knative.dev/hack v0.0.0-20240404013450-1133b37da8d7 h1:fkWYWvdHm1mVHevKW2vVJnZtxH0NzOlux8imesweKwE= -knative.dev/hack v0.0.0-20240404013450-1133b37da8d7/go.mod h1:yk2OjGDsbEnQjfxdm0/HJKS2WqTLEFg/N6nUs6Rqx3Q= +knative.dev/hack v0.0.0-20240704013904-b9799599afcf h1:n92FmZRywgtHso7pFAku7CW0qvRAs1hXtMQqO0R6eiE= +knative.dev/hack v0.0.0-20240704013904-b9799599afcf/go.mod h1:yk2OjGDsbEnQjfxdm0/HJKS2WqTLEFg/N6nUs6Rqx3Q= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/vendor/modules.txt b/vendor/modules.txt index a1c8961264c..5db94568bba 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -300,7 +300,7 @@ gopkg.in/go-playground/webhooks.v3/github gopkg.in/yaml.v2 # honnef.co/go/tools v0.0.1-2020.1.5 ## explicit; go 1.11 -# knative.dev/hack v0.0.0-20240404013450-1133b37da8d7 +# knative.dev/hack v0.0.0-20240704013904-b9799599afcf ## explicit; go 1.18 knative.dev/hack # go.opencensus.io => go.opencensus.io v0.20.2 From 7129b49f05d0cb1a79aee612fe3d1a77b9070741 Mon Sep 17 00:00:00 2001 From: Rishikesh Jagadale <87235655+rissh@users.noreply.github.com> Date: Tue, 23 Jul 2024 01:23:10 +0530 Subject: [PATCH 04/26] Update button border radius on Tutorial page (#6070) --- docs/stylesheets/extra.css | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css index d5217cf03c9..4a008bcd66b 100644 --- a/docs/stylesheets/extra.css +++ b/docs/stylesheets/extra.css @@ -204,6 +204,7 @@ border-radius: 0.7rem 0 0 0 ; .md-typeset .md-button { color: #024c93; + border-radius: 0.7rem; } /* Giving h4 tag distinctive style because it is non-differntial with bold text */ From 940473b4b54fdf5eabca18954bc863887e7c869e Mon Sep 17 00:00:00 2001 From: Calum Murray Date: Tue, 23 Jul 2024 11:46:07 -0400 Subject: [PATCH 05/26] feat: document cross namespace event links (#6073) Signed-off-by: Calum Murray --- config/nav.yml | 1 + docs/eventing/features/README.md | 22 ++++++----- .../features/cross-namespace-event-links.md | 37 +++++++++++++++++++ 3 files changed, 50 insertions(+), 10 deletions(-) create mode 100644 docs/eventing/features/cross-namespace-event-links.md diff --git a/config/nav.yml b/config/nav.yml index d8f2ee35cb4..519aabb102b 100644 --- a/config/nav.yml +++ b/config/nav.yml @@ -304,6 +304,7 @@ nav: - Transport Encryption: eventing/features/transport-encryption.md - Sender Identity: eventing/features/sender-identity.md - Eventing with Istio: eventing/features/istio-integration.md + - Cross Namespace Event Links: eventing/features/cross-namespace-event-links.md - FAQ: eventing/faq/README.md # Eventing reference docs - Reference: diff --git a/docs/eventing/features/README.md b/docs/eventing/features/README.md index cdd9000bceb..7d94c7cc8fa 100644 --- a/docs/eventing/features/README.md +++ b/docs/eventing/features/README.md @@ -66,13 +66,15 @@ data: The following table gives an overview of the available features in Knative Eventing: -| Feature | Flag | Description | Maturity | -|------------------------------------------------------------|------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------| -| [DeliverySpec.RetryAfterMax field](delivery-retryafter.md) | `delivery-retryafter` | Specify a maximum retry duration that overrides HTTP [Retry-After](https://datatracker.ietf.org/doc/html/rfc7231#section-7.1.3) headers when calculating backoff times for retrying **429** and **503** responses. | Alpha, disabled by default | -| [DeliverySpec.Timeout field](delivery-timeout.md) | `delivery-timeout` | When using the `delivery` spec to configure event delivery parameters, you can use the`timeout` field to specify the timeout for each sent HTTP request. | Beta, enabled by default | -| [KReference.Group field](kreference-group.md) | `kreference-group` | Specify the API `group` of `KReference` resources without the API version. | Alpha, disabled by default | -| [Knative reference mapping](kreference-mapping.md) | `kreference-mapping` | Provide mappings from a [Knative reference](https://github.com/knative/specs/blob/main/specs/eventing/overview.md#destination) to a templated URI. | Alpha, disabled by default | -| [New trigger filters](new-trigger-filters.md) | `new-trigger-filters` | Enables a new Trigger `filters` field that supports a set of powerful filter expressions. | Beta, enabled by default | -| [Transport encryption](transport-encryption.md) | `transport-encryption` | Enables components to encrypt traffic using TLS by exposing HTTPS URL. | Beta, disabled by default | -| [Sender Identity](sender-identity.md) | `authentication-oidc` | Enables Eventing sources to send authenticated requests and addressables to require authenticated requests. | Alpha, disabled by default | -| [Eventing with Istio](istio-integration.md) | `istio` | Enables Eventing components to communicate with workloads in an Istio mesh. | Beta, disabled by default | +| Feature | Flag | Description | Maturity | +|---------------------------------------------------------------|-------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------| +| [DeliverySpec.RetryAfterMax field](delivery-retryafter.md) | `delivery-retryafter` | Specify a maximum retry duration that overrides HTTP [Retry-After](https://datatracker.ietf.org/doc/html/rfc7231#section-7.1.3) headers when calculating backoff times for retrying **429** and **503** responses. | Alpha, disabled by default | +| [DeliverySpec.Timeout field](delivery-timeout.md) | `delivery-timeout` | When using the `delivery` spec to configure event delivery parameters, you can use the`timeout` field to specify the timeout for each sent HTTP request. | Beta, enabled by default | +| [KReference.Group field](kreference-group.md) | `kreference-group` | Specify the API `group` of `KReference` resources without the API version. | Alpha, disabled by default | +| [Knative reference mapping](kreference-mapping.md) | `kreference-mapping` | Provide mappings from a [Knative reference](https://github.com/knative/specs/blob/main/specs/eventing/overview.md#destination) to a templated URI. | Alpha, disabled by default | +| [New trigger filters](new-trigger-filters.md) | `new-trigger-filters` | Enables a new Trigger `filters` field that supports a set of powerful filter expressions. | Beta, enabled by default | +| [Transport encryption](transport-encryption.md) | `transport-encryption` | Enables components to encrypt traffic using TLS by exposing HTTPS URL. | Beta, disabled by default | +| [Sender Identity](sender-identity.md) | `authentication-oidc` | Enables Eventing sources to send authenticated requests and addressables to require authenticated requests. | Alpha, disabled by default | +| [Eventing with Istio](istio-integration.md) | `istio` | Enables Eventing components to communicate with workloads in an Istio mesh. | Beta, disabled by default | +| [Cross Namespace Event Links](cross-namespace-event-links.md) | `cross-namespace-event-links` | Enables subscriptions and triggers to refer to brokers and channels in different namespaces. | Alpha, disabled by default | + diff --git a/docs/eventing/features/cross-namespace-event-links.md b/docs/eventing/features/cross-namespace-event-links.md new file mode 100644 index 00000000000..77afbaf243a --- /dev/null +++ b/docs/eventing/features/cross-namespace-event-links.md @@ -0,0 +1,37 @@ +# Cross Namespace Event Links + +**Flag name**: `cross-namespace-event-links` + +**Stage**: Alpha, disabled by default + +**Tracking issue**: [#7530](https://github.com/knative/eventing/issues/7530) +## Overview + +This feature enables triggers and subscriptions (event links) to refer to a broker +or channel in a different namespace. Without this feature, the trigger or subscription +must be in the same namespace as the broker or channel. + +## RBAC + +To ensure that users can only subscribe to events from a broker or channel in a separate +namespace when they are allowed to, this feature introduces a new RBAC verb `knsubscribe` +which a user must have to create a trigger or subscription referencing a broker or channel +in another namespace. An example of a role with the correct verb can be seen below: + +```yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: example-cross-namespace-role + namespace: ns-1 +rules: + - apiGroups: + - "eventing.knative.dev" + resources: + - brokers + verbs: + - knsubscribe +``` + +This role will give users the ability to create triggers referring to a broker in namespace +`ns-1` in every namespace they have the ability to create triggers. From c98a44ee2460015b58c605d5525d14cf3c4d1607 Mon Sep 17 00:00:00 2001 From: Calum Murray Date: Wed, 24 Jul 2024 03:57:54 -0400 Subject: [PATCH 06/26] feat: added documentation for keda scaling of Kafka dispatcher components (#6061) Signed-off-by: Calum Murray --- config/nav.yml | 1 + .../broker-types/kafka-broker/README.md | 4 ++ .../configuring-kafka-features.md | 14 ++-- .../kafka-channel-configuration.md | 4 ++ .../configuration/keda-configuration.md | 67 +++++++++++++++++++ docs/eventing/sources/kafka-source/README.md | 21 +----- 6 files changed, 87 insertions(+), 24 deletions(-) create mode 100644 docs/eventing/configuration/keda-configuration.md diff --git a/config/nav.yml b/config/nav.yml index 519aabb102b..a9721a60381 100644 --- a/config/nav.yml +++ b/config/nav.yml @@ -285,6 +285,7 @@ nav: - Configure Apache Kafka Channel defaults: eventing/configuration/kafka-channel-configuration.md - Configure event source defaults: eventing/configuration/sources-configuration.md - Configure Sugar Controller: eventing/configuration/sugar-configuration.md + - Configure KEDA Autoscaling of Knative Kafka Resources: eventing/configuration/keda-configuration.md # Eventing - observability - Observability: - Accessing CloudEvent traces: eventing/accessing-traces.md diff --git a/docs/eventing/brokers/broker-types/kafka-broker/README.md b/docs/eventing/brokers/broker-types/kafka-broker/README.md index 9fec6c03685..b3670d299ea 100644 --- a/docs/eventing/brokers/broker-types/kafka-broker/README.md +++ b/docs/eventing/brokers/broker-types/kafka-broker/README.md @@ -465,6 +465,10 @@ All the configuration mechanisms that are available for the `Kafka` Broker class * A few more configmaps are propagated: `config-tracing` and `kafka-config-logging`. This means, tracing and logging are also not configurable per namespace. * Similarly, the data plane deployments are propagated from the `knative-eventing` namespace to the user namespace. This means that the data plane deployments are not configurable per namespace and will be identical to the ones in the `knative-eventing` namespace. +### Enabling and configuring autoscaling of triggers with KEDA + +To enable and configreu autoscaling of triggers referencing Kafka Brokers with KEDA, follow [the instructions here](../../../configuration/keda-configuration.md). + ## Additional information - To report a bug or request a feature, open an issue in the [eventing-kafka-broker repository](https://github.com/knative-extensions/eventing-kafka-broker). diff --git a/docs/eventing/brokers/broker-types/kafka-broker/configuring-kafka-features.md b/docs/eventing/brokers/broker-types/kafka-broker/configuring-kafka-features.md index ed67487b47a..19ad9a87885 100644 --- a/docs/eventing/brokers/broker-types/kafka-broker/configuring-kafka-features.md +++ b/docs/eventing/brokers/broker-types/kafka-broker/configuring-kafka-features.md @@ -52,9 +52,10 @@ The `brokers.topic.template` values determines the template used to generate the The `channels.topic.template` value determines the template used to generate the kafka topic names used by your channels. -* **Global Key:** `channels.topic.template` -* **Possible values:** Any valid [go text/template](https://pkg.go.dev/text/template) -* **Default:** `{% raw %}messaging-kafka.{{ .Namespace }}.{{ .Name }}{% endraw %}` +* **Global Key:** `controller-autoscaler-keda` +* **Possible values:** One of: `enabled`, `disabled` +* **Default:** `disabled` +* **Stability**: Alpha **Example:** @@ -66,5 +67,10 @@ The `channels.topic.template` value determines the template used to generate the name: config-kafka-features namespace: knative-eventing data: - channels.topic.template: {% raw %}"messaging-kafka.{{ .Namespace }}.{{ .Name }}"{% endraw %} + controller-autoscaler-keda: enabled ``` + +## Dispatcher autoscaling with KEDA + +The `controller-autoscaler-keda` value determines whether Knative Kafka dispatcher components will autoscale with KEDA. +For more information on this feature, please read [the documentation here](../../../configuration/keda-configuration.md) diff --git a/docs/eventing/configuration/kafka-channel-configuration.md b/docs/eventing/configuration/kafka-channel-configuration.md index e0ee35913b0..9e08fa96953 100644 --- a/docs/eventing/configuration/kafka-channel-configuration.md +++ b/docs/eventing/configuration/kafka-channel-configuration.md @@ -62,3 +62,7 @@ To use Kafka Channels, you must: kubectl apply -f .yaml ``` Where `` is the name of the file you created in the previous step. + +## Enable/configure autoscaling of KafkaChannel dispatchers + +To enable autoscaling of the KafkaChannel dispatcher you can read [the instructions here](./keda-configuration.md) diff --git a/docs/eventing/configuration/keda-configuration.md b/docs/eventing/configuration/keda-configuration.md new file mode 100644 index 00000000000..e53fd7fd5b2 --- /dev/null +++ b/docs/eventing/configuration/keda-configuration.md @@ -0,0 +1,67 @@ +# Configure KEDA Autoscaling of Knative Kafka Resources + +All of the Knative Kafka components which dispatch events (source, channel broker) support scaling the dispatcher data plane with KEDA. + +!!! important + This feature is Alpha + +## Enable Autoscaling of Kafka components + +!!! important + Note that enabling autoscaling will enable scaling for all KafkaSources, Triggers referencing Kafka Brokers, and Subscriptions referencing KafkaChannels + +To enable the feature, you need to modify the `config-kafka-features` configmap and set the `controller-autoscaler-keda` flag to `enabled`. +Note that in order for this feature to work, you must also install KEDA into your cluster. + +After your changes your configmap should look like: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: config-kafka-features + namespace: knative-eventing +data: + controller-autoscaler-keda: enabled + # other features and config options... + +``` + +## Configure Autoscaling for a Resource + +If you want to customize how KEDA scales a KafkaSource, trigger, or subscription you can set annotations on the resource: + +```yaml +apiVersion: .knative.dev/v1 +kind: +metadata: + annotations: + # The minimum number of replicas to scale down to + autoscaling.eventing.knative.dev/min-scale: "0" + # The maximum number of replicas to scale up to + autoscaling.eventing.knative.dev/max-scale: "50" + # The interval in seconds the autoscaler uses to poll metrics in order to inform its scaling decisions + autoscaling.eventing.knative.dev/polling-interval: "10" + # The period in seconds the autoscaler waits until it scales down + autoscaling.eventing.knative.dev/cooldown-period: "30" + # The lag that is used for scaling (1<->N) + autoscaling.eventing.knative.dev/lag-threshold: "100" + # The lag that is used for activation (0<->1) + autoscaling.eventing.knative.dev: "0" +spec: + # Spec fields for the resource... +``` + +## Disable Autoscaling for a Resource + +If you want to disable autoscaling for a KafkaSource, trigger, or subscription, you need to set an annotation on the resource: + +```yaml +apiVersion: .knative.dev/v1 +kind: +metadata: + annotations: + autoscaling.eventing.knative.dev/class: disabled +spec: + # Spec fields for the resource... +``` diff --git a/docs/eventing/sources/kafka-source/README.md b/docs/eventing/sources/kafka-source/README.md index d2631ab65f1..9fdd2278ca2 100644 --- a/docs/eventing/sources/kafka-source/README.md +++ b/docs/eventing/sources/kafka-source/README.md @@ -208,26 +208,7 @@ Alternatively, if you are using a GitOps approach, you can add the `consumers` k ### Automatic Scaling with KEDA -Kafka Sources and Brokers for Apache Kafka have (Alpha) support for serverless scaling with KEDA, including scale to zero. If you want Knative and KEDA to scale your Kafka source for you, -you must [install KEDA](https://keda.sh/docs/2.13/deploy/), and then enable the feature flag. - -To enable the feature flag, you need to create or modify the `config-kafka-features` configmap in the `knative-eventing` namespace. You can create the file as below: - -```yaml - - apiVersion: v1 - kind: Configmap - metadata: - name: config-kafka-features - namespace: knative-eventing - data: - controller-autoscaler-keda: "enabled" - -``` - -From there, apply the configmap into your cluster and assuming that KEDA is also installed your Kafka Sources will scale for you! For more information on other values you -can add to the `config-kafka-features` configmap, [read about the Kafka Broker features](../../brokers/broker-types/kafka-broker/configuring-kafka-features). - +You are able to autoscale the KafkaSource with KEDA. For information on how to enable and configure this feature, please read [the instructions here](../../configuration/keda-configuration.md). ### Verify From 7347a41efd76e4bc2a0575f50cfabc1fc23393d7 Mon Sep 17 00:00:00 2001 From: Calum Murray Date: Fri, 26 Jul 2024 10:09:13 -0400 Subject: [PATCH 07/26] feat: add blog post with demo of LLM Agents on Knative (#6074) * feat: add blog post with demo of LLM Agents on Knative Signed-off-by: Calum Murray * fix review comments Signed-off-by: Calum Murray * fix: url to prev blog Signed-off-by: Calum Murray * eventtypes -> EventTypes Signed-off-by: Calum Murray * add link to slack Signed-off-by: Calum Murray --------- Signed-off-by: Calum Murray --- blog/config/nav.yml | 1 + blog/docs/articles/llm-agents-demo.md | 147 ++++++++++++++++++++++++++ 2 files changed, 148 insertions(+) create mode 100644 blog/docs/articles/llm-agents-demo.md diff --git a/blog/config/nav.yml b/blog/config/nav.yml index f06e40f3ff3..2184456641c 100644 --- a/blog/config/nav.yml +++ b/blog/config/nav.yml @@ -47,6 +47,7 @@ nav: - releases/announcing-knative-v0-3-release.md - releases/announcing-knative-v0-2-release.md - Articles: + - articles/llm-agents-demo.md - articles/llm-agents-overview.md - articles/cross-namespace-event-links-feature.md - articles/aws_to_func_migration.md diff --git a/blog/docs/articles/llm-agents-demo.md b/blog/docs/articles/llm-agents-demo.md new file mode 100644 index 00000000000..588e2e79128 --- /dev/null +++ b/blog/docs/articles/llm-agents-demo.md @@ -0,0 +1,147 @@ +# LLM Agents with Knative: A Demo + +**Author: [Calum Murray](https://www.linkedin.com/in/calum-ra-murray/), Software Engineering Intern @ Red Hat** + +In the [previous blog post on LLM Agents](/blog/articles/llm-agents-overview) +we discussed what LLM Agents are, how LLMs call tools, and how Knative can +be used to automate the tool calling process for LLM Agents. In this blog post +we will be looking at a concrete example of how you can build an LLM Agent +application with Knative handling the tool calling and discovery, and explaining +what differentiates this approach from the other common approaches for building +LLM Agents. + +## An example LLM Agent using Knative + +To showcase the power of building LLM Agents with the tool discovery and +calling handled by Knative, we are going to build a simple chat application +that is capable of answering questions about the cost of resources being +used for a fictitious application we are running. Specifically, in our +application we are interested in accurately answering questions such as: + +> How has the trend in the average resource consumption (CPU, memory) +changed over the past few months for my application, and what impact +will this have on my costs? + +To begin, we will be deploying the Knative LLM Tool Provider demo into +a cluster we have access to following the instructions in the README in +[https://github.com/keventmesh/llm-tool-provider](https://github.com/keventmesh/llm-tool-provider). +Once we have deployed the chat app from this repository, we are able to access it by running: + +```sh +kubectl port-forward svc/chat-app-service 8080:8080 +``` + +If you access `http://localhost:8080` in your browser you will now be able +to see the chat application running, and ask it our simple question. When +I tried this while writing the blog post, the interaction was: + +Calum: +> How has the trend in the average resource consumption (CPU, memory) +changed over the past few months for my application, and what impact +will this have on my costs? + +LLM Agent: +> Could you provide me with the data on the average resource consumption +(CPU, GPU, memory) for your application over the past few months? + +If you try this you will likely notice that your LLM agent replies similarly, +and that the UI will indicate in the task list a task called “human”. This is +the LLM calling the one hand-coded tool that we have in our sample app: a tool +that asks the user (the human) for more information before continuing to answer +the question. + +From this interaction, we can see that the LLM isn’t capable of answering our +question yet: it has no information about the resource consumption or about +what the costs associated with that resource consumption are. To give the LLM +these capabilities we need to tell it about the two Knative Functions we +deployed into our cluster in the setup of the sample app: +`average-resource-consumption` and `resource-cost-calculator`. To do this +we will need to apply two EventTypes into our cluster which describe the +contracts expected by these Functions: + +```yaml +apiVersion: eventing.knative.dev/v1beta2 +kind: EventType +metadata: + name: average.resource.consumption +spec: + reference: + apiVersion: serving.knative.dev/v1 + kind: Service + name: average-resource-consumption + description: "This tells you the average resource consumption for recent months" + type: "average.resource.consumption" +--- +apiVersion: eventing.knative.dev/v1beta2 +kind: EventType +metadata: + name: resource.cost.calculator +spec: + reference: + apiVersion: serving.knative.dev/v1 + kind: Service + name: resource-cost-calculator + description: "This calculates the cost for a given resource kind and average usage over a month. Use this tool whenever there is a question about the cost of any cloud resources" + schemaData: '{"resourceKind":{"type":"string","description":"The type of resource you would like to calculate the cost of"},"usage":{"type":"float","description":"The average usage of the resource"},"unit":{"type":"string","description":"The unit of the resource usage"}}' + type: "resource.cost.calculator" +``` + +Both of these EventTypes refer to functions which were deployed in the install +script we ran earlier. One function returns some mock usage data for the past +few months, and the other is able to calculate the cost due to the usage of a +specific resource type for a specific month. + +The LLM Agents we built is programmed to fetch all the EventTypes in the cluster +whenever a new user session starts, and map those into tools it can use. After +applying both EventTypes and refreshing our brower, we can try asking our original +question again: + +Calum: +> How has the trend in the average resource consumption (CPU, memory) changed +over the past few months for my application, and what impact will this have on +my costs? + +LLM Agent: +> The trend in the average resource consumption for your application over the +past few months is as follows: + +> - March: CPU - 21.33 Cores, Memory - 8200 MiB +> - April: CPU - 27.56 Cores, Memory - 8117 MiB +> - May: CPU - 33.17 Cores, Memory - 9217 MiB +> - June: CPU - 34.51 Cores, Memory - 10117 MiB + +> To determine the impact on your costs, I will calculate the cost for CPU and +memory based on the average usage over a month for each resource. Let's proceed +with the cost calculation.The estimated impact on your costs based on the average +resource consumption for your application over the past few months is as follows: + +> - CPU cost: $448.28 +> - Memory cost: $161.87 + +> These costs are calculated based on the average monthly usage of CPU and memory +resources. If you have any more questions or need further assistance, feel free +to ask! + +Looking into the tools window, we can see that the LLM called both of the tools +we provided to it, and the answer is evidently higher quality and more accurate! + +What is truly powerful about what we just did was not that the LLM was able to +use tools to more accurately reply to the user, it was that the LLM was able to +use tools to more accurately reply to the user _without us re-deploying the LLM +application_. We have decoupled the development and deployment of the tools from +the development and deployment of the LLM agent! + +Now, we are able to declaratively bind these two components together through a +glue of EventTypes, but the people building our LLM agent do not need to worry +about what tools it will have access to or how it will call them, and the teams +making tools can give it access to their tools without learning the codebase for +the LLM agent. Furthermore, since all we did was provide metadata about a service +to the LLM we can now create EventTypes to describe existing services we have +already built, and the LLM agent will be able to successfully interact with those +systems with _no code changes_. + +This concept of automatic tool discovery by an LLM Agent through the use of +metadata is the central concept to what we are working to build. In the next +blog post we will discuss our vision for how this will evolve. If you are +interested in helping us build the future of LLM Agents in the cloud, message +us on the [CNCF slack instance](https://slack.cncf.io)! From d33c70d8f422d4c758abdca6e1fd1ad284742574 Mon Sep 17 00:00:00 2001 From: Yijie Wang <147119743+yijie-04@users.noreply.github.com> Date: Fri, 26 Jul 2024 12:03:31 -0400 Subject: [PATCH 08/26] Adding image to cross namespace blog (#6075) * Added image to cross namespace blog * Added image description * path error fix * Update blog/docs/articles/cross-namespace-event-links-feature.md Co-authored-by: Leo Li --------- Co-authored-by: Leo Li --- .../cross-namespace-event-links-feature.md | 2 ++ .../images/cross-namespace-event-links.png | Bin 0 -> 149330 bytes 2 files changed, 2 insertions(+) create mode 100644 blog/docs/articles/images/cross-namespace-event-links.png diff --git a/blog/docs/articles/cross-namespace-event-links-feature.md b/blog/docs/articles/cross-namespace-event-links-feature.md index fe5516d4d39..2ab52768d92 100644 --- a/blog/docs/articles/cross-namespace-event-links-feature.md +++ b/blog/docs/articles/cross-namespace-event-links-feature.md @@ -2,6 +2,8 @@ **Author: [Yijie Wang](https://www.linkedin.com/in/yijie-wang0806/){:target="_blank"}, LFX'24 Mentee** +![Cross Namespace Event Links](./images/cross-namespace-event-links.png) + Over the past three months, I’ve had the incredible opportunity to participate in the LFX Mentorship Program. My specific project was titled [CNCF - Knative Eventing: Cross Namespace Event Links](https://github.com/knative/eventing/issues/7530){:target="_blank"}, with my proposed feature track [here](https://docs.google.com/document/d/1rtDW446cldTrZaqeiOUdZuVC4u6SFHUneT3r4j2izaU/edit?usp=sharing&resourcekey=0-MNvWVD8pm_xnPfyCMMXHDA){:target="_blank"}. As the term wraps up, I want to take a moment to reflect on my journey and share it with you. ## Feature Description diff --git a/blog/docs/articles/images/cross-namespace-event-links.png b/blog/docs/articles/images/cross-namespace-event-links.png new file mode 100644 index 0000000000000000000000000000000000000000..82e97f910d3ed68afc031d8286380c10195f7b50 GIT binary patch literal 149330 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 z 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 z�g)2*PBJM!qUUoR^kbs6#v$@r3cBWVYBwCrXBE~uzt=jK+Q97T~ zNOn_Ie$cZ1mK=vH@P{&kBfH2>2EJART*rUWWUxhZxqEB7Vaa9v5pccATGsMnDJLry zc+}%&HKO|am*FBKy^+2&HRsn_AUX9->hE~RO8dwDynj+mgv&0DCKY3%vgm7l8eOLFpa za%xg@YN}GTGzK^#%D4@iL^>MJ%$J`Kg&$o|=ZRiEJ@yqpUQI zTpjLy=^Gie#ffBXXREG%kAE5VVx{j!qC#EKZByq3V2$wKW3&XTF59lh!1zTgyXmRf zV)u&KVs#nafH8L@UxxDkxedqg1DF{XA|5L_cz=zugn0z0KQfQF#a9H$VC#h^R5#R& z&2WP`vHajQ4F#(yS#QqAnin~&s?|re)w%`Gy=3&a&z1MxfP1InSp|FBmQcvTvfR&i z3F;p5y1RSjjxxE*-Zsp&241Y})hF{uBwZg_V=1g$9t_pRInnVnTR#_{me=vcE?mb1 zzNSz&)+@4`ZJiq|E&W)mY?4q)?BT9Hne?kATzGFVv(TYr8@?HuIe%tz1?|37Wojw8 z9U0{Ip|Qovlx_lrPow__X#0-dL5U%HH>B>kEGbJ8LT9!%7oSu`rJ+J3O_sa*VH@D? z`@x`W%=Lz^D0!kZaG5!AH!uGa#Z0)*E!QuT*AvBMelL)Z!RpyCM}G+y#qcz!hi-KsL2Sni%mu$opUB`wdQJoviJdaa6Xk}ub22b|pNTOR zD0O)ZBOujZ*BCr>*ubD)Q4Ysp%38t<-!{rHkO)+IwXqPr=|wTtlw+`M5`wV`-fs@kU{%F%@HX-9jts|5=bVrD_R+0LJeG&iHRv7e|Dtv0=OfMHQ{${PK-) zjWk|U&hg0K6VdHiF;tqiMO95E1D~wELpFxl*6#WG575p$Pc~ao`rUo>nAXP3_0bwv zWbxu2{BuogPk8ap8?mGF4ZHd#joe=fi<&lAnZY*fFY_8q)KYIG4{gBo#_<39=oD8!{L1pje}yrWsH?QM zzGux$D^{@0`>DW#=6^_Y#+g<&CpP7vr-UKz|zZlk=wZPyQ z&B)Z{F{S@JTL^h2i&^qZ5JSI9aM# Date: Mon, 29 Jul 2024 01:20:13 -0400 Subject: [PATCH 09/26] Updated the supported serving and evening versions for Knative Operator 1.15 (#6076) --- docs/install/operator/knative-with-operators.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/install/operator/knative-with-operators.md b/docs/install/operator/knative-with-operators.md index e6f49a611aa..e3dde12948c 100644 --- a/docs/install/operator/knative-with-operators.md +++ b/docs/install/operator/knative-with-operators.md @@ -5,9 +5,9 @@ You can install the Serving component, Eventing component, or both on your clust The following table describes the supported versions of Serving and Eventing for the Knative Operator: -| Operator | Serving | Eventing | -|----------|--------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| v1.14 | v1.14.1
v1.14.0 and v1.14.1
v1.13.0, v1.13.1 and v1.13.2
v1.12.0, v1.12.1, v1.12.2 and v1.12.3
v1.11.0, v1.1.1, v1.11.2, v1.11.3, v1.11.6, v1.11.5 and v1.11.6 | v1.14.2
v1.14.0, v1.14.1 and v1.14.2
v1.13.0, v1.13.1, v1.13.2, v1.13.3, v1.13.4, v1.13.5
v1.12.0, v1.12.1, v1.12.2 and v1.12.3
v1.11.0, v1.11.1, v1.11.2, v1.11.3, v1.11.4, v1.11.5 and v1.11.6 | +| Operator | Serving | Eventing | +|----------|---------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| v1.15 | v1.15.0
v1.14.0 and v1.14.1
v1.13.0, v1.13.1 and v1.13.2
v1.12.0, v1.12.1, v1.12.2, v1.12.3 and v1.12.4 | v1.15.0
v1.14.0, v1.14.1, v1.14.2, v1.14.3, v1.14.4 and v1.14.5
v1.13.0, v1.13.1, v1.13.2, v1.13.3, v1.13.4, v1.13.5, v1.13.6, v1.13.7 and v1.13.8
v1.12.0, v1.12.1, v1.12.2, v1.12.3, v1.12.4, v1.12.5 and v1.12.6 | --8<-- "prerequisites.md" {% include "security-prereqs-images.md" %} From bd985c0cc5e082e90c47e9794c1a47b9056f6287 Mon Sep 17 00:00:00 2001 From: Reto Lehmann Date: Mon, 29 Jul 2024 13:42:08 +0200 Subject: [PATCH 10/26] Release v1.15 (#6077) --- hack/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hack/build.sh b/hack/build.sh index 54cd2705351..9f2d8850926 100755 --- a/hack/build.sh +++ b/hack/build.sh @@ -27,7 +27,7 @@ set -x # 1) Make a release-NN branch as normal. # 2) Update VERSIONS below (on main) to include the new version, and remove the oldest # Order matters :-), Most recent first. -VERSIONS=("1.14" "1.13" "1.12") # Docs version, results in the url e.g. knative.dev/docs-1.9/.. +VERSIONS=("1.15" "1.14" "1.13") # Docs version, results in the url e.g. knative.dev/docs-1.9/.. # 4) PR the result to main. # 5) Party. From 2082a7de28fc13579a539a5d870629aa35768ba1 Mon Sep 17 00:00:00 2001 From: Reto Lehmann Date: Mon, 29 Jul 2024 14:34:02 +0200 Subject: [PATCH 11/26] Fix wrong artifact url (#6078) --- docs/eventing/features/transport-encryption.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/eventing/features/transport-encryption.md b/docs/eventing/features/transport-encryption.md index c648e2d9917..debf95761e5 100644 --- a/docs/eventing/features/transport-encryption.md +++ b/docs/eventing/features/transport-encryption.md @@ -122,7 +122,7 @@ necessary. 2. [Optional] If you're using Eventing Kafka components, install certificates for Kafka components by running the following command: ```shell - kubectl apply -f {{ artifact(repo="eventing-kafka-broker",file="eventing-kafka-tls-networking.yaml")}} + kubectl apply -f {{ artifact(org="knative-extensions",repo="eventing-kafka-broker",file="eventing-kafka-tls-networking.yaml")}} ``` 3. Verify issuers and certificates are ready ```shell From 5d70b7d147fe05364a03f3ee87d73bef5608c02f Mon Sep 17 00:00:00 2001 From: Leo Li Date: Mon, 29 Jul 2024 13:48:51 -0400 Subject: [PATCH 12/26] Release 1.15 blog (#6080) * feat: add the first draft of the release note * feat: add the banners and update the nav yaml * fix: fix the errors * fix: fix the errors in operator title --- blog/config/nav.yml | 1 + blog/docs/index.md | 12 +- .../announcing-knative-v1-15-release.md | 133 ++++++++++++++++++ blog/docs/releases/images/release1.15-1.png | Bin 0 -> 146026 bytes .../releases/images/release1.15-bookstore.png | Bin 0 -> 253619 bytes .../releases/images/release1.15-eventing.png | Bin 0 -> 187592 bytes .../docs/releases/images/release1.15-func.png | Bin 0 -> 160964 bytes .../releases/images/release1.15-serving.png | Bin 0 -> 172363 bytes 8 files changed, 141 insertions(+), 5 deletions(-) create mode 100644 blog/docs/releases/announcing-knative-v1-15-release.md create mode 100644 blog/docs/releases/images/release1.15-1.png create mode 100644 blog/docs/releases/images/release1.15-bookstore.png create mode 100644 blog/docs/releases/images/release1.15-eventing.png create mode 100644 blog/docs/releases/images/release1.15-func.png create mode 100644 blog/docs/releases/images/release1.15-serving.png diff --git a/blog/config/nav.yml b/blog/config/nav.yml index 2184456641c..0fdf7c9b0f1 100644 --- a/blog/config/nav.yml +++ b/blog/config/nav.yml @@ -15,6 +15,7 @@ nav: - Blog: - index.md - Releases: + - releases/announcing-knative-v1-15-release.md - releases/announcing-knative-v1-14-release.md - releases/announcing-knative-v1-13-release.md - releases/announcing-knative-v1-12-release.md diff --git a/blog/docs/index.md b/blog/docs/index.md index a435e055087..49048691b74 100644 --- a/blog/docs/index.md +++ b/blog/docs/index.md @@ -22,17 +22,19 @@ Follow this blog to keep up-to-date with Knative. ## Featured Posts +### Announcing Knative v1.15 Release +![Announcing Knative v1.15 Release](./releases/images/release1.15-1.png) + +Details on the 1.15 release of the Knative project. + +[Read more :octicons-arrow-right-24:](releases/announcing-knative-v1-15-release.md){ .md-button } + ### How IBM Watsonx Assistant uses Knative Eventing to train machine learning models! ![How IBM Watsonx Assistant uses Knative Eventing to train machine learning models](./articles/images/How-IBM-watsonx-Assistant-uses-Knative-Eventing-to-train-machine-learning-models.png) [Read more :octicons-arrow-right-24:](https://www.cncf.io/case-studies/ibmwatsonxassistant/){ .md-button } -### Knative 1.14 is out! -Details on the 1.14 release of the Knative project. - -[Read more :octicons-arrow-right-24:](releases/announcing-knative-v1-14-release.md){ .md-button } - ### Enhancing the Knative Contributor Experience! Actionable Recommendations for Improving the Knative Contributor Experience! diff --git a/blog/docs/releases/announcing-knative-v1-15-release.md b/blog/docs/releases/announcing-knative-v1-15-release.md new file mode 100644 index 00000000000..a6a48a9ac1c --- /dev/null +++ b/blog/docs/releases/announcing-knative-v1-15-release.md @@ -0,0 +1,133 @@ +--- +title: "v1.15 release" +linkTitle: "v1.15 release" +author: "[Reto Lehmann (Red Hat)](https://github.com/ReToCode), [Stavros Kontopoulos (Red Hat)](https://github.com/skonto), [Calum Murray (Red Hat)](https://github.com/Cali0707), [Leo Li (Red Hat)](https://github.com/Leo6Leo), [David Simansky (Red Hat)](https://github.com/dsimansk)" +author handle: https://github.com/ReToCode https://github.com/skonto https://github.com/Cali0707 https://github.com/Leo6Leo https://github.com/dsimansk + +date: 2024-7-29 +description: "Knative v1.15 release announcement" +type: "blog" +--- + +# Announcing Knative 1.15 Release +![image1](./images/release1.15-1.png) +A new version of Knative is now available across multiple components. Follow the instructions in [Installing Knative](https://knative.dev/docs/install/) to install the components you require. + +This release brings significant improvements and new features to the core Knative Serving and Eventing components, as well as enhancements to the Client, Functions, and Operator components. + +## Table of Contents +- [Learning](#learning) +- [Serving](#serving) +- [Eventing](#eventing) +- [Functions](#functions) +- [kn CLI](#client) +- [Knative Operator](#operator) + +### Learning + +![image1](./images/release1.15-bookstore.png) +#### 💫 New Features & Changes +- New beginner-friendly E2E bookstore tutorial is now released. ([Link to tutorial](https://knative.dev/docs/bookstore/page-0/welcome-knative-bookstore-tutorial/), [docs/#5880](https://github.com/knative/docs/issues/5880), [@Leo6Leo](https://github.com/Leo6Leo)) + +### Serving +![image1](./images/release1.15-serving.png) +**Release Notes:** [Knative Serving 1.15](https://github.com/knative/serving/releases/tag/knative-v1.15.0) +#### 💫 New Features & Changes +- Added a new job that runs after upgrades via kubectl to clean up old resources ([#15312](https://github.com/knative/serving/pull/15312), [@skonto](https://github.com/skonto)) +- Added anti-affinity rules to the activator deployment ([#15233](https://github.com/knative/serving/pull/15233), [@izabelacg](https://github.com/izabelacg)) +- Adjusted liveness probe to account for stale leases, preventing webhook crashloop ([#15256](https://github.com/knative/serving/pull/15256), [@mukulgit123](https://github.com/mukulgit123)) +- Allowed IPv6 address for sslip.io in default-domain Job ([#15328](https://github.com/knative/serving/pull/15328), [@tcnghia](https://github.com/tcnghia)) +- Contour now supports TLS encryption of cluster local routes ([#15378](https://github.com/knative/serving/pull/15378), [@dprotaso](https://github.com/dprotaso)) +- Knative Service now supports setting startup probes in the spec (note: this increases cold-start time) ([#15309](https://github.com/knative/serving/pull/15309), [@ReToCode](https://github.com/ReToCode)) +- Pod anti-affinity rules are set by default for all Knative services (can be deactivated) ([#15250](https://github.com/knative/serving/pull/15250), [@izabelacg](https://github.com/izabelacg)) +- Pod runtime-class-names can be set to run Services with specified labels and available RuntimeClass ([#15271](https://github.com/knative/serving/pull/15271), [@BobyMCbobs](https://github.com/BobyMCbobs)) +- The net-certmanager controller is now part of the Serving core and Serving controller ([#15066](https://github.com/knative/serving/pull/15066), [@skonto](https://github.com/skonto)) + +#### 🐞 Bug Fixes +- Fixed cluster.local Routes not reconciling when external-tls is enabled ([#15234](https://github.com/knative/serving/pull/15234), [@dprotaso](https://github.com/dprotaso)) +- `kubectl get revision` no longer shows an empty column for `K8S Service Name` ([#15260](https://github.com/knative/serving/pull/15260), [@dprotaso](https://github.com/dprotaso)) + +### Eventing +![image1](./images/release1.15-eventing.png) +**Release Notes:** [Knative Eventing 1.15](https://github.com/knative/eventing/releases/tag/knative-v1.15.0) + +#### 💫 New Features & Changes +- `transport-encryption` is now a Beta feature ([#7915](https://github.com/knative/eventing/pull/7915), [@pierDipi](https://github.com/pierDipi)) +- Added prototype for MQTT source ([#7919](https://github.com/knative/eventing/pull/7919), [@ctmphuongg](https://github.com/ctmphuongg)) +- Added EventPolicy Reconciler & Webhook ([#8024](https://github.com/knative/eventing/pull/8024), [#8091](https://github.com/knative/eventing/pull/8091) [@dharmjit](https://github.com/dharmjit)) +- Added JobSink resource to trigger long-running background jobs when events occur ([#7954](https://github.com/knative/eventing/pull/7954), [@pierDipi](https://github.com/pierDipi)) +- EventTypes no longer need a reference to be set on them ([#8087](https://github.com/knative/eventing/pull/8087), [@Cali0707](https://github.com/Cali0707)) +- Knative Eventing now supports the CESQL v1 specification (note: breaking changes from v0.1) ([#8103](https://github.com/knative/eventing/pull/8103), [@Cali0707](https://github.com/Cali0707)) +- Sequences now update subscriptions instead of recreating them, where possible ([#7948](https://github.com/knative/eventing/pull/7948), [@Cali0707](https://github.com/Cali0707)) +- The filters field in APIServerSource is now alpha and disabled by default ([#7799](https://github.com/knative/eventing/pull/7799), [@rh-hemartin](https://github.com/rh-hemartin)) +- The new-trigger-filters feature flag was removed; the feature is now enabled and GA ([#8067](https://github.com/knative/eventing/pull/8067), [@Cali0707](https://github.com/Cali0707)) +- Updated eventtype CRD to include .spec.reference.address ([#7935](https://github.com/knative/eventing/pull/7935), [@creydr](https://github.com/creydr)) + +#### 🐞 Bug Fixes +- EventType v1beta3 resources no longer have a default broker reference set ([#8079](https://github.com/knative/eventing/pull/8079), [@Cali0707](https://github.com/Cali0707)) +- The IMC dispatcher metrics now correctly record metrics once per event with a single request scheme ([#7870](https://github.com/knative/eventing/pull/7870), [@Cali0707](https://github.com/Cali0707)) +- Avoided fatal errors for unknown feature flags that may be added in future releases ([#8051](https://github.com/knative/eventing/pull/8051), [@pierDipi](https://github.com/pierDipi)) +- Exposed OIDC identities of underlying Subscriptions in Sequence and Parallel ([#7902](https://github.com/knative/eventing/pull/7902), [@creydr](https://github.com/creydr)) + + +### Functions +![image1](./images/release1.15-func.png) +**Release Notes:** [Knative func 1.15](https://github.com/knative/func/releases/tag/knative-v1.15.0) + +#### 💫 New Features & Changes +- The S2I builder now supports Go functions with new instance-based method signatures and lifecycle methods ([#2203](https://github.com/knative/func/pull/2203), [@lkingland](https://github.com/lkingland)) +- Embedded Tekton task definitions in the binary ([#2396](https://github.com/knative/func/pull/2396), [@matejvasek](https://github.com/matejvasek)) + +#### 🐞 Bug Fixes +- Fixed Function namespace resolution in some edge cases ([#2187](https://github.com/knative/func/pull/2187), [@lkingland](https://github.com/lkingland)) +- Fixed --registry-insecure flag in deploy command ([#2335](https://github.com/knative/func/pull/2335), [@norbjd](https://github.com/norbjd)) +- Fixed Pipelines as Code setup failure under unprivileged user ([#2341](https://github.com/knative/func/pull/2341), [@matejvasek](https://github.com/matejvasek)) +- Fixed buildpack build failure caused by wrong socket mount-point when using Docker Desktop ([#2350](https://github.com/knative/func/pull/2350), [@matejvasek](https://github.com/matejvasek)) +- Fixed pipelines as code build -- build via git hook in tekton ([#2314](https://github.com/knative/func/pull/2314), [@matejvasek](https://github.com/matejvasek)) +- Fixed failure in GHA caused by missing cargo bin ([#2440](https://github.com/knative/func/pull/2440), [@matejvasek](https://github.com/matejvasek)) + +#### Documentation +- Clarified --registry-insecure flag description ([#2348](https://github.com/knative/func/pull/2348), [@norbjd](https://github.com/norbjd)) +- Fixed the docs for build section ([#2368](https://github.com/knative/func/pull/2368), [@swastik959](https://github.com/swastik959)) + +#### Other Changes +- Updated images from ubi8 to ubi9 ([#2328](https://github.com/knative/func/pull/2328), [@matejvasek](https://github.com/matejvasek)) +- Fixed error message ([#2372](https://github.com/knative/func/pull/2372), [@swastik959](https://github.com/swastik959)) + +### Client +**Release Notes:** [Knative Client 1.15](https://github.com/knative/client/releases/tag/knative-v1.15.0) + +#### 💫 New Features & Changes +- Added option flags to define nodeSelector, nodeAffinity, and toleration on Knative Service ([#1924](https://github.com/knative/client/pull/1924), [@Shashankft9](https://github.com/Shashankft9)) + +#### Other Changes +- Added release note template ([#1956](https://github.com/knative/client/pull/1956), [@dsimansk](https://github.com/dsimansk)) +- Removed release notes template in favor of global one ([#1957](https://github.com/knative/client/pull/1957), [@dsimansk](https://github.com/dsimansk)) + +### Operator +**Release Notes:** [Knative Operator 1.15](https://github.com/knative/operator/releases/tag/knative-v1.15.0) + +#### 🐞 Bug Fixes +- Fixed bug preventing liveness probes from being overridden to no probe ([#1823](https://github.com/knative/operator/pull/1823), [@mbaynton](https://github.com/mbaynton)) + +## Thank you, contributors +**Release Leads:** + +- [@ReToCode](https://github.com/ReToCode) +- [@skonto](https://github.com/skonto) +- [@Cali0707](https://github.com/Cali0707) +- [@Leo6Leo](https://github.com/Leo6Leo) +- [@dsimansk](https://github.com/dsimansk) + +## Learn more +- [Knative docs](https://knative.dev/docs/) +- [Quickstart tutorial](https://knative.dev/docs/getting-started/) +- [Bookstore E2E tutorial](https://knative.dev/docs/bookstore/page-0/welcome-knative-bookstore-tutorial/) +- [Samples](https://knative.dev/docs/samples/) +- [Knative Working Groups](https://knative.dev/community/contributing/working-groups/) +- [Knative User Mailing List](https://groups.google.com/g/knative-users) +- [Knative Development Mailing List](https://groups.google.com/g/knative-dev) +- [Knative on Twitter @KnativeProject](https://twitter.com/KnativeProject) +- [Knative on StackOverflow](https://stackoverflow.com/questions/tagged/knative) +- [#knative on CNCF Slack](https://slack.knative.dev/) +- [Knative on YouTube](https://www.youtube.com/c/KnativeProject) \ No newline at end of file diff --git a/blog/docs/releases/images/release1.15-1.png b/blog/docs/releases/images/release1.15-1.png new file mode 100644 index 0000000000000000000000000000000000000000..1c710fa348124a4ee850624890694fde4a983026 GIT binary patch literal 146026 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

u6}h10 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 z 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 literal 0 HcmV?d00001 diff --git a/blog/docs/releases/images/release1.15-bookstore.png b/blog/docs/releases/images/release1.15-bookstore.png new file mode 100644 index 0000000000000000000000000000000000000000..b41c51575d1c82a3adc1022e24e06f5e147f224a GIT binary patch literal 253619 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

#PjH^P_J3%vx^zM{`t>i~TIck~^;jJ-|7V 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 literal 0 HcmV?d00001 diff --git a/blog/docs/releases/images/release1.15-eventing.png b/blog/docs/releases/images/release1.15-eventing.png new file mode 100644 index 0000000000000000000000000000000000000000..0bfc570fef0a1715666c575c7b8dc593a66cf9f7 GIT binary patch literal 187592 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

Z(R>*r_-6!v>*RCjL=++j_-{xUo7*Ge~J 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

1o)DW5UiJ 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

eB-Tdcb*1ONKi)!SH%&kuj9$qzPeAygHRtAMx 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

FG7>hH_uJI6=kmCc z|2Qjz?y<=JObgUWdnkSBuu7xhJKC?N zg?6QsI*o_%;gWCLyXAm9F#(Jwj%;Fq%wf^300yXHT@MOCsjjKaL%qi|Y9+UQ(>@@= zewh7_Q0Iy_#iZTX5nwrBp_cK=&L9{(8i*i7M@hN%dx>6*ZYXABt7vrrVd}UG(D` zd1i{8#@+nnSNc;cz;Z7PlOJd=*QiAI)6-~y0g!$%r(|k*V2lu`IKsN3LoMf~bQN1` zZh6C_9=SoDFT$VurmiVOK9~fYiJbi2Frdi+F~n>dGtFj(A~vWy(5$!A|A+rk-t~@QR&!I)Tq%FDgbDWQymaQ^C_>#|ua3aTtI8*7+}3Yje%b~aTGwN@_Bm3P0) zTH)?LE_0 z3QI-TTo&F0nM8F+59L8 z(j3B2#37kEOHzoh38XQ-PVosh@j2s@@z$=feoMg+`|0c`$jS?|O(FM$ynB7HE-7idSWx+4*G< zy3k~=&?HeUwykO+d~6XsFG=F!(P(f$^*jXMtd!$mcT$8Mn<+L=o;0nccK@m1x=8IV zuO)k7H)d!;WDwyMd+v0u`0{)(_lF&vxO0<$Bv6f~cEM|zxsW6EW8W9i)F@Hj;DK8r zbr%M45wUJ%P7P`j2}Ldj6L!>!LdJYaak9{-N`8eT_2bDeHcZU|xvOdiI$t}Q#%zJ^ zwYsli))}sC-;~)_R4#0FwN$H@ifnz++H3@2kZz!&admQw+QFfLw z3wvkUISEzFuT-A3vra1;b2la^A~wj?K0?>OQ5W#FDw_+p-Vzh?|DM_^ZTf1-+|0@J zGhFMwYO?zp;iA!-;y9#-jyK;Uk7f;_7D2PNns{5Iyi@yeDv(clxPUQxG!yd9#{cye z1Dax&&GM1_^Kz7jWj8tHi-9<@=r+C>n(A3CP1PS5kU$hOAUMSu_F z?p?Qb7k3SnzpNS zYXFW1z4Rh&(#~t<)ae%|CN)2p=e^@NTQTjxP@`rl5B$rgRuP|Pk2p6j=QDSszH;`M zj`2v3v0H?^*^ln#Vg6)~1QG`j8DUTjCp*NyCOp=lzkm5(XJmysngL7c&ipaJ)BwRU zwa@=%N%6VNV7`pSMJ>;P1~>Jm8~Kk!tI5oAVD}(pedfEqyE$9PdRTM(z{Y3_P&YD;R=I!ym2)z!5Qn5FMgK>z*lmdm_N%UmpSO;ctup=jt^ z%1+K-N@gcnTcTXE7Wk`9Jsa;>s)#FLiuB6g#{u`yV2)4VyO()|v!-|8m6NRK;}0KJ zdRxtvZS~bm0uN43c>6maz?Cel0oM@SIAVt{;RX7KkUfu%{y=5;BB*8}XX0U@c(ug3 zrs22lo}+qF!%eMo*I4MMsNHQ|Z6gLns(~x)PcR1fXdzWscS)(tIHXu~(!g&`+rLIR zv)=#Lb=wmd0#tne^X~nv%u!Pj>nigkjh4|=qct^{v=u^q*$2RH2!D*>`a04;38b>+tJm!Ri_{V=-NVQmErKrBWI#MSKVG@h)o*!OA9dq@;cF z=qcEhGenA#rpiwkqbJ(;CR0ty_zS*KlFniW@{J%f>(xmDnWec zYDR&;)k{?-B1=SkGkj@IqKlJjC;i9@n%)X?&7-$1azbhMACFWctG zeM~E|*>h)vUA%Szo zihk}s_au~>vjWQav-Ak+Ue*fV@FB}}JG_s-uOiDn3c*YIBZ2vw$m6e6BF?uNB8wgi zK5EoYre3o8IC1Q-sbd(Rb;P@?jqq_cbEv-a0Dg+3j(wMHw;(}_~=9-x- m%biX0C8;tZnW+4~&%$12zo#LhRnj5?K998YG-2vC(Ek9p>|r7R literal 0 HcmV?d00001 diff --git a/blog/docs/releases/images/release1.15-func.png b/blog/docs/releases/images/release1.15-func.png new file mode 100644 index 0000000000000000000000000000000000000000..e3412354a4cd8adafa216bae7c45d27024083ddf GIT binary patch literal 160964 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

Np~ zs_O(i*{mBg^d5I@9`cD_3fNGE$dv--3k)6Z$3cc}`Z-B&Zj1V6%HCI+x$j(EoqMic zv=;CD$(mfr#g&hbT!6=_Nq733ZRi}r?oRdP@~umPE^UY%tL52PO@~m79-m1b|BT)Y zml{nn-N0l3Z5HqRGd_3>IEG}l63f5@YrYXgkKz3d<5=muyrc)q#I*t;g^#!C%v1A( zgza;(a;+QGF7esj3Ln=Rk;c^KUff&L=+oq?ICm-UOuZJ>~p@KKD?C3ZNWP5>C zPln?EmB9g0Qu~A2EF;C94lm&zb*hw(DifiRV)P8M0urb?_1a2bBP80j>c^Us#x&TG zFj?r6&9ey<+796vld0#fl4(}tSl+u6cvSXa!sz}E`WN2$Dg; zUC{tRg~)L_hY$w{UjAns9a+gQ{tGN~w?fzg1j3(C0RR|sB5=lT1=@weOO4uhm3)bR zLE>u-(k_zSfYP`j(ie%3U&_R>&)S+`(KgO~uYkD${tb?`%>O0zfwxi7A9zYM-@2&K z(G*Nc^d_y@3K{h`cWBz$V9MlY2VkLYa<`*yn>28-qa3pxZ5ZR=G2=-{UaRK+kQ^2e zXB$Oyld0+uMRg1Rsa}Rto4x3>nke0*ZtShO>1AOa zww}u`p1lGdR8xo0sVV>&#xG~psX`j+(DBq11T(PMOLMRF0zDl)4U`Kq4%v@ zRyjLi-E4-vY*DtmspN-%QH+MvTKW^o0((Z(lq96TSxfNRFQSQ?1v~5>RdVVT4CQq$VAuC`E~A-q&qe)?|rT7+zzE2S@sGfBc&dI zX3Jd9wbjro1lQ_}Je|wBimE$30Si4T7m(6`)YFw`p3%bhT6g+!Gz*BiMXQHR& zNn&OTFMLU8pZjK$N2(G@DgY5YX{p#qO?oNk16yMfC6#>D5hN&P}m33ymN zk(j#L_DGLc+e@Wieocg%gJ@7;+bWZ)(uMezpLftB!nKvXW=!kp!bvk%cRn&q4{kPR z!J+*-L+5Pl_BX%imf#R}!>M}%gt-!5(|!**JD=WO%rY^?0)GB)I3KU&n+^nlX3 zK>eQFi(9!CsM4%qME8#bvKiGsC9{1SM2C-Y`P-@azj5(JP{H;J3SP2+K>sv{=$Nc% zyTT+am=;d$3&NRmLYZj4Kmjz`2_AS*J1QFK$~KfH*-H!LucUKdiIX3;)x7N@^kc71 z%H4_zaZ^@hSrwg1erT_W+_%|hJOPKV8zk`v{&|SW~PcI zW2~k^b@1?*W6jpUnx4tWVq5f}lLzUHi}gC3j-*3P0TO3ri*G2XG zvDBH0ca$midL3^?>)fB9mp)!^H&sABa9dt4L=(6c0@z}|26--y+PxVPxk<(^__&D1 zS^8h-4geAxDdy@&j-WR7m03kH#8%3m$uXayy2So$AMl*(gD^v%jNs4kOma9jH_B9s zS-aO8?kyj+8~x=jYT19He$vmEW66F9AKf6{c2kbhM69uG#GN`=uEaR6neOFeeyrdW zNpJBjk>%{w&=*_dL3`-e*hahb>QG@WVBfai-IZ@=7%Fv?-{@kPxWel+{GK(!yz-O4JWY-%RTKZZXAf?bpBbEo*ikT@thPaJ zA9bo)=0$pGXKW}5KILPeBDx84JmOtP zr((vMa*FWgr!Q?@5ivQCC|gnTbcDC4kp$XP#!1-Pa0)O!tD#Q}z1<7Ub*tM27Nm@Z zMU|?L)A6^j;iVE5v-tOmPv7y9RM}ur;gKHCFCX3Q%qdf@I$zmq(0Vz{a7n$M<{}9THkNNG%e|FN#!;1%}F%y?|$65Aj&)lacpy zbfNRgdL7;?-YMS}Ei8jT6yOT#xYx(DzA$JGSFJFIdx-KxB|-TD{mCdfui`pa8bM?u zNV)(qF8|w_Dm?D- zi>93Bw8Yxh!O?)b0aOZ0y(4Zb=~y64KLi`jHu7EDhu?oX*!AJc^}&b7A(}4rRKSe( zRjFD3#iSJGFKjWe)%-<2vV6Y3cq#CKbYz*jKaX-3^;Le#r|A&yifCR&abG|`+p*qn z&L=vBhf}nyupF+2SoKNNo8;^WIe+JidC|bmN3rNzVOFZ|y3VDv^UAr0^zG^kry(Un z&qprS=MUwE>>f2#B_-1-LA6%thWT%XYv!@hi|g>4V?AK`A>+ z3uD~HfJHc4nOT%suGMe7!*1E%bvL^3tNd$;I7hW6>nY6Do2jhl z(rx%m__QW;T%6PD!}Y{EzqW~13Gy;)n_$77`=Tm%_o}AZ6Lwj9Fqjny32VEQUuwTp z-?yPU3qX8j;8hM_VFu0Hw=8Wd=5Pgq!Yw}#1D@VD@>K`+sf_OlpG$hD5>rLAQ?NQ`Xi~wJuwK8D zTTRNjc=3yrwT23(^-D{v=rDA(H#vzbn@5*DSaWU8wnqGv1}{b{GRG>mHx>s5(!O4w zqm6;pD@R#RE?Wbq!xhKvT-o_lg-(aqZ}l(S}Dv$8Jx|;h}@A z@o(O^BCNOmmc2KPfnWYV05d<``(_z_U%{-XS->%;x@N6bYOk(we;~AjpAQjhjX>>H z40?akLQTb8)`X2T&Qj3g!V`(lrOR1Ti)AFRsPInNRQ9YkKRMvHac6^SR5ujqf5=-Mq%` zyL!T@kS%YY@OG8%wMQ>JQkdO0=I(jA4Dn~^V3(b5#06Z&e5*N>Og_l48pg2~&fjb) z)H%tiJRy1?KbT@Mi%BT6b;96c!9`~_kM!k;qw=`O-)@j3X%HcC30OQ^b~=?to!-^T zlm~vY1h^l{5$(;a-{7D>dxZ2V|AXBk>iFP~L_zYc{AyZ?;sf282ll73UWTCo=b8o{ zY8=jDL6@t4{bd{`f4z=K_KVlE)17cfLD`zHqq+B*m!0+88)BHw^QiRCU!?~{ri^ip zl4`kgRp;yB1vRU3Eoxe9pfT`$3{pK3O^#&6W1;l#?_Syv^s|u6cimg8OW&^}+*Ox8 zcOXaENU+APxbQt6=!hc-J~%y}!;-xadEh8xikV&^kvXp6;2!(tSXjInStAw zTjefGu}8P%V~^EzZ!=rV)YD6&<2fJ$GAtlWyns@*zXV4oXGgW?Z+djTodtjM3O?s} z@Ea*uvVZZ^pSM~}L1uDN>5z`ua{|&NYKzW{JPXo7er~(;yoxWhAxE4hW;#JDs@9Ho z?`TtEE`?5%#D+|_9oXnMP^9xeM%&TLdpk(T?6u?uMVk_{G7y@9T~zGzhHpL6Slt_Tymw(Bam}0D zw_5md!1;zwA2%wc5in{;h0CTRKdu_R)}_Xj^v!+yg}X9=67PO011kmBnA)K#S7>yl z0)B@pLY#?Ic2pW?tP{H>gT2sSMhQmqWOb204})vAo{bm#=bvsHOO%)1{;2CayCjUYxci(7B-z~CAoI``IR>UAT@4kZoV4(z{)+7?MmwEv^AW_g} zx!H#D8bEpk6Vf{SZJ7MLD8|7uND>a;#HA0)=wD=dz!y|?^x%V$U%Pv``D!=4CcRNL zeQ;lpq>asCb9R{KdD&F-+pY>J;S1Bwk{!1wzAO5a|i!PqgY?t<|`#j6}ySwu$VUCNS z?G4IjXWNF77qGI+*n4(n_xK2Kg>*~JjP`VMHqxC>_{+OmZuiCRh=Qp zjU@JAY9D8=sc-Wm8nBftCM{;0N%N@rZ!kd!r(#(+DC+nAdj7upxziauaEB$h4hJpM zg8^xSc>97R@)8^JqC(1AMJw|&jY4-x5Ja+Gr+8j!6(wOeu~m4t?mGer)3>zm&;6u7+&PEOm9aQgm13D4`fN*+E-idcKD z&k3r6P*?)p6JF_i)qB;u%DHHyVR67tnc1O3ql~^aJuu)>Qfo;i#`-!U%#oGf1BLyN zD1Rq&w*B#)WpgKr^?mC$CRl^ZaXTy4zW()7i#= zDJoX^!P5qx)J`?#9 z-u@CPAi9~_tD5IPWTxXM&L9~+sKk`W5H1_-9IVb2rmA;aNN31pzP8TOU*af5_AH|9 zD~ILFBvjvXmx@d;Q>(EqkIU^)+3U}sh>kQ{)4o-`1m?s?gU3caEvtQm&dCCTDzhAF zcT*UmCNaJZ>KBK1-M7!5_$=)LK`PpHwr@;&QStUaUl_(^A9n>#>fkIDEzAg zpO8d{TJuG|PsB!HqU8GeSzoMU)#gZtP*i;C>g~F!4^0|4b>9)*1(o|)7X32u3szXs^RiRd?)%9rffr(F^$^#9C zWF{Def{-dxDg(?}$$(L5JZPpNOF4Vfh~BN-HKWn6vC+CQ}u}DF_2Nb+vhc*V92%ZWSu*73~m~q<1R_9^W*oXF2z0{LoQSCy2Ohb@v%amF66k=QdIX3v;fx^JwX zDkPKgxxFmSd7f2Zo^?9-cqDtEV7aVwxvap%(s$fOX~R!ehDj z?H#Ay%BHC6@`tJUn?U zXcC{WU3GoUEYUqdZQWX0{t}VSCl`y3Tv*2+} zJf-zm%e%a}H|=wgQbNkFYv}o3D%NZbS6^gUUZ{>WN_x44u^lqEtZTg-tv=7PoGT{u zEHn{Pe=HnDf5{9^Y`lF*zwVw_d;s=WxogfbGIE=h#Pq&Y?%m>;+qSn0I9HX2>aVz z)X6NM{=$RC$$yz}-R__kHHpnw^P5Z-Dp8pqb!YyAHF3XoP0#po#Kmc63JAql>yS+N z+n?_*%pMkvYH1}OvxzL+@(ibIaiURsP>Dt*IQwwB^!P^AmO{}NuX+LZ_e<$h31{2p z)US#x@i+sQY58O?@#9l)iBmI%4vhRy%0hd4wq~%a4`;`uH|P50dPZBcQ@#uL6u+Qu zwrvo7_QFU2x^!1mjLq44_IZDP)32VLMEA8%hzl0>9+tMmAf7TY_%mzuX?bFKTl@`6RN4 zE}h$%=2hvCmYF>PvGxbRXFKJs45-WedZ?;a(0YdtIPjk)9IwTdL<3IxI(DO_W~9D& zW;bc@SXtredNAsjUd6b1Ge-`nQiEuZa%-gF#TS(6UY4C)iM|HD<3f@ZwdjpURU5`t zXL_1_{-`_L$TEoj~|>>c0w7!%v|aj#oaY3Yg5b13T_o>>c74CM7ed*iVYQnOYE2(Af|He z&+-4mtMd=Osr|s8Ow=rWDbN+{X$yN7T|<@lj7U3pI;?s+?TBA*?<-rxYH~6fuFJ zQtVO0pMo*SpW$QTk!Ie(3pT3|cs?B=CrNCLTH8|*tSGAiq6 z#}#B5)P3YnxZxD*Z)?8YR5G&n)ZeD?>29d__w4dRTI(;cp%X;$kg8{HFP182unI?5 ztg~#?1La5d{8c_>J@*^2yWe2+M&s#LAyLxdNl=A!6lJA@0VUbbZ!cGF_9A&1v`$zc$rR* z2TN=Vt#V5%Ns4KAn2V$E^k_|U)n)H;x)byJnwsF*0X}ERsa0#{%$lmunOW%zr^TaD zkbQwRR&_8lGrym6Y?ow;Wmskv+4i%!_r4Q~8u^=GM-x z(Q+3ej_1h>o3!HU zOIfF#x`^Ue9x`8)_Lt62NA)VV_&G9cRW@TWI%w?y_nPoB3OqInbjcRqb1~jK&ML=V z91L4x(vc`w|E4>06nV5~<2eLVevjT&mr=~VBZwo9uEB(J zSH#qtCX%0AXlT}l~`N^-d?YrW%QrFXpYSRNF%U{-+Kvc1CXt@4$YC@ zk(D1`OO7vl*RP{*r(~L!L;e2Agb^>l5=+K%>H40T(~zCq`>**9zE!4qj|713SzVsn z{Ps*+>i8t1_~wmdqCF;}y>^bs_a`1*0K*(U%p7J5nlie}s~?UeZx$Aj@;I5i;d!@? z8dy^DYrYZFj6ojngXy5CRF|)VVK4q z(bW0Q&=0gA_`xs`QB&#vSOe02n;+zXg9N1A_`ZhL?;55zdu|2rX7wuWFbs~%3?Biv zi;9ryNBI~Wukri3146nJ7DW~mg%%|FHY7zhWX0xW`OQ4q4$rgdz2hVdaL2f{XL#-k z_;&+sDp1YR?aWofKbq$qZa~pfc~(C{3+)q4_2!g?>-(~^+L7FSqB?phyh3sno}WdL z8RQe6U`d`~DtH$f>u&e-P=5iu*5_X$uJMQ$Ic1Rdm(1P?PF%XhJnOM=OD^SFW`p7i z!!U0UN9eP4Y-_*-1FQ;Eq_r2siP@DpgJXkeJ3lzae4u^qx%hncOfI@T@0{_;cu-WR zXjNp~yKBk(sqL#hR13E7GR?Of)R4BW)iN^g9evA48+%3Sx63dVnal7G z_YZKp6AghLBdDfwL2ONk_^09)Sj^f&yZ$sT-mN$_Q7)dd0ylU5P|jhUNB48sew$>6j+B4^JhIIq?r(%I z@7Vv24T19Rf5-ylbP(D0$YM57^?y>)8}qF)EBQ-jX5?+&^@9adk=e$!iS8buM0O)z zH{$Zv8%R>sMIl23^UjYIMg9XddVl0{{f;CcOUXeAoaP`%jHO9}(RMcm4@L0xl*PyL zfqXUKCXJ6zOaKl6S4<$TX6_K!Bl;4Het)lP?mr=gn4|Z%bLIj$UF?hS6JRzI<02+_ z=Vd9(I+8GHHfoTDK_d-7%)_DEt@czr^FmJmK)m*-6is8Yqnw*U3{83p%24s{7 z>xr)FSRtV?hvv^V0K<1wlMUjh!0qv(cq6Ll+5p&eX!MMp@}V_X>Zm z6&U>+v^RH1eyhblu`xD8>~WvAroY|xd4_{Cq^|M@C9zB+``;Y5pZBQ||Hk28O>%yJ z@5hA!s78paXcd!6c_Xl==J`AFX0ZIP@X}AdV(AOI8({V(=vB+xw1alEzv)8T@m~~z z{Ecl2l&|y7i-@d`Pj}RF$I>Bh+JOdp|C+^bjyqrA02#7JJYHy2Aoj?ayi)%vYJz|7 z=D#n-z$wR{r+Hxm{&Jbv_49C_*Rlf-gM4M`a ze=q0vMYjo-0fLf3Hnp+3YKnqI3Hki|-hXZ7-}J-z0mNlsNzr%|X+?;B(!(nkd+p*c zCiidg0umnx$dFxNmeCCZHzVBjgl2vx9)ghwt`bJP8gBhSquOEQci6cf|J)9cD)P|* z0g|-C@o*I$FZVr|V>ErS%^Y<#OV#!N;kf$=L6FE92cuPy99&_wpR+t{8Ya}$B15!{ zwu3H66aV*IuPQdl5pmd{o4}fip9|wPTRk%OJXtqPJBV%3P~*gdW-XlGB-1_pH-7vE z==XCw$PhmqEpj?74YbAaV79js9CC6AzX#ghB=$PJWU${-mA!fGs-pe>M3bsE7_zO2 zpenmV*xj!e*=3RpoEm_Y>}EaN$evFgd?!SG=#5Ca|347Tvh;6W;0jKoF((&=kp}k! zPtxx;&+s&6Yu12PLENb-7ZvF{zRqXOuJ?FkK*l|i$Nb*p|GYrvB7^W#WfI%nB6Y9BtNwpi7)xIJIZABs67=q!8>Yiv+E8}^$Go7`$xGFUi0qR%-|VN0kb z=hGAYZv^|to%scRP-ye@;rg^Nd!}PSMhk^Ko{#hDtXR#1Y~P-|e}`wvggr)Fox~;VR=pALAgD!ps%K5+zA?DU z-}8mCTF!HHew<}@OIbphGg-*AG4+{=$>aY4svp49-*%$PrC5l^{X^=U|D zJJ1c49Trj6f?R*&ITXWJ)jV zeN#m%FhG>BdQ+h{CB0*IJSpjgJhh4K`ewW(sd@2tW8#g13wc(9ABh`a-|z;cKf8X`pS;w7_V;=iOWSAcZw;2LVr1IDJUZXAcLD@JQ+MIP+}(xVJK? z#Q4vMxF=3%O3Je3OoAy0lVm4(i@#oT;J8PDS%c-zg6YR{;Lp$?3e*}Uf3|wBQ5EBa z&M00w70;%zzVA|sTYza}I z*$yf@4P0vCvna2D1<3e1M)9``v4_MzbkTD~P+}FGQVLuz(zqcyFCX?L!q5oQ9>O~Q zF_+M3PBwM1?`^fA*P`9(=xK}Q>McT z97y(KU2~+0qq+=D5Hr-KD_!@Rhei?H&5_xuDxt?pM;ITY?s|!f_Gh%+cpo9Pqxl7z zLb@CL!ng3E%R9{~+(O_w*8BqKDz*xhSOF%SjXz6{7*8^c7Fg;)Qg)Fc($lO*E(>6E z8ypM!+Ld8%Z(teJj5V#dU_v_i4r{+#`iqSV^@8Q7UM4?ObT*$B%LFtQ+X+j`6{{6i zmanx<5lXk`Grr=Ii0Cz_v~N@O8`F`?6d0Y%66Bi}xgl`tSXG9|fyQGOFaAnn8i`_c zHEF9_Clk#icM^fri$3>mkDmqA2rbECwOQvGG8=#fYn}Pv#Juq8JJWZrpVQR&cz>)+ z`daWDLhE7Y3q43Q+P_hVmJB{TEIVIv+vjCrLA|NKPhzbFE52hBDB5pt*1e-cfCWQd zm*>rG=`mv&?B8~F7wdn}K7VtC*e{ePYyC&ffoEm-Ekf;pg)ms+XByG}-f{Gq5IR-LZnpMyO**$L4{K z9M=2?CC6_tvv|%m%%6NI|IBcC6$#is`&VFQH`;8;bU>MQruD6jHJBN-qsh1vID7_= zY(1#Zy+G5fWx;IdA%pEIAL(`6kST%nhnTJ|zeq(%<7X2gz=Z8E@iWPgT z+pzAH2X(~Ui12g-#YIFp66)us@HES(oWAP5Vz18tFzgF9etKf%Xu7vf4dN5yrfIs^aKnsM^7oQSR$SY2#)6o3p?oLV_($z$rcb=R3G7i{Kp% zG_~tu{TS;JBTa*32!`9D5KSp_8ieEzofj!SUwv*bxJ(D@X7aPN028zSx(Z-5^6c;} zhyT~%JEixbl|JR;%jq~j`F$%3sD8T#(G6OGYBi)jIgXJi!QjHHITz5|H{=A7q*MV2w|(=GS09Uo(>ZDZCKh;4pX^ zL3FR7mJ(L_sI}ftYdl z7dZu03sI10D(Z;*KBt#xEfbk2a9$j>LNL5pwsLtjCC)KnUg zbMh&F`dg8JRwjV3vroAuz`NIQDumt_o;>FdT-@4#xUh<=%30BoQi3_R^EArBlHwS|mw19mn5?u>vIZqTTas|o1* z{~kBV0U(Wty2yWz4DR$>U?AsW0p=ny!Sd591E8cShrFY~YzKkSP5spKk-#hjiP12+ z!mG(P{KVfATI7n$e*oj3D@FqBf30}+|83k}-d3>U!aM&pGJplljPt(%_Zo?B|NjGS z{yQiOfoN*{_ll8#`yVU5!o&ZEaaWR%kX8jE^WR$r?)<-?$}hmt>0Eq%MsTa>BKJJ` z|G*^<8E?f!qp+|%6PT*Y**!zR#oo0z{KqzfjlbIFo`@Nu3%yS?7h}&eI!+F~$WvYS z?p~}kbb_vZQ%gsvIZ4ywQ7`nn2iTu!DX){4VJh&@Zc_M9eLC^E6n?St=Zr-3;q%A( zM1yy{ABwJMjb}4=Ansq6rDHz9q66mhY8Bbx>mX4YoQI~xjdod z$2WHfn{`>Z`&fM4b5$V?8+HoKz=kbD??U9jXL0`U`T8n3el-iYVo_M)%(&rpl7vn!WaVOs* zXLer*?bni8K9GrC-(^Aq_o2wDRvLD?%ih5H?Ul(jy?wE2@ukIBE=6qBdkM~8%95Ty z{axgAw-)QSQyNcw-ln)$A_oOfz53(Rf87&;^Cum|^X38UfUA;ksD->QcZTcvl26Yk zjIPAIPZOkAsVpA5U4o&-yP;Bry;AFWXlr8swKYFMYiroKAQl=m=pz?!5oH{!q5a1UjlrEcjDs<$iXGp`P2IisJ2ooS>v{ewct2lD zf3I}_6MrN02XfYTApU-Iw?%FbW0qoLh^_-L97AJaWsD&gHTpG(l5C}KYoZNALh}ut z!-o6lzwi>g`5Q0cIPlJmcq!4`>-4iS68R5_0T6K4@ktu6@OD_kvM97D?W${?58!`H zba)4Xg+b=UX&xOS7E zTF|bmmSE}7V!h0b_ZO1!!Xct~U`$vyVcAnAa{s5=yn+1TtyTm99Sav-;@U{m^G?bj zX~^+NaHcvOKaG$JpQt|nI$I7|_x}Bv)$fFW*xD)p080KCl*xF2LOo+xF#5DzsmhuV z=PZ%hBFDI?!@`&|YZWhkqmpo4aHtO;x2^u30-Cj-qQy(@EQ*GZ#1S33H#)>);uB>1oPGR3gvGmA~IP?kW+p!>_fy#Rx zp7el%hQrkut*HA!B5od(D=q2ctdNjpfIO@0YsUTlZ}|4P??DdwioU3G z(4Fl_8n!MQR+A4Fa4KSVTY_a>jnNGghbCOX!v|_a`sKJkS@6#0s4CRCLimqC8JtmmfzdP|4vP@eDzTI*`(a)qz{;zwa(o%Y3+KRb zRpp=jwBUI;p*5aoC0CE51#nz_)z$|pRM*v4Bc|U?U7;=*hiNXS%ioK)2X-OQ%!$T( z*==zq1b_th+I#jJ$&orLVuB1ifZ+h?fc(?HQCjLFZCb5n5wa3>svI)ushYs~WJKXn z;0{KjcWMy6rE!7pNKr27)J@G>(!PE;I+Yn!jz)yfC;Rm4rY$Nt)_SV8auS@CbsD77 zxh>_$MG~0f0)}q@f+9GLz5`d-@T1v>j-D=bQls6+hE=<*1q-zbyF&o@aiS$y`vve? z<`e`OSYa?_hSemzI(q;}us1*WKQCPOPui7RCL3j_Tbqp^{UaG9KE`5&M4xkMajM z2dl`3e7R`-w&qqUmAxJ{UI&=>IzyGVUm(?*M;c5%ef(p((A}!n?kcl@Qm^umXxH!mJL|8=$ri#Q97_0-F1 zS6dYjy!k0uBP52&k0q~hscHIDm`2rygW3Rl^%nN_t>E=wVIOh%g(zK0X3#@!eMR&` ze2#Nb$7G)|kS13XW^jzrI?mht^se|0IevzAd@g&!S_{iC5+TMh5H}LTl)^e?%*@## zd@BzJss91*D+&|Dj5n}k*I3cBBEzL>pb1Pq4_Yu%MN{W}HRQhtRil)CnAjAdJN4F7 zBE}|(xzaJ`T0wA(Ek>fP+#5U`SGlN76179j+6?vN`+toD+GX2a)(n*M<8@(`dA%Ic z+><6pBE~}~)>4cjpYh|;kUN{(Z(3Ue2S5fQ6bsMg?)WD>ALz4hOIG}(f1xmUrntAU zEDcDD315nR3KW8?lo7yh)==b9L?7QN&6N~ch5RHDKqnZ`-N+IykBBk0yTwu5HKR=s zM;5G(MzZNyGFCm;d?|CbV_h>GgNbLQn`CyWTg+((=&eDPFPF?{8XRom$6qB@je%@ap=JcuE`$ z{)Z;!C~at7o#um3j``2}OXp{*PLmhgR zj&p$LOR4I5 z1)uagSKB?zS_HJUWz4KLHf9uY?x1>#9`Dp*Q2wW})jPq|_m0KrQvTD?baVG?4OC!T z>IHq^i}mPnegX^_aK)s}kP|6ETWhYLilb32duX$Cxx@M(0PN$D~uz z)ZRsb3s%u=gqFvo-_OzvmV_4;J!pKj70>GyVtsCMLU#&%B4SxNYR-J9xjc$~xHUS- z71Y~Cc8zl09mgN4avCbkIgF}wCRWkUGXVeEYum4Rd$Qrf z^*GqdyzHr*nL)_)+~wi>jGCE7o@uBj32#(B#Yd^;vL6PSqXDjh5X!%3^|koy?aM&> z4$F%tEtHx2FO|X(&33{Sf3`ESCwwNiM0B>f{T7OYoK_V}izbi~`_>EP^wn1UnEiARiBg-#0)WUusCmBBc z?%xvofQLm%c`C9UF+2%Ff#hLBOCvY1K|3OBbaW8v?sQZbD7lH*$cvEmAlu| zoAF?W*7D(l0A3>wLw#vWR znsM{q0xq~tF53{#G|J?6ae8~=ojj%#^>FB46Wb)WsXb|HbPW$y>W_e6ynzpQZn$xv zRoKesk=uS9!8mqyoJYtN++{6cX`QH1@IYqd7SJk-%BU!7zr-BL>^K9B>@FQ7+1E$$ z-Y+I21W&nkplY7D8=7fsg+(C;wh~X`u@@fmSx(vnm*(y4k+p6kn>WSI1a#xx;pHQ^ z)Q9RrND3qX6u2HwICcZJDe$buLNj8yPg2unwrDYt4hvIhx?J+`8_wZ@a>9sPeJ~%@ zWAVs|b%k=EOVIoH^z+g|9{p{Qt>Wmb~wK z9-N807_2N{O;7j#vG!I0S#I0+ut@k)@)82lNOuWHcXvxS(jg@+h|(R>Dbn3tigbfC zf^@eu-@>y!XYcbn7ypazZeO^0o_DUf<{Wd3vDOplX7I_$q^YUytARt)=tM3^NLo;t z#@XDDSG9GuSbKGynN8$zfRN8&lF3W?R^9{R# zBWotBq&pYSjG+=P#Z4a#WJ&-h+$c`zUoQh~OOMFY#q@uci^(G$&1x7im2K4EK7FaozUaOnhWO?D z7X24|9U(Sdy5=lTB*=2!8Jp0^?S6Ux(0{W37&X-l zw`3LdDD0VJUmI$9#cV|Uyn`w~w-A5bSXZRZ$VACES?Nyz3x(v5owrYoU>C7UgKU!L ze$~M;QiI9&Hjz!W!ZE0KR#=Uy0JWvX6RR-v-!-f-6#UX6)~!1=@t(4sS-&;>pC)9> zGD0e+X@=!FBuXVA@sES!ZxpFzdsOh~MU14Ur+Gh4;8_h0ns;nxo2WQ$MdMX#E%Ya} zTMw8|dcA3JPz>EEfFK(GB%+!8k%nn3s^1)?E8|XCp)TT|B4Zf|(V(1>q{Mh|vc(BM zz|1k4SW0bD-R@b{Vx#Ob@7!;aZ(@K3XBc4Ed~(5dtLbq6t}yVK*=fEHu-CT`;2RUf zr^rlSko&XDQroes_z0XJfS-$wv5vGs+C_rkhHowb-=f3=+QjbB)4#6@;WER zt-H|1?4Wy)^Gok-yiR>#6Z}lR4d=X1lV?WAWZ)-rT8lGZ%vF7y=Q-@vY*vbm2>tWE zBUC5KZ$;gRQ|N-H@Eb^wOU-b4^)PAVY^{Ht_P}YE^-|yOwapY2_AY#veD_H44Gin5 zU@&29$(<~sHN*VxwTZ#2208J)VsK|~6<{m5981UVWAMG>qVz#nys0WSp+D*wwa#qT zJ+m=u1+4;lja<$%%M$Zc7;hqSVJTpzo%kVZwMwJ-#xmbbCy9z|ZFZd;-eOalO`zIS z^p%q#vk1G}RGnO!Pb-KGnD7r@oJa2nc72Pfv(w@C}O7@45qiOi;xj%^KkmZZ4z4BY2`GWey! z(hQ#AhBFSooi-aZD+HnL_%BXKFvLT-Ie9HSvp3GmM z2>h)c2o$lp%O^;gb9$7ya`}f_g}tuy%X$rIG{abftRwC&%nXtCw-X5GMxMsoN-*cK zYBKuRw=Cq;mkuIw_M|JQO>VnKONxw-L}RSBN%pi+Pupdik}XRU%NJZ9DXWNAhKEEZ zXZ&PNDjv#F*C*r7j~FY_5R)`ZE3G{nH%Rh7RLNW}2oKITs-}i~7aFPPHzPc)jq%vj zGOa541vLHy5o*5-qnjVloENGAGR_%M1<&K#+mWIqn!TGupe=Eq(A~Oi47X&EFwy-* zzzGew=d+Eufh0}WSFp5ER1JkZLJ*b|J62T0&7ceam+alxaZ)8LE{%00uFj@hPFZ);zbg^t6k~Z zCy7X|A$UZJ$RPw_{qX|4kym}3*>CHm^c`rheb%obrY+GTk|&uyE6_6-<{~hCqejqC zJoRGCYnSXv2%SMlt^bCpj~())Y9+0A()4SuN|=^KVJ2DXkVVy1!E;78^4D}qtxe-| zMjLUkaBM5=T6*%OPwYJ2IKQeN5ljrewA$74XY-$5ha#;bVoqN*U1lYSOz{EMBxXXK zgSOQ!4E;3Sx>+(&0|FJ(Dn7l z4daxs{2v3N@gA;`a{2SXarrlK34S~F$M*J8YUJ`SQG1$`BJxHvK_tP>F0Cw?KzO#k zy>A|XXI6zNiU8r*fab&5cGL6IeA zV!y4U?*19ED>T@Ka$8?PqkKlqqza>g=(JhK#desG=nynzfMo(Hv7W$cYpf0IaBuB% z{<>#VKMotp_Id}XRweli+O)P9=M;i(Q$Bh`cT2P?aHsM=kP`80$XL>>Yiu=~Tl9~k zNrt2NYSt%ZS_QpoNH~mJvXhOtZa+KxXWJm3C23UT#tAQbDUK#CGs!)M-+#@DjygQj zO65^GZ$UsLq`@cgo-qHk5*71ge9>+X-V4I#-xKN-v1@eH@BVWE z57O&}){uhJ@2X-s9SiF?$q3@Xr``rxVUZ}|QK^>W4N9nf75ysPrReh(8s(`jBGxn- z6cYkqC{oB^(^QyX4q=Y5ga)J(aS)WU5=3pgVr{neSbE<wnWiky`U5x7#X^plnGJ zHd)ltwsfoyY+U@0H(e@LIEVUi)a~Y7&zPH46x!8sNOMq&$CpkX-z{(?6yHe}Q&#hd zm3aH}*@ZLNu)O?&5_)1*IAh>~qoy?$R-RLWYb+@U+nS(f^;~Vk5(UaU7 zCQUgkDmeHI3K%+}GzfiKpB&0x_b$4NA&HrMLg4OWL!gJ(NcpE}=5OHZ^BDNpjuW)BK^Q+d*wzG6!GP%orIzglAWl-mlJM@iGF=430IMp)em0lJv!QPMUo{X-) zdzl#U!2xID((3E?IKxioJ(|AV|XN86;SLh@wlE$C(qxMDOIw!VIfb+1sA5xldiZJ4T(?!wQ3dPq+OAjQ&k3ZtrsWH-B4x=Au>haia?Y=D;X_8DBNxaL69~s) zSrh|msoO-Rc<*9HFnFDdg!*PIhBfJX5rv0KhH_N5=XLdCvsI1HZDOrt#E0@vZl4bW zhDxD~85uq^z_1do7JK7{m0_6Tes0@);$J)dPE;hAq%M)~^2c7p$ji_@EJOn!ep*w}zAR{FJ(8&UY4VT(WIs? z=7<7+Uf5 z4LKMA-8~9jya1bj0tfo)Bfoig=OicmflzE`jpW;)37yNs6PP8mbsd4Y(t!pt5FLikVS6o^?JCD zQQ0FjOf02>;{7uBeGGFi37Jq@3M6Wn{6*8_g37uKT24+_L2 zu^VX*g#WCK;oSgf)ya5;-y%c-8mz9lGe|jng`pU_H}bag4;(b4`|*XK;uDvkp?X2)!+SirN;=w9`4EMLHoV!pd#%Ny zMt2mdQ{7=fDgUzTr#S!F=Q4)Sg?(xKYe2q!Y2n|>7I*9E5P>jf$CEg8P3+YI`F(%B zxZ>~+Dl)-w-&u2PO<*-osgb&7BQ-;}V1%ffX-cYux6O!!H);`5FDBvYB^w`iJs^|j zcveyct)kh*nQy+2gRg?RZFas&!?3!dHv$h|9f?RtwaJV7R7g7@b;?4dy0L$INzn-R zw>4-zBXvTieP{YIv>$#pi2C!3-lAhv^+J0X+DyGyTB^gmG=;WC9Eyvmn$AC2w{N4g zoY`k9X5p6})F5q}xrNMr^8t`KrhqF8&Jd2Q{?0zDX=1}p4HXnN%yBCQ5fR)|VSS+s z%nXEgPk!xc)IPnjoOWTlr_$eaCoI@KC;i*2fOK#oLrbB?Nk5YKJijMPZ^fcTz`h~u zP1bnlU&M{Zg&pnA1+|G;*kPnFt9kjZPrGFA;0e}*G5O(9V~3eQGEo(%VXxl)>M>s0 zY9D_Ro8In@#>n?QJVfkw^XDap6c$Z*)bz|^wIqXx{O(HijTYr|*icL2^s$t&~r}Z<;AqSSHQP>3K zyI5breDmuG{CkXIP_B~}H_AZ{_X;wfkMJmfIz80f;@f6>$$f?3rGogX7q@?B|J#oT zny>&^37$UbSXkY}jO{#WJa8Mtr|p3%{Ji!90Hv(0L~DXZfbsQX*89T7-8?{X5BDX) zD88$gz5(rCP`o`@-V2s8VFh} zC`j~nY~e;oW)06E(@%vJHJMWK^M{jkqPfXCne&QF?L+%>-hYIh$|<;$%x{fc~#KihW26u#dLN?iVi4KHM5bo<%TW&?>{N)eQQv)6L z84o`!5#d-gVr3N{&1N7Uev%}H2p6izoo_b0*h>8Y_Ybbu3D&*xbe|?pL!!=%Xev>b z+U-QuG{4Jys|fm&U@BM2E-iVn8(i6HI8P~>7NU9KCL^3LYh1_G5}P{YB!^k?>RyAA zu`!ax`btmy-V4ZdV%4{su>~+i+GIhZPB<(9C_zzb)s3GMy?{(}0u`@x?qC@>-QXRu zV((^bR3o6--VJu}0Z^T0l+$mx*RlhLf6-I})BTwI@0oS1-A{@I9~$G=rycmMK_-Wv z2V><~4w!z|S2^P>abe%k@f0H1Bo))gKXyfWQ!rt!sg!lyc^GV!Z2~JggsSIkI-Tnj zCkkJDqx#997+F{EMQ{IiF)6#y7`efcKI_RtkGE*GH?k^MpLV#-jF_c+r4-9qD%Tq* zdu>jw?={#HDE9X1?)yujc0f4EBy6^$DJw<30F*z?=qo?yl+RI?uF%xy7kZJTBcB#)VGlXXe4+nigMlLZi_MOriAay*F;}26w)xU;-G=mE;_s>_Rt^*0Np} zCq|5_QHxu2%PqF(abI7(C?VN{ShH&HO1&_}n=w=V)@VQq+y4A+WV+6q(1#IHIRk6@ zM(&f-8|zKoAk$xjk9zm{)V&>>t~p04thmkKdE$c_qCb42KW$>viXR=fH4|aiVvOi3 z!qiM2A5k^T4Ue0HYP-7{O~0e+yL(e{1V}SiA_jas?cNQ+3i0u;S)b=L1>3{rBR|%< z?OPJm0+pS}bW3Ug>Xf%%j)$T?SFPb((zD`on{NAi1vvefpH+94;9bv;JFlMVrD})# zWAp8`TbE0-cg^xpBI>GZ>V73v(ZF0GM$Qg-k-Aw>vAi~25)p3`Rcn8D*mPtPYjds{CZ8V5ARJ|A^OhhvX#q@BbfHeV z%Q2L&msa@bw%%P)-A_y(nTh?>I(pbQygBQE#~29}q?N&Zube6X4d@LY8Shf(_7_%G>_EUWRA0fbY?dyrwByMC2COi!FM zcTD}ZDt>5O;f$OQujW!Tny5Zp{~*gC_oBhZBk+HNm?JE#ACJy3hYeG(0}5tQUKsru z(mfuMfX^%~6rw{C9szaux7H0P2F#eR?m{`O!TDFhnx^Ou&R~FI$}Joh51GdznR=7| zRq*J+S8bs;yld2(+tbxIqNrM+zaGD(Bp@unBPeQ<6=tzKa92m=_ZGEbH70$kbYJ3Q zIsEK_tHjpgLh-dPc%%Vv0AcwXf$sDhrT3FMu`&B|>sV&|C)+ip@)H$Re(eJAM5 zS^z6oSFh^Dz$6isg=MlmESbA9UVWOYX1M|2Wm9^Q;TS{-${nzo4wT$i+1i$~{doxY zss)yk#mU3=vmPzZ7hidl-~E!;+!nEfLcc`#4Ws`R%-=2_kM0l3>_5@aDYlK}y5n+S z9Gn*qU&FJFOv>dk?`XdqmZhi8gLDk`K9}8FUB8f1SO2W+1AhhlJSWf1`c{$UKBG6r zzGIFVMzmfBVjM5}$mp=`p>Z}&?S1N40A2q1&Xa+xsH9Gu5uPZ+oj$~4*iakiU}ox zT_A%ll}a_3L4_UyaSG-j>Y7)C2ls|5B~NJ51o(WE3(j86Dky;MhGp?R87^rZ;7<23 zgQ0N)X}zy=ZRa0bW`1HX=whQsX^meEa%n5m)dd@K<&5jI{@YB#5->~_IiU`Nv1*4q z2I-lI;yYY+bcmMgxI~o(3SxL)(L_>F$zWwMwXb<8^~;D}VOF}S%_!ObwUVDPm zRoZE@iLs~)6VI!ma$ce2r|@e3^-d~Kxdg>Um-Uefm?)j-v@5Gx=nco)YB~aRjfU)^ zuLdrfs9KtIU%Ryiy3dte!j+cmh4V#`D!d*Zsh#z_|8T^CL&U7e6F7_0h#X`wO2I%`ZO*`s0Z-8cG)IOITNZZ zR*X!)>hR#YC9B(yIuer>p>nuOgY|N0Kb!m$z6(U@xK#*QnO0MuY6N406o2)WGR0Ge zEf7<9{A&V^q|gTHkK#|0*dhwIV!}m$2S^691jJ;h0M>%fYAZEI!ab7nyfJ^9mlR_6 z##Ab~M8hX;L4ZMV*sS^Coo3k|GZa9k-+T?#3xVKJ(!wD07-KsrZ($JoXgl!nhCNnZ>43N7`$^{7WiP3zp{(hOrW*JW!CMM# zoPE|FWmE?@@Hl%8;f!7K{i$?Z{$4OBHE-QhE!OHUdBWozRNlkBF_QZ9*$9h7`vxBG zDTd1B_p!LyKCKze@BFT-KcX@XV-~J8y~mor^_B*0QLD0Lu*tLZM&j6f+fp<)c^SI1 z8M~Engw3GMi|~pZ1aGRg&Ev|X+R!}ENKsK>(*KLKeJ)0o!<&4)#XDNA`g=>7jGA#s zanhCp*D$e&d=&QW`2yu3GX1NfK&MhX&&@(U+OQVRc~%d(qKpAfAAZrBum3TtIYO?m za3eswdV;YE-l*Ge$Tuq5D$7J;5?p=#lY7spTL2N=j9k~=r0M!6GV0TTU8Lsel|(5H z$b@-|&ZOBKqXrP;qj3;LB$g5(jN^3M8g4K#m(Tk}pz(`X&xP77v%kt-sU6S`2b4vy zXfiVOkDje>vF?1ySl-Nw?{~+%r5U?N1Kf8vMzw<1Z-ujoo`})n?*y(KjJ+R+J^tgW z`rsR)-;s`*l>R$8O&LB~J7ARg%kCD5XND}2JTjWciBpT0WyucQZ5J0|`)iY}QMx<~ zxqC6ls39R(9<*A3mM)x?Lwfgq>O?6YSwX&lO*{G2%q^LvT&PjK;PPC!)9PvU&}UV? zRAoNKN*7zbpO*PZ2;%k9UN((Vre(~h@(fN7&z^ut@B98T32DDvtW*EIVQ%k}NK5|o zU2Q=AnbfHn@-6#Mj{AV`x?@6!eBmyKa2oIZn*Dy3+HOsrcC`QWYxcf;6Jtg`5t-@O z_@2|Y@{Q0aVNe(`!#+)+J@VkAVBp8if3PnLys%TE;PX^I=~O$^6a{q_wOhO7a>hLJ zC=K`4T7*f$!7?==-=)NH*lpw3;s%L@dFqV-U{RVFHOnAM<^)~n_lEjosMdPRIGR|* zL~Oc-c*BvyEXhUgUthx0p;{j%9`pV-UHbR1hKMGMgNN}jckrVMS`m}m={EDM{6;yN z#N8jqHQ@rV#rd7U+!K-Nn0mL|GRV;u_GLbZ9VGDR4QNElrG4M4H_Bu4azTe@S~}Pi z)@FEa=_x3r>EmFW-Xgk@4Y^+Jv;kS@{omeBRBO87`6h{pOhhmDf=E7LEVuNVKZ)P91cH zZ@Lsj+m0+Z&kUfeM!d~4DY{zmb;XEb24G)rs$d@9GkthJ5%38U0~_>Td+1-*c|FPG z5j+h;+~hn%IK#l#_JKGS!WE3Mshz4Qs7kkd1*_j3cQsE#vA$>u(So0X6RoT2IQu0o z{L5(ezTJ!?y+R?IQbgse6o!)2r_j}nt+yXrk!;4E=70M?#`a+z(q7u)!ER;jwbmEfMrNP#;$SLdQBok5yYc82D#$0aq;C(QTDJj=)vt# zcclMueRP9(T)cbRV3aC5m5DUY?u(0+0PR#AEN0u01()VhOI^Ul{eiT<4?7Ge!(^I1 z*Jre=hI_IN7?67Y!2S_%{YCXFUXr^KbuSt8+Bic~$XVmct`6@b^g=BldNadzGCs<~1owa|!2kctQOo~tvperoN~OeFtPOpE z5}0WYqmRp7y1kh^)7B!bkn6)`XzepSX()8+3+JmzfsO|p+Z=oa9+(%Q`wH(8Y) zy|0^OVyzBXy$n`I);~?`r+(Os1rpDDlu3>6c=PdA(tx8Uaf)bjj2GTtr24=8<^(Cs zWON*}p_51IebeG&J(fQ+l{+s(b_G^ze9|&g-L%+lV$HUsPy@vu?6q}1&1H8SoxwJ< zz)7F5r5)b=_!NT{^_689&XcuZ^~w*Lklv~x8U-xh1prhoksd`e@-6GrN$z_a4=C`& zY(F{o5wiOe@IQWZVuKo|MBWvWt?-EXPQ%6?>sI(LSKuElE}O?&FaNqq9VafVr}E&%)h^rUfnvLNN6Gyt#J z{HdV+bAENsfME0XHQHY>02;t=&;7H&d(RnUdHcT-4l3k%A1m(XW{rT^Va{`+N}-h_ZSj6MQ!_88?{EL| zKRf-QGtvNsTXvDS6kjxvqRvPY&9lauX^nOJ=ey!tEH84a#7|4zNIUiPge80Ea)~gA z|B(%UUa`$_$KGdUYW2P$wAc0azomu{!7-dly0?{j$cr2#lR4%|EcLUQ8GD7l>(!mo)h z!-pa9JGK7o8&Cux!ZF@^B6Vv92q?dPk*~GiVAki@`)n=S&(4#p1^dfNWlLLKjprYm z+LO$&;4+k=R&>XtQURIOuUF^A{RWkdPypE3R3$~p%-f}UOA2H<1DQI6w znIp~l1uoa%#Ii@nON61-`Dl^2W_27<(rK5%?`d!%X@B^UJr)dmmRmgKO37NCr)CA+ z$r#;OY6CF$Xv;c?|7tsJY}V*?rce|g;(S`P2F%Br=g;9AR2Aa_wx87zY-BlvoH;~s z7Bu2oQ1MQy>RTq*kbMqwv>&^FvQMp^s53_>zdkvYA*Q2P3r82SFqQxV3h3f=zB)# zS-YqXEkPS<@EVoA9W-uvOjoKA^XjWV5+2IRvlKrMBzLph5B@IA_HI<>%;q}7gO10- ztc+^ymHO7)mcK;xZTJv|{D>-3v*1w0mAScou=|Bwdkw~qcbuWAi}^G#hJy+FqHk|( z-i6ZX98B5=Xas|Lgl<$X_Mh1mvH~LOzl-c;CEC&meSSt(Pw$OI8T?ARfdY%)utC*Z z)dzuamu?!YZjeX|&f>w7>sLHM95Vg!>g+XGvFsgBg?8VDaz!g|kdJ2_QNBPXxLPVm z7{lomdS{BGE~4rxt0kt2q!0COi9-AV($aV|#FV`koEpQpKTJoiRXeLFgcH?U$fhp( zc}1;lQ+};i|H_QX8X)E7YZ^JJxaBm?#5OYo(RO}{xPcy=-Zg}-cP)5)q!~&%aq2XZ zec4@)1Ru-=nM{QC1Qe6_e}t{!cjVb=4X<`!|7g-9)EnzM#(&ls<1cCPdBjJd!<_wnF6Qz z{KFCygA{e};(He%hOM>q4{J)f658RDFx=_&hlSM**+n}RjW`1oNg!k@AwQM` z))8u}oHfa23fQk*+il;_au+99llmRBZ{p*{>Q+h1I}D(f()->%=Xn{ZJw5zT7uB+? zE=%)ZTthno(Ij_*>h(R474jtbd&87!Jtd9(ULeTTbiPW|epc(v_wXUfmMprD@jg81 z26ki;T5ID-3ECAPB<#C6XBDPUa2fCs)ew^A+NyAIW`lKeYKrx4oGRIB3j>F&P{% zuQ-62cr<&TS3c_t$imMq)QM$l@k193i1~S6|WVLqTFk{?M*Q z&~^cptI`V1^aa`zqUcSb#xTz+ZiKV}ni5|=sarjHrLcs@`|412&YF%J#Km3L@s2vN z{sMXB*{&dxlvYxhv|h%dn%Qn+HjYIOhn#lv@+*2xHWVi8+OJpe08alm3fN5N_Xp#y zRF9)ym2~^=qK8nO(c;sojV}*xHx*n$-#91E=Sm)>&F70*X$U2F=Z{{9!63ikijfy~ zmN&6P$4Rh3RBUvjgGe1L?v)A1S?;FHkyTr!K!hu_<6(s)DFp~qpHVjBhNDiUci9|z z3*DFee*>*Q7;aR+3(^_B-bsBYpuh9Mw}s)88Kn=*t9|&T8Ih+c;T3(Ll!T^14Svy7 zj92!gZN9HAB$2Gv4tk?~d|LYUDovaV$yj=D{I@u60yREz zS$@NA%#0SR1ShGt&JKu$qpgn_2uDDz_z@7Hc?mX@1OqR-#}&vWvQsm6ddM9+6Wri( zw@l>t3qJ3f*x6-RKj7j=|MKlGfYad}EAmot5;s{7BUPP#i9w7kVL)AZdk&jMTV|dC zW&_2nrG$4MN@F7uU{f0Jsr1t(X*K2Q%O zfwPg44vL@1w^5LYomi8+GD8%-=H<6S_Vl+&Pc45It*^Q^kdD^b`N{D$i|!Kj_@bQd zBljs=Q#^iAdcMPU^+sPrsEVrDkwU-^!#chtIg_pNuS?hbo4(+46lw57-Zd=kXZh}8 z_;7BERnFIa|7ZE{)}ek=v(6_EX;6m_0n%D0cb?<_iM`usv)tQ@z$3Dr2&2Rqp}TO! z3>qA6J^!&qq|89a!N$BP`uG*}klGN;JaS=q5=fA{PWgUlhFrzXV*0-2PD2;#$;(^RQs%RhnzVfa(G2-33gFg<+Xp3>7nfZE$75eQk+VaQnwjLImNTV(^Gcsw)Iw|ry+5oQk8797;y z_w2s$}0#W*yBqlV)z^v!#B0n57r>v0PEpoz1EIiCm8>;Pa_dIhf zgW(IxO;gp+h~#uvicXOiXMF=f8QB~JJr6Bh!I^(iuS2vZYP+|5OPI~i>DkGbu79;l z>B#ko@g#gr2OLMUfuoV)Tzz!_tKRkNA?8Vip-Jorg~G{$QH{(pD$&Pb)*(IbyMo^O z;(l;u{~R$CE2x^`_QUFxiYQ0Q#w;Nfk(+Dw?n-iuqR+G!URs0AvUId;9mVC&PIdW; z`)W09$$O5}s82dTq$8v*KV8ypPQCP+7SW+VHwWwm}zmS4A+z0G6r-Im<_ez zFneys0?-a{5-`ui!5_V7yTHc~+&jAZb`~;(o9?;rjIMm0wvpP^eJeXuMj&WlJgs`j;U&$7LHURB}`#75_R(v*;1l%{gyK2QieaGH_fL*|&bHGIzX|^y{NU zN5+^sH2!x;bJ@#lf zm6h?5&PqP4)W;0?+ob0mE9s9NqS~ZDY5!E0mCWzEePc8>^7EC9{*C)S$O|$(-Ln;m z*@tJj)8STzb4^BziQmkuKfKMX_UT8&?$2qH#K}UEdeKVr48P;Ue7yhXYuwjJ93A;f zq;nl!1{6c>{Zt#EeM6S-Ig!7y5!aKPuOULsbL?)Xi~I{jSgwqW*(Q!Ak9&}3@Vq8R zNVQTCo!~dbkA{0Z33=f$;7|IGk6jrTJrHJ6FmWI8yi=7~y$G7W>B5`M=Z$=I-BT#g z)J$ZOFwf>E{7wd!o!{X01KbPvJTk?Ej0{Oiv|4;~nHT%>F&a#BE}q7sX90yq29Ji7 zbk4}~l@7m0)c8I}LK*T8s8N9#vG{5)2CnpgRuRwX#22tlN|M?Py6<=~eKL+eYhZwBaFpV#)q^Wgn3S(YyPxxE0Wmf1?6? z4oI&VH^?Cz&e|VWqX5oN8ArLcHhu_sQlgjcCp*9`Xg5<*=yk}^0A290 z;`1z*7<@sYxd6|KT{b$!b@?P9vVsv1p_tz(%+}q6T5Qt zS&!D_iAIc9t|MqP+9L2#ArHE zGq=CKs0xW24B^`e1b1*VxRU^{T!p*0cYyd-7>Vc7v95x5)xaLjxgXTU!{G9=sKfGi za>PI2a1DnDubVr@VED>$W#G)O3XMRubN==9JVdbppVPf7Pc~niv_ltM`yB7KSB4kF_PEBa7#Qg z5fB$B4J17o=V*Lq*F~Wn$G>bAz+!4`XP1$!1poWNFIy=`u2uCZfzPcE@|nG(gD4a` zjuX)Zn+9@mAGVs!&t1+-3>Zlbs^$b3?7M;`>sqN;hDus6{#wdC0XKAc^yER+DAH|V zPKmXtJq}t99*%`hE_#_+=(64 zNb2=(zrV<1(!BS6tcEF=tpW$2Aa&oA))2v3!2Cp%U~sbHA+Jkht!ZiGvJfu7SS4rrIa91vjVhz_>Wbp*$zQl~@juRwb<*HJ+8hG> zmZ4ie->u&^e~TM5hq@{AXX!7B!KcGJ-fYA>(6u0QC#tBbjDZjFe8R3m^;|;un)>e5 zdT~U+6=usU8mywWBv*{B4VB=IR~0uP#;7lZpQ0E7rt#^g8L)@vZ0$$Eo^bhvZ^a?8 z_DR1Ww2zupj8*IsN+iwr7D0#x{==&dG?Z)TAYv%~;TCJlu78|doPQ+Adeu$kL0=+N~u7Xf-Cal*01@t33BUB{0YO-e)r zWR8BCiN%9}f2E?{;EG0@)xaH1W=K}fP277!=%`9%ZRbAabrUwAuZEtYaQ&!7sp-Uh z_i`PmbDQC&uim@S40)qa0Mm?v@|f+43uq+16OYE~jfEV4H(HR9qCy*t zbBqusK>W5VaIddlB>;1UwFlS2wIy(_cm&BZEPE&AXLBapfsJ+D)?ON#s5{XiG5UHqWM?b34{NQZs;UA^_>SmETPfKI;wrdG1 zrM59<{)cqm)_9G8(lcLJp@cY9j@oUxaCsPkGSn&}UUQK>-Pk3{_-nqoI@`(m$=4$L>Yk-(;3gH>v0)E)`~hXUdd3 z3Bk>mfHJ8ZzF3_HotK2=>w69KA{|S8fnR(f^WTQyraHxxw+Lb`DVGi~q^j?T-S~K{NooDde zgCQh*UTzvRzZUQs5H>v>*xZ8iBo_zgRXy0F!)94zQ`neJ|x1kZqBk{$nz2vj= z;?-2|oOt*)VtoPgV)(YZybsW)5A{L-aL;e0xCGv_-^w01exuFrFR2giSqM9CMk5VX z!nT(8H$?Tx=Lj`3$OcSLJ3*+%xyNJTN+$rA&A-%W;*Qx{<<_qb%$*OFko42%HMsU_ zO@;L(R9949GWk5|vRen&$xmOu^oDl;f(M_2<%v|PU{LU>c*lbi zXpg&%tVh#WeoAq_Y~aQ!oPBBU?eAm$zlFEUHhu{mDwr?7we{4Z|A8?m~FMIUhA~M(%KiniJbdkXiTJmsV;=ty> zxI2G7$W7mt3qe2aptzcg^^v#BQXiD#wqgDG&V$(tuH!J;T`=3djR&|N1IzXC8P!Jw z&>wT6T9w2(hvl{zbI>si#hM_&IL_~Xz> zM>)Y=7G$@(B9IEyDq<9R(A-^}v{(YOLXHrIX?^xoy*!0*y&FKC4P95?;c=8&fFM0W zFad-3qei~FY5CAjrl2x$kiNAz05`Y7bAHFM14em`g zC_Z@KzD?S zO~0Q2atl&A4(^mgqgPL`A=H@J`aMiylll`E-t-ehA5J>$*N9zpCZ3+G8hXmpDV~|u zwg$W#D@usU+9}1ZR$%rw~p&}7*cmn$l2dXemOrErvcbVTvZoziUs1<5W?cPm5 z>ZU1?>Y<~`7RP1j^zxe*+xevM0GHJQmTQ4E*(%95M)-e|Nj zq!2a`x_>~CTGHySH{g6hphtfcd43q_h#rLOg?!_qr}axj65|9GCB$*p?d;^~eG%PZ zeENh2vLw=eSDKqMZ~(L|kl8=BV%i(=7T6xLAn3~-z*L37Eo2S1oC}-oVfY{LQ5Gv7 zbdvdm9nvLrtm7`Fsja+EPG$1jlAHCKmfqW-0K@bOkXQ=khuk()I z<54$?Z$PkgHq{Y*V(x^igi?nES`yCr{!z+K@?Uu}PrT4~1duhBUC_KTxK!`Fb!^Zo0){?Gaa z{v19tZoM@^$_FXq>Lh;5Esk1g!=KswBJVf8AM6s(lB>%1_9fK?1g}3V+Hd9hO9Ys# zSGf@XcmagcP>Cx~dLnA3OTJdjtUxisY9|(mQ8QqO(yLcN@rhcg5|6{)699vQH$oCa z3W?VD|zZ#HN{GzCj^sH1p3yNSB-?{gk+m-O$CrSH78T^cgBkDbVu zXlmF2#k;3->IB1lz$Jt7EvEl4+uf}vPE{EXi$WP%x5ZR|fJd9qCsv>80vW$y+e{p> z!p9$?nYC7#URJ+PF`w);zZL%&+}nnXWcT6fbFm{)fdt^lel6<>NydA1NFeSpnZc(W zSDEmGid7yJnELEEg~StRgb@Q%^iz^8Y(2DZ(+TzQHers|i{`mks9wuV!=vYy=|0F4 zI>-7|=aPDVM&P$e6mlNkXyxN?r>^ zEa&5J?Qp$X8r*v4vIU3HISQoBdu{0Ux$zhvj!e?zOyc@>IxNi?Hu?v^&8sDwap79HwSk(?WN52B8^T#u;4HSTKZ!!qxb@HOHRXgVzzxi~5Wi-~7_(+lQO+TW zv6~wNnV{|xM$L=w-O!h(QOLIXkz*x(e3It*aCye10dc$F;sk9r0He;I0-x-pfrAb6 zAs+Cgo&+zrP7ae20Ia9vj~?gkLU+*o{&dHd?3X`@Kf?h!w)HiT>CFS^`(0jJykC`D zNgm!3gzoW03G|n<;|$wOI|=}gBoP0+AUEyzY#$Cdvqrv66=5c|%TEXOzo*BB>f6JU z{0<3r2+9P)tT-~a3#haM{p&!vqzd_>cV$+390e8pO!0M=sLk1z7JqV60;#hOXwi<@ z+7%VZ;;+LWQ{7$0__2`lu1`o5rvhX^!}$W6gnG-k4^U%+yF1uIZ^&~ZOK0iuwLUX( zb)dl_w1`IjQik#a)|rK7;9ozMOz3=2c}cat&@Xajk~_V6&6rg?bKueEQdg5f6HX#p zKl_o#XQMk$=H*%xyKdNxHJ}|DC(JIo4HasyaJ08+?m)$RA@=w+-W$2~N6fxEDWv8EHVli?tbtHYxFwr~l7p@))=0R*JGb4aDTOQlmnx(7iTk(BNR=>`X+m5}a~PC**( zhre^qJ?FX4{euVe`DVVo*Ix0icdfm*t%_NC9wn9>=2n2BI{2gFJcUh>(h1Nt2{5uS zdfa&;7<2SJ;00z?y8f{IEBUGJ+yD>SegcTwm^aZLf&i(DgUS>(7r-EHjfGuq7RsVK4ySU67k{_j(D&h9ay<(DCCmU2R+wOpZldTfG%=;zOaCb z?(lJ_SAliC@5R;q)RQ!+=u= zmV~h|1(6pnD;Jn#2^|3qZVs23x4plbm|ZQT!qd4HNA+BY7GF zkKMJHm;5p*f9r*nvlO??dFZM5mz5z9jxBnr8IpMH8`i^e@gs`lC#xL<@2>M(zMKOr z+G9y;AotdHU44e&{bKOqt-_;-=c`#jQt+>_(~C~!vlOYwYi#U!Fv1bH7hnT@>SUli zDX^y9%S<573Un_W|AJkN06DzKHGZJ#vi&=U-^K~LBZkz}-mKJGQ$X(W*j0cA#afV1 zra#?Li~*3@7tAY=Clu_GEca_Qf#Z`@<1qT0k8!KxO#$tc=uqp8ZyXn0n%Q60d7e36 z#>}`@`L`3J@;hGjEj;!s{!I%WE+9`(JiA#GGt=6QP0DKgo_5@<7-n`Fm0EROFi76L zy1I3BtUe$k-=b5@KRR)uhG#dqcI#2U39_TcilVX<%M+3U?VbQ-!qvQ%3mM|bP@qXx z59gG{3Z4?hYp6E0iMeZ?M7Z(vEi0iyxNs=yCuDttfd`LYd6UER$P2rz{=Do1t)9iaz}&aB6rzaV-|3rdG%gMFnkBF+ z-E6Fx@#cd+=wI^Ftiw6@DMJ?@t4}J2`d$`3lD@%jLc^RPu1M>0svwf7Nqpt8aU4G+ zV$dCOE+svSf|MX^_!#tL6=;R2#uIh`>bh=ZU#^cWADcS-KGeN@Yhqy4=pCUL81qr< z`9?i+YiDLm;K*xrFHM!V%ChZqc8V2&NRJg}K}sTrcSuHBUhTk6q8A&dE{|oIe}I5! zSe%~ytZ~L>dO3V|K!TDsfOZL}V*w{;zqH#|;&cHR=0}9LT%L-M*V||1@S?TWj4Zxn7kZKKo@;H z;n<#UfsRD!ljw2zFi>oOBq*ksT8(_cejTFWzB^Et)G1$ zzclzG4E$ClFt*ddEMN59gcDPp!<4cs*zm|1GTlrzIIUkKzirAtkMgbF82f0Wpq((>dq_jOAuF(_-B>Fwa;4 zliJ#XP)p<@u|hv6mCvYf={c8rd*oT z0E2)fz5A{8W6(_z%KhrW`Gz<`xBR$Zqw|n`!w)^Y7pTqvP!Ce0kF1w;JNZV=>oW4$ zE*q_5Asuwm)l6mHR~VzzGLTEy1Pl0%ISYiIwIp6l`I9|AkNJW464~HT>7fg5e`F5d zj>vhW*YbjcMYXhdGhu3ywJndOX_!>wL-`)IKEVckf9G_V6NSS={;Qks|KoA}ij|7cRodyi~Xsbl(#gx?U$SH3bBZ~)+J zWr?ZkNC2c5hktX}JoMMoCoe!iRo1+(N@-yhNYg=ZgsJ@-;M#%PH{PSKM{ORAt3S^p z1v>-#QSKLH0oOWqArPcg|JhOH$tqCiz5MP7^n65j9tyE_B$)4mru#WUPGW_=(tnTA z8f7@ZdL8|3r{lYK2$1#A-Yaup9$aGo?-X2da=uyzokUc8u1F*j%KrW&j_6gDUoA23 zhl8v&fC!NhpA}0so=2Z&b&d}nZMa5y-lELFE@_41x?lf&)d+0sUO3NC`DE2f#8}#Q zsY%xHo$ErQ%qCWC@`aOoTmz0(kX-;!SUjJ0I$Mw+a!wUBLrP=GR?8}I@uiCnr_$=SQ>sNnzD`ORZ z8Y@sYcLsVk25=rmmOKIl-dY+3jc)2PuISKlSqky{S- zirdMb^wbq&aKayuo|L&R7#ML2{K`z}-3kRXT{_$qa(_(?AKr7b;E;)ig3^sTHSt5H&*HG$r+eFHf`RlmhisoG!Sw-f4RDd zu;vX37n2KcF~%-MEBTMvmW) zCTz=RfXN;hSO^<4P5gXsK9~v4N~9i16I^{3@jeuw)2B@nrW+L@dA;`9_Hiuc{TnYY z^>bK$-26fO0ZFe8T;>a%WIJYA+K>GK3BId@gEzu*`0xM+!GZ6n6wDBrAwJ4>jq?CN zfMAndj-)rEN8*V|KJ*J-O%UGc&&R z#Wx@PyO0jRLMG5PtMy zNBDpeC&GUO%ux7xpTBkdq@!C!h+=ZkN~Y=rTV|<7=|^=vYsK1jcC|)R35Seb) zAE=g#3h#yRoN;7+p@H>w4hX!CFjEy=-t6=oC68TF^0L2*4{&l@doQdataL>IPm@FU zZ3xjEaxWk@GgGpCoL0zuN*Pd#<>K)L)%O)UZ7nbJWQ0n?hlg?_w2dnoL=SD z{`YE3m@>A9fgyQyRQ~2&RcN(N3o4!kR}7zwVwo>@l`hv=Vsck3r}Do$jmUPrqv53b zB8%!=d9DMJm!^fijA%goc31oD zzG~!sSbkDBM;k{v^uczMb4!!h8)aHv9w{yk)QRULL!5ie^(*q?&(Kp}FVY5kp?&H! z9lT@~!IeyqC;?9Flw#s*X;5@P!aThn)9|&1HGBIPrHS|VXP9B;r>fH+u25i`a>3~Z zrSDEo>##&?lrXdHeCqG?2wMYNLt(W1(-YC<_YIDhBv#1+G3NrWq!z@w$gEH#sOO?V z{1ilIXSm*d#5as5w@gjSfH5iK9CAGW?X+m=DDH5I{1fG(Kls7kjazUr5dFnSm#ZD+ zmZJw{V@O*&=pTav^aIfU@$KEj!`3v;yF1OZgXdtLn=D7mPZPfnaij43Ge$*59@aE` zGu1}+$X|dE%Miiie>_153!=*uniW;G(5OU* z$L;H&=jqZ-BW#HGhHRa!sP+*0dZX!je&+0|=L{>?2FIHg@>N<*w|%R=%6xB7I_NGI z5LGLL8#b#uE5EAeg$~!CUYbx-V^VC@W(sx*!5Gjkk|*p8M}9t+Cjc*t$iuaH=%K~= zteopMv+e&a2_H~10u_n}rz{_v5id_(4#cIyQ%D@Gw3H;k|zcRA<-=7N*ysm zFuZt(5epB1ecc#e{R)_V8{waFhg4h57-yVSP|(y-+vQi%CKc)$kvi+G#NR>sN^&xX zD@mMy*#~ehqe*D)s zRr8@)+TiV?OD_&JC3si9O6qgVm;Ps-0ahy$byZOXHfG)4Zt+0+tZ-d4H zLk6#Lnj%c+y{W`bQu+ECsj$sVIJUp3A0?<^sVXsp{e0NhfQV!kAjrJpLET;ZE)(Zw`hCK2MV6k|nIGEnZRxN75}McUL_egbD`h1G zE(CLyKooWG?MP;ah9fk-#hs@fukZJ&<3vQy`DkF-aFtEHfBfT}?vncxx+e^e-j+Ua zWNYD|QWA<|45$HnD@9VHd6odU)7?k=N=f-ZtZUnB2rcYZ)w>As0g?Y4_jAbGW~6Ib zYiNq**yVhI9)dG{wm|W+UAoWgGr_IcUpIm84_d(PgN%2WMQWFF)hNZpbBNZ=#|6Yw zSx>Gp`mRD;32(I!QHO-_1&L?wCwHn@%)QX681KUHcU3(LawsX8Dd?<94-~Bajh@yki zRjA8m8EfY9G|bAwG)Bam=i9E2$0hzHI@EC&N` z{iA_`^?$>=V4(?)ITBwv1%e03Nab4@vFx^njArtM_?|8FAQ>PM;dvW*{Dtx_u(d6(p`Knx+|^MLQT z-hBZq)|nhlAl(1MGo$3!+U+En+SB8FOqyLdohA{XH$qF&Pw4!CJ zGJ_Gx>+Zj1*i2N}d}=!#6Ef4R`$ieFAvGVOWc;O8UKnuH&KSerezz>&(#EWFm;J z_bV`8#<{8z;K6Zm(KwAmw~%Vg)-ze&ZYy4@WA$Ol#9v9{D)8+im*e`O@8d1KxV%E& zg5OR#XTV*Z=%4^F{EKkf7DZtsBm@|m9ARL`Z=P1^oJCRaMbU+EF6z64s}4#==|EXd zQ;fsh6%~|i41?e32utuAWo&$C;H-dSHLe|1VZ3~9KFNO6(%_Zu5INXTmEj$w43qY){pd1l(6X?v$(j8!Xm!_?F#^EkH&1NwvNbuM? zOa|7@)?PAai-(`eGdL4xrsOKz7ch}IOsU!RTcIKVJ;)<1Kj97zujfvXdnJC=ESBeI z!!()I@|vntB0ee|4DZ9OloCVLz2rqYS@&N28MzlXRkWvoV0EjI$}X-d?Hx_Qj4aZ% zdDW~5y7=Z5*7%&Tk;?S#C-JwB&Pro*j&fDl+iljo2Y+mvW9frwgg%}l7?An(TZ~({f-=-C-w|Q zbHKfy99#v$1fc5Y6~-;}tgk^3;H3R9{#C3Uh3qi4>bpe__OG=sLmiwk>zCOOy@E!= z&DbGlF&y`w6OlQoe+duZOR+4}ef_hTyk0Xz&ax*G$d~iBRq02R3HBe~lMo)nfdc2X zZxb!t>`}laJaul-;`l3#M`|^zg~%NzUhq=yw^}-U3+M2sfHIG<3TCq{hyifI247@2~+nXYxu(N7fJaZ&G`|h zQ=ja06*-`W{^DKwoazSG3B* z0?)rX4C-3Jci5bHdW;tH(R#s98s-ai^Zaf>{5p%hF@&j^i^4xt26b=n;CTX?D~j{R z)2WKzR(84ySLCAW0yNE0iR|82jPq=d#2%vYVWVRR}B@x+B;Xp?`Dp z?Bg8X!s0j&)rb8S$hUE-yu47#i|rE zv*r=VdXM^jj1(V|zn(G5wTE~rheXr}IJJv5M~?sNZ*^B{z~gicE(N8NUwJ97-gNeZ=#P60WN;rD)d}9*wG% z!l+J26r$;Z7pTeT43IX8Bs30@he*Zan70=j&tT5USmZnCw5+}^My|sz`5+sViU~$c z!C}2T4WCheKq!b5(1@M|>s)p&xkE76eVbG^T{Z#id%SF*KEE_JIf8Oml!V7lda#@L zF#tiBvM>Pc^267g?X{}Pw%b*GKxVu#V4cZGb$*w!>$xC#V`-Q7%Ahf>Zdb2mVT4nb zj@rfZbB8Ujk-a~(|IxdB0GV(?{t;Jt^Uj&{yD+_40&9wv%pStXxUkWbBMU6ZaD{cS z-?l^;c>ukd&6pA{I8=l>#iDgjm{;EMG~cM}Zq{!CgxzGkj`U*-x7P#<66lE^<^pT|RtZb@6h8IhLEQ$+2Mh;uI7kc7A;P}^ zzcMc2g06n3)M0Mi2>B<)1uXIvE(GH^^!I`HotnO2n zFX@DUl*}*OplBRLW>rltmEHTjlJ|9x=kzu{G}Y*XulM%1G18qdC+LTdAGK50O{f|q zo?OfxyIoHKp2=hJke1f~HPKi638c&cEfudA|IMZVz6!Y;*0ksX3R-V(NDK(Y@1kn}9hw1YCnWKJIsx~PgKKtD4L1}qwzqGW}y>^G>C^Z%{Me(4`8}!u4WDFG(@l5&>>{! z=mJ&SioorXs!#TWqA=d;AzrlV!cX5Bha22|o_4hxKxcng+J-efqlGzVU5_W#j&_N+ z#032nny!zQ#?P0lV-^z2GN!wXFa`VJij^!~p?5%rMu&Kv?liMSnW$|%J&w|YJ40h6 zepFHd^2NzAUI$H2I3>Rd(hn`r?JDvB(nN8=4b{&6essvnyer;?dbd;16C`;t>Xguh z3f_2W5rp+%Y8)Wd&wc}>`qz0^9d_|o-Z3%*@}Nc9eneerDxB~Uf+s~ux&q;2&KWyL zS*NPBj0%XVk1(RL#GC+HV1NK?L^8pSnH8%s+Zzk)OQJT9aS#28czCf<`ucbs$6pkV zh!A!Qc$0aScfhj$JKf^qR0=Nvu6qwj2LAvODFNyhP}d_x^5+??W&ueQEkx#&<|m)k zZG5)7oj0o-h&ObI+0GO2pG}$@zwYn0@xO~oy*By2l8K6L?xQQQV7=6r(j5FFJTp;( z9-)58BauS8^M;$$L(T`ZnvvcZLeXQ;1 z(eK1Zz90ae3KCeB9n=VltrBcmW(z8r;Hz`*4#S8}LAw3s@(^Jvnlc=q1%e=4;`6{P z0Uk(FGgYLk{yi!Z-SER2K8q>f8w8m&vmvUW?J6yR7kj#Fs{?N9I1m-JpjVW`3p{Fv zha+8&$hl;*45eUKAv+OgNb=kyU`n>FO04n!KhDbp2ZC(^^@K-8$rdKmr&!w_1r>?b z{t|TXCS`+yF1)(#R>VJgJ-oS%mkg!qN1a~nev$y!o^n_6iH-6yi&pqvVhxK{?C4F81&JTQl60y6xiLF?4!1NVvCD@kl}Y6yjSvqb2x`vvNtZk<%)yK zh!F@h!?~F_7aiq0A}=Gn*e_4HHP57BY7@i1<54SpvJO{yUt^?83o?T}a6e(p2j1+= zA+mQz%)M(u#qPa`21g$(0$$$|K@1blfNs=J=TQcC*J8DHn9S^YLX6jjo97rBO3Yen zGe%HXoUhXbpPwHTz_T4h{Q~DtUECk)|V+K>ai{#D}A9W50}NRS6fD zY!)f;T>cuq`&23ccJHzQ10PmrAlItPEw`E)y}CLZ&8-I_pSi3ET$!0nG%r6rEK3MA zuZ{cAm9jG4D49qELaAjhzKv%1G{8O7T`{_$)=1;*4}kYmko~il{e#md28~F=L8~=c zPH-u1Q%H&A*~}>&?hM5WLwFQ2;BioU-=O`Aa#RcWMg_%+`tt1{Ng5Q``Ugl=Wztu- zzkdQCxM>EC4}gtlPD5&wkR6I)qd+qGnYxmW_44$T$1dh)WR>TZ9$5f=V3zSf)PASF z5WuJ%Z6~%I*@})=0Vta{GHtA{z*%x2$=~%{ocT7xQlyKjBEVUmzs;1rx9R;x7lH2W z+KK#cKcyV|Vwm%skIGrIp})sLw8M`_ieet%@DR4(;^98-`ik@-$Ln`p(>g zIm>oYzkFOP28c|IoATR90;ae2j?t>n6UM$50b`NW>G5Y+Ojp4>L3jQhnH0I8zAi%F z9~!QNruWDD&$HYv-?`<=c`UDtS1qpOq<&U8YR2EfPe&&59=|!OCwE0>qJ;%CiX)sI zY4&CR>>xd+Rq%vGw@hWk@cpm&9>bYg3Vx#@4g?z6EKxt%KkuLTLK#--|yhAcL-7HZ{`+cm@z*f1)Nu(``**Z5-KwE9oh>36u}GvOxL5?7EUiqZ3QWzNcAx zDx)`DKIeIgycJ__(IH4=gy_79;?GxFs3}gZ$m+H;g4nw6t&OnZwRRM-3rd!u!8B0N zLgo$=a&POkK-H^*=bzTmf#fHMYxdu?Z4aOuSemZ@N{Xx}P|HMZF^Z}qRfho77q&!j~|6P6g@)(l;{c+5l>{sQ|17V2&C7@NA0m!iWhPFbx z3^F76^&h^oLx=4G+hs(lhbw%2(BJu#{`30A|1rD55eRFN>^qN2#yQgolNO= zPkaA=p59L^pBO>4*%=mH;V|kZ5B4m6!$~ zvH#4=8o+k=UQH*k>W(AMzwdnY_t^xp|CTPn7Fg#+6{#v{zSRRD`>~>)qyBwi37{DN zsR2E{Q1OU8)iWm^R;^nD#8%)fTz?;bf&E`%${BD0MWWK}?usX%TgAPpa!7ld?kuN! zl>0s?V>3ke@1jfqkq=n?iGRjI`BwvCJaEi+0#$1_hQ1c+%XEh<4&XBHS{C=4%q!(i zf(&N-B*xr1#{8;kZh{(u_(E$&zX0C>15`xmpHcpgsjeqW>&^Q~P94*#-+@uQBqn zRYePhU{_-J30ZWgy@YZvKjTrs<2S*tpnwV${#9M)VONkVkr4KpaYPF-(1@dJ^!5R5b1-E78GX%!A$Zh0>S?){! z!dy>Q7m(scG()Ev7iS@-i+9iKH0hK{HvTIiK+@*)b$_DWadMp49*K%52s1rHKSWfQ zb2}A3fUmZvIonFq73B0wrQ|U{-$o*jnDn5)0oe+HqqACDEzM*SltcK)6XO3g#aQPtn zo{8JQp`66{uUvC~W^NlvyE)JbFEjQyeL>IJ;M#z^VS;%O_<0~f=&z5Op0#&syz_Q* z1^p(f|Ci`ATIYLt!#KZ`ec#vuRw@*4X@UnBM)l%G(Ffq4@k{o>6mZuoKlN3KP4AAx zbs@$fJE^oPW2J3@%z^kHUKy`9AfgG3kuTm6^;ED$&pAIUyH@JJ2a*T}9CMq_teRh5 zxz}8%kPUUv=Qb)${vS<~f(hH63E&aN9!2yI*kjEffkJ?rpMqO}+?lVeTLt4BDT{(g z<|{9dHU`8Qj@U&BJHw5xiIwLH1Jmd-EBjXfGS-&y;E%PzfjC3|QMdOV#zkK+R-Iiz zIsE5CO8$j_i4!3rg*rMom%D&Qh|lC(DPo0YGk z^2W)L_m)%H=-Y%meHIj{x$ZCa`DdgnsE;$O`VGyc&Uc9q%w{36J8B?pD!AMT;{=^t zPKTTVD`R1*3c=Jq7u+#OXafG^LxX>6ksLWi83mjiUP0sW*MrLS*=+A`suw&~SU)7y1kIls_?MR7In|WGmAJfqq^@$pl znYzLToBCqBN#)=v2W?7IUAG6lxji+}?UX9Oe1*ke&8MuXE6;Lw-{xMwjfOI9Fu~k$ z?{&{&Egy;mpGxuM{uax%V;O4?*}i(eef42`QT~h)a-E@2uXal|cF$o<1to%fx(|xG zr{=m02&w5iB|M?K0IzMJ0~kwsQ&NBt=KKjby&_c53kmtPz1rw=J`Hk;7dViKuJ$bg3v}0ewWdi#P8C7F6~`64eoj$Coa44c46Ls^O>mL^h*6O?@MsMO-lz zD=c2xli&1L7De1aC+qsJR+~eoqL%Lie^NdZ)!ADmnza{uIXDo&$<*me?PP}Mn$m)_ zcQIy|tgp&7PG8$B$3szmKqgMXf2Q>D6Jrx#YFSVPZxE3-?z;l9Dtqru9l8X9AGDia zD^*`yPuE6nFDjo=(O;{A@2oxqDav$Wj;}P#+uMJxrWrE~|KfmIgI)vJ=jqJ}Jr}_fOxf zXPUNB?>Jf;CU@nj92q$GzkoLUZkh8=Lo1!hZmFEA{#vLFMI|TXm#o!jb*!|xX(_*P z&Y=LJTm*gJhX}^-K}M#~W3D?Y_*XdE&1n%HrBi|s!P>Vszn+wU*%?|S3ZF*$%b(r9 zJQD`{^@ZR6>pi3?C@+5t?ADH^Nh=1qA;H!G56loj|gPJx2yE z(v7?H1k<)kWHHBtHSjZQUE8;0sC3^Yfb`Yz!GoLh(jM{HW7^=I29>m_WvrzjxmeUXg+*iM)=F}_q z^u;1Zjt-8w=~M`EK^FpX+>p$(cQRYdxps78^`Sz+hsFJZwMR%Lm^K2g2^ASbR?8|u+`;*i3utGK zt@{)SwYNCOwD7FtNN#RLZws8OpQpys^3TGR+}x?(`^j?q#G-iTgu9S@l@`OeBG9(JtMFvGU%xeFXQN`)DSofN8<6fbQtjB%H| zal^`lUi(KuqRoWnl{bpI#dZ*IuOfL{d3$>LU`Xf3k<*-1GXm5dK5t)_#paHZjRYAD@8IFD!E%|xfcStM>Jzw3T#i? z6|jsL^Tm72IJrn<&se!PAo)pAv`I`iVmX(_C2$9NDkuyp+dfcb2zb1Z@=P2+7H6)& zk>x5ojsjQuug#Q5d+N`)Tp57i1lHz`tFA1vQ!_tx?dwV*>vvqGWEWO>R0%PC#34-I zUxe`pDhk})ud;;Ho?8l%^YN0)z&II4e;HT?aS6eSFdh9&8I}?c@%+6^qK5Wf=q?Xl z7;8PXSI2*2LiR?T$kC9>-h{v=fuMbLZ(OEQS51+K(3bf*YD7vY&03Iw-jA;LyGdD* zH%`eE@U3SE_Cm&ot3m8}Syi5+Y@N{28wQ5ctUt ze9OHf?*EpHoY`YW!$qRfzxH9NzQqMpFA5tM(VE|UVAK@<_?&|b;1X*4Fy#RoKuJVi zjL%T+7bE#Pjw&w_rlu{Tpb`$;H*FS$fgy}G18B!DFn0zFg5A!I@*^1DMe=;t`xBW% zwG5Ah~vUuU7B>+I=XKc4uM)@`=};W-yDM2oCrV z<~&iDgA^{y=U;gEhAv;2NJTI4#@aKsuhO=!;EaTh>!K??FO0a32a?VJhC!NuQ72Q7|Z*ryBxvu!4g1Ab?xM!*gu;1|mcn_k< zNO<;|93Qned~{Tx*fPZU?By7MeBbQCUQ{461Q2j?GVrzJ4=P$PV~@@T@(bz+!H6+h zSZM8K)fHiQm@i-n#jz%|5k~YNQ&4fV5q*Rn6Ub1F;7=tJP}_!w%TBIFI$2uooPepA zsTSz%^$q9iV#p}2P24BHbRFffx23J#TTVp_=~Mm2@FPwPo6~wfuN^8~Uka)X$6c;2 zCXk} zBSA)JuK$qy0Rwjc4`ljUlR*NmlTHs=W$%w&K>Edrk;?wh0Q=J5Rk+EUOpu)gN=2LC z8aMc02US8RE(u8jA)G1=+jjC%a#|lr8S1dGUS$BegP!${rb(HaU@|c5@4jPihaqio z%abW@rZep))6JGXnk}VSk0rf%u2PR$$7tB_%O_ljk7vVN}q`C*wdY2;#G3%H`UNE`0NWmpB7i#aQ+QJXL=eDB)f=NO!c9ccz zw@J!xEhT>kon-emu+7{lD>pPS&v4RL zWv5}+XiN1Vmy`x)Wc$nOZxIedv~-jh2Q$e^!_+)i)h+Jav~SJ&KEvJ!rOGU~hHZ<; zoMq4uNB%LT%@+Wba5U?=ai+yF64WR`)fF(__ilneYRbI`Jw|!uER^F}d^A;O4)k4V zacURZx)9Y@V3hNinURFPo0YWnFr*JbJM{$hafg9zLWadVYU|bKoK8JZkzZ?Me{tf> zZB8~Nr>OcXK{q%Rhq`LK46|m+{oU8DluIx!Q@7o7{^A1c(;e9QN9pa4%i7e6wjuPm zO0_x!P`e(4cu~-8+!}1^;JMDhfR4j}jwGl(2yE*E^3Xm*xX9Cz(jedXh2d`y=RDwG zF*-mR#8?=XnTF^8r{GPa0E_f@X6fXKJ`Mt_fSHet>$a(Vw(56k?ZHF!z)wnPwqynN zR9yOK%&YhB_~;?9YZL9gc;9am1Ca7VmuIsy6=1St=}XhG5I!sFJEtKmIr_UunRzVc zFlUjmfcM)T1y3Wr@j|3}%;@X&cr)U*@FFyzN!B!BaXKJGdPU#NxH-It#&E-jgfaz6 z6Pz4&!v4Ky5#kA^8$i#(Q~X&o9VfJJ2+x`OCsF&Jg~e46lwO*<+Iq-;*0MeIKu3NJ z&-Ig}nx5O!pC0&wJw-Z-DlZnMmIuZl)yS!yuj(km?^8E3+m>t8N*$G~#B-nGl#Hgb zE~S7@!w;w45aG)B#_FIL;_5!)*CtFqO~}^ig$4-Q6T~M3t64)s`4MaTMT)IW z=?CS3$V;s2gs&krg3u%=lMBd;E2o@6C?}o@I(yX5b~l0-(g0g{3No)>8?AN)krwB; zL6zCmCZ-3z-C?A=ybsEO2SOnf+uyfsVzqXHhHcaN1?PldWEpXq2`zJF*WT9~E(x7Z zfOwzyaa(vL^R|SV5>d2-IlH-lNQHAs$8SfgDjDTj9rpTkxlrF@gq#{C;^$)wGNCeQ z+J&UsMo_?qP@)e8y3WeSxW|6D8P@3$D$v-_unCcm zKoh_;oHUVYU~ZBV(LJthvrgXILw*tOEZ1L>N;CMto@r_~@bW&68oJ_-7?RqM0Y*e8;8gl*pxj0$= zw!~m9;{xndt*ny6K5WuqVM%^12l_n(Ckr~`){om;Wd_zzK4s&dykf|HzS_}R2c^-L z2QPDUH8s5l-fLs$piFL19n2xS>up<3>eRgZsU4bsm;^gax;*@qQfZlw#?2Dz~^f(zP(a57Y->) z+5N_~OO{uHRcEKmms`(5O>a=IoU1)guf8ix=$1=XQW>9S%Sthtc#ufxrjdp!}ML)c>N1aeUQyAj_p2<{r(@j?bGtT{G2Sr7%QBd zr!ZgbnSiRTb7DHnpSBUmBpE|C7UuOmT5^j@~uE9ZYbbLSLbbmF@)qAsQDmsT~sjC z@C}*PZ|RS;xoniryRa%m#_dr^=c~4K5y{<{NM~qlExl1lOU(!bbe*HC4;%Z}#Z@?v z8L>oo%6Ofnyhd9mR~2Qs8lqp=ebyA1vhd&6aB+>!j+tg@3f?1{Kn+2g+S5R>;aBK> z58o;PfV=>`jc=M%IaA>Q z7*ay$N3ggomH}Q3ZV*_5AHKQ;wr$FiV=T8U30+8I&MR$W2tBmmdmf_otW)bEWE8Ww zbVqZ7FLe^PwCvMQMU-OILhs@iS_R(bA1yH_6(`*#%Txnro%{aX3!pJAqmm^^vvF39 zyes=bOIqsFOjQYb?nAS3D)RcT#o?okiPj7va566~z@?x_0TqE&TWAS3jc3Qaj ztrqpPF0rDv^74?bPn|8R{%TGOiLxnm-dygX&!w%ves<|tx_C=#=Fe`NVyEyzG7M~W z<2TWV<7cRLTDr*Smdlgi*%#V1PFm*~ZdE1m!yTIS&w_Wgwa2r~LyD)ZLxkPnUq&Ds zyRaP5`qZBZZt*c*jX#^`y;Ic=$ejDJqYbh? z%=UTsh0|FG(d{h6d17k0tf0$PG_7UoejYSe4168k@1q{*;dKeA^_T9aqkrEF#VFiEbRz8TpZ{~E=K}B&G-0e6KTKb!s*KP(vJ6sHfP3VQ)iBo za@qoxri;K0D-ruurQR)nYOl*42e3<2tnFKmKj}YVs(y~FrXEmWyTVfHV0X;#)NdUy}QN}=SUM86(-t>f_@*c&WVffp(m1(wvvvcgQ5Xt!IFDtpCf;YC2d^l zS;`!_vF+wFQSTR4enJH$&brn~rLyC$Uj70z`?_kx19zwv(gG|_?t9d^;7bS?9x+V4 z@H@0K>Ad1+6-ET_98CsG6CKOhAW>^q0*~gx5)-y>BkQrTRDLMuTm!>+p{Q-D{IB@f z(#YsD4EC*a42-(A;6Kb%GhNy!4%;vB;dAE&D9gl2>4WWj`mP|u&mGyIoQAN`a0+m$9Bs8)Q)++sS7)7d5BwD&pdXTjx+anNZi?1MP8Xe39GufYJ6GYXpbKVg#*j(ns zSq8q~MV=Uy5L5di({nxgln+@ZyE#kU>_nPKOU&3#-!I)VFOBri7*5VRK@zQh!=lifrDnrQNQETkq)b& z0QU0b>km10y}4{h+|{OEVB2X+wv1}&ZUku&UeQsofm(MT0v@lZ8gX!Hdm1%r8S`2Y z8yUX>o`eo{ex(#IxqTifjkckXpB=fawF-$strYC3yYvN{ZSf6)JNC+1I05(d9|UX( z`mg4J2lwxDUVR8Zze4``lT-2u_Qg*Wz%YvE))dc~sfvU3u$7PUW{Uxfut6wwgVTs(k6nGPo#MNLhdLQU1q!=Bn6N1YX3r7=x(Vfl<*Q!iy{u>(WC6*i}h zRbko~L!T^nQkbLBWu({7D#Vc@e{Kie9hRN4ek$hb*MeqykA_l|C zh*NzW6jo?l2|-I4kcBy9#8v(Mvj03;siN>j+~jf8r$AI9g1>Z>70!_(-_QklxkK3; z)HL0hV8F;UIc$LC7(@3muLGuHYq_maC{OAHZ|hOUiGh_7%?t$0QppPk#SD~O1cG=^rP8mvVu^)Xr-wNk0ox8n&VkUEX>GX_4>ItDq z{QXntA(y4VZ$PWM)?gHM$J!3tqp0;PfHT?y*FCP50i~_pU!`z})3?!%GX!2t_g4+c z>)fC%wr5?a;*Z+k!u(gCc`tqrAYhx(Q^CIsK_)gKZ-T#}@_Ew`Aax9mqFxcgO)_8F zg`kpTs|!Q^4_{va6=k=!{VDE!U&VHEZVCd*6B8*S_zR2YBx&OdNpD9laH}T!N4<@@^6d z^4&S$DrZW|X1=X)>s0Dz!r70PH4 zj0#jbKS%KDR4kE4Fn1$mm~{_YM;}%kC_KJhWIOOF2ziDGe9|XxqOYS&w{(i_Koy`< zktw1~OmyIhZfQFl^p5|jxxlqI!MgCPW#n$OV#@Y~>Wd=%rq!$Tp{?|{f{2GbWZ5T4 zhHfBjG-?dkH2D#Zxx}V6J=^YOs!71Dyb4|x2^maaN%G|PGodmv#K8w+M^Mk+7w~8o z!UjzV#1dyN$q=mA9?TJ^z_dDoF+&YY6Uvgu&w8I`Z$S;SP2>1fL4F1vou!>%!kL06 za(r9$gP(xU$o3(nV|m~sPtY}xyT{9G{5%9tk{y80B0dF2+JzUso25O8`hE(Q#G8Q& z_&I=rS0O4Dw6=y^-=4UGc)fQL-9d8#)UY7fv{i0!W%vrj*Cr34u`EUQPSXNZEy%9^7|mGRsoXkAVF*( z3aK=gqK3i$v4rN(ecTavp(a!agBmFlK#lZ?2(HX1!&NI%g{D!%%3;%XrNNa(AZny+ zlL%0efvGQ0!$|6aBljp)C$MncL8dxsKnaDv`k2tae&cFpywj#oc3vf;C6D$v(Z^P? zBG^8A6^tFtUmHyb4Br6wvzmLP$&eG5XeaHTT)%L$g>LnrxtODuNBvDo<8GptQu5!T zjoMxPaN`kL`fp!VeJxH!5t|%|d+R|x>012jbW|&~@^H(Go{JIJzPg*exhQc|e&3?~ z)QllS`yF9B^Q*O$6it5iRj0SfK&bU&&k81hphOO8MB_f3rOTMuBlb#*oF)_z1EWo0 zY4Sj1nTWa&N>b06v5J^_NEz<=_<|#Ap4w* zL^KKivED#cBFpL*EijYek*(r)oVkg%4wtmqOnH1rg}lWyeEP>3_-Gq}A&l5-az?tu z%WqapVg>I(#>?Sn;42^~!NZ3D9xaP-`w(np9WX0|QWQpg#DQ`6F5#XC>fT|0u{Kuii^ z({3uVEr z8LkQ-cJA{5E1MADY>x!7!X5CfN&-`*xpTH4HoL=tG!+~gpi@CxxatN+5 zxb7E31OvY0@)iLYH$1M5FyIWWvjiCSyu3#-KQ`qK3~bH8;OCVaVa3ESJ$zJWKg8y3 zrA0)&g`Cn8q`WPxJBQ3{_7isk6)V1`@|?vmOSckwQlmc*fR4}8kSnX}_X*b(6`NS- zK_ASqSQME17m8bl7s^nSV!$-o>0SwNnJDL1NNk5o2#P+n<#cbvx796Vb53%%&lYe0A3D{{GTd_Qt1~U=2Qd$_JlLYJRHEtn`fL8seu790a~mhAA=P) zyhfxG-~z906~kS$m`uv>sFGtM^9Ze8!&-r(V**fEqfW-6_)@dWA=CMQ+GZ2Rc??O(Jaj21pLlB--$m$?DZ!g@!VzN*a z9~HUu<0nDz3Ph#)HJvcxR$Wk85^!{_*bpOc^%|z$gMWx`@D_wJ-p?Ko6ye`cZ)zAL z6VDQ)MUgeU7n>;0cP9N*TJ~x(e;hwYcf+l7-svUv>M_{CJY2q;5($$qZjmrf)pTrW z6qsmIu9b`}1DZ%9IL6Ak$Mg~}7ukt9g;b$I>XD;pK#8GPYXxriG+k8R!P{7_%i(=f zW*uMQFBS{)RCREXKfM&6MtxPys!q4-;qS1Rd6I{a{sW!lt;QPq@g_zWce&lFUa6h! zX;a*yeJn>8j8!v%wOiNab?{SWf^7y*A!Pb*8Miv7m5ha=`&fEWCg~;GyT-Ev^OW24 z_eVb1!<(ljduu-}VbgI}H^ZQ;c$*8nk!xPg%{TK_44b~umvE1$2VdR&Sb^>r|6=C@ zq(Feo_fIM)z!3YC2$xc=@UI%}M++~a;VZDSmHzeAXIJ`+lEY@feSdVj1pHu|Er0ai&^%W+kdMxmR@pR<3T} z_~f775T}B+3_IIORkxmHVqm38bt!4e_~k&ji}$PFNAnjf$BteDuMb&Ra%^N_Y*x!^ zYv#V^s_w|Cu02AY;L4(Nb%~$5C_+KrRitI_6&al`6@e~a=eGy2c&QWbSK}MZLW_fO z=Ko=ZK*J9Klmn>9<7+MxOJ5`JaZH2_0hG!7;+6b)bLFa*Lw{~RP&U0b$>WKUl^mFh zX65xTNS5=g$|Kdp?uo?OGvrQkL80T#6^FUE_%quo4xk0Tr7q;wisV<1TqCaeC#F)@ z)apMuJ4;*HVVcKa4sQ=@6Bav}Pl1^0h1vVCB#mQ{kYH#|F_u61QBnFyH!Aw_dxEKS zyy~;C?b%lJDlC9R$>vDIXujhXh7-T3BkS~%sYw*#(Z<-+{>m_)#EEggEWPU*Dr=-_wtHMsD85Z3dCdNHVHQ?Sc;d4UeS_ zGYJ3v(Eo1_lz&MAAv?elfFH%|RQYc9FF<-0s2!}#hI_XBn9LtFB_sJv1oG_|oK%9vB6Gw6Q;#4kieDjmea zjsCk>*?mE~#H$~099sRYY$I3w3biK2y`$D>mTHAYo#ktG<{rqi2dBD=Y|Y--&{XUA z9v3IBWv`wSI{GZUi+^Y{+)_OG5M&~;g5@x=`MMWEB*l&w>?F+^lD;33t{&mr$z7A`_#-a2mH|w&TifU<=c}RsgvDj zn2~2*3az{K^xV6bp__N9V0P*%#Tn5G@pypz`>)OU2VeHTB@6WkARwJOd~M*^anqhO zU!ETVDyg`yM7Vdy`=+}B=-BGSUA-p&;fMIBN^v2+JEYr zJwWmYY7zfKm?A#lWfjMF>x6k$AKBGy_~=oZ5PCUibtWZ2=k9d_(j|L$`on?jLTBG3V8itNktrx{g50e5UCuAj6u@G@dDR}W1<)gjC;{q7r zN`D9WVqIqs0cb@q8B26GK(-RxiGX6gZ-{#lJpjJ^-Xj>|U}naONG! zFT55j7lGp{T~l6Vibsj>rgbJoKRANMh}W)ja(?sAnR~REgM4}B&ijK_dII9M;L@~! z3nA?KUyJ*PrnqUZgN3-AkQ80vyq9k%lsV**QQkvd)R?pxC|1?xAa zChsZHCRGBg)W=tkzV?wD4Uiip)X{4V3nHGUr%QmEpTnL@*UJuG{!S@Y(fdg|#nSEk z$Bgs|6lZekLABHLpz+L7RZ!Vlpj7O-#s6Kn^!s4@0~Lu zZ)w&t#}masWg3C4|FVpTYEWGsm>!NusLMzeI9d{sJ+pr>SM+_(aX-4X`8(Z2+ai)BQK>&~; zXcL!KPplA^j;#C5R;px87RxlSAIpShILGd!f;RZ+*!%GWueG+r1Ia|yPSvNHh+CSVylOoXzcm@_$VNunVzPqsL-Sm8bt=D zc1}mqiP3n zQ;RvNcg;sI*L^S%uC+V4yQOiazY%nzq$N_mEzt{J= z?AP(k4Mbl%n4e&U;=&f*&GSM44i+_XgHKQ%ahe^1yU1()bN~KmmxlV{eE;rf=oQV) zP}=>)xvt{<-Hpg&Uq&nxLAdkhK%6N{`v*7)OZQ%R#7C zFII;O+lFJ@QnGN&$sh=2ZvHyWlk;LemBO(6&v}a(89Vx$8mE$hk@;@ida!PTAeXeH zGvY>V{CM;~JPyFIU5=vvoMe$I_Q$au_Lm{j(Npsfy>v@&clP<{98qD~^fNkk=drRK z>!JKjPjPl~9_DBNJr=xc|m~SyWZbdGw!R-#?1n1Qb&Q zNbvRgi<-A?l_SS+mJm>@K#tw<&)wDBIYX@=1V_Jf$7w_6C&0rFJ=R@FH5ehamUKY6 zIT8tW=liSNAwt1s(_I_)H@v-Jj3x??u`UfZ_cbh+byRd14nl10QmeOTY(c~)?LT~M$?kwPq!SCX=^e}5)y z6yPd+!2V6-v5$%O4~+(gLWRUwkORvyGCwYjW)QuQmSpV|8Y6t+N>LAK#}>g%x-OXl7^sG0 zjJnttH8SxK0_gZYv55kh_`nT)&uIgDmJ~%?GYTMN#r}oK%BjO`EjK37#t{|H@%8Tc z37X{@&Z;L@(HHo(eSI3UO9Vm8Qb*#QSS3~@>Y;V9E^kXIk(SyD(K{01CIM#G`yM_o z?5po{3dxr(ftBtzo0YeiZ?#1cBAfNx_wjvwefrL5kU4~RH=V3;e1+=>*Y>Y*PNYh& z=%R+NzDq+RpxB!1XAiyk$0GKt&ghC`vO>Y_k^}mL?_%IyZlx{j!8?m>JGM4ZhwQl6-$s8Bf7>*e>KLYG&|{^HHOg}lU^JKkJ) zmMR@GfIB=9x3#tBMDGi2`V!O0FrY6`#R3X#wNUU{09*&Z;40U zNv_vURhPFXt=69z=^elBgS?d$eICMNEnV}FPlKkqMzBLC)oh`tH-F@ zdd?8bbJ8~znRUz-J%`xI*6NO(SXpY=KC-T|hx+k5cFI((da(^fqL%?85)X7LXh+eW zFzJ+*6CuKiRC5R!f;pN>zyfh!cO*#eu{(Fa9XiV7DZNymKf$}Y&B(~Zn$!K#>QT`c zz*&KI>Jw`5b(-!7ym+|T7lK(ey+noIB3>pp;elZbNB{w)zuTSLWH*6A@U-8r~c2G7+M6V!+O%|5D<)A}y)lcj%nV9k;< zHN|LCEPI#9={>i8#Hv?8t4wTS^e)dr`>P3T6>P@LLaA)D&lGU?nfs#klGDDrO#dcV zk=bscsdlY;|6Y8{tr(h#KLBtCm{{z&Z^Z_W`6eeeiVHg#wD(Dg!@;I~6TgLIE4VSQY`+tm9 zKsNJL(eMWOoonZ!9|@^qq1HK6?JD?hzxCwZ1=ULT=>UHjD!z0P`!%GH0p}X zj{ulsj8GpAokT0SZ1tC-$UR>3BO7h>pF2hx6S{;F@J}#!D*|@9fEn-Juf%eU3@>&z8^94H_iQgSbcF6S!piuN z*Cuv9W0_H`+h3Fw4mg45s){9NlX8voOF1QpSI@DzRH2ehv^`i;@oVmDsTObN zW@GDWIZxs5ke)w<#WdBT?WBlbr$#>P!lELx`BO`<+ZC2&{(~_8TF9$!?)h=w_xWA1_;)U1w!{gIYP%@l!TKfI0DuRCaH#_N5^@{9W*H)hC+FuIGeKRJ&4E-CA_zw%;PYH_%R@4jkK!-u@z&dv*YML57ik5S3eQ} z6faMUSfwX`s)$~2w}%mp$-&XZriht5Sv_)vl+sUK(Y!p9x`LKPJyP(^Ny+kNX}>NT z*_;-)SotSSk|lwGos%80V8Q99B$X}xfGroW0axY}S_2kJw5hl7Nsd)?-SuzxUyFxJ zPP6<{1wVcr-(-6ZTm+BN?ii?j^I@b=`2dq)+8wfQ@Z@a#GFU(%P$zPpvJV(!u0;5z zw!S?d)7sQ

4t~>$$G?VT`hGy>n&{>X!{=Jk1BOlo+$Ocqnx}2oKYL1E~LVFYKoU z5jV32U)2Cmg|eLz`50ZKCrV#E_+=qZx<0jlI=HTq&w+Coh?%1a>zK5ib2VhgAHQkl zvhf3lR>%KbzpW~jd|g4ryGdNbJ;-8Fc8ERsrSs3d4}b`xR!-~aU+Aq_WY?zbIEnY+ zw+nQ)>Ep^hmN4hS@x1o+ZM$}SM#l+ul^bxqfkXwwA6KUU7@tuhb4p0AAPR^FTaJ_5 zT}63r2Yn-L4$6bg=UFg6^TL!2xa*I=gn{J(0+`seN-X|^D^FOtUM!# z2#!pHU+~5d{s*)3CvL)~h6!pjv96C{$tA$u=(xqiJgikW{X;V^iJ`~jM)Bis*o(rn z9wI8)daCFGpCK%rE)cp3XH}E)r{-Y`yH?vy?&vdwuhE-Spm#b@Yj3>{AzX^_Neo;M z^n_=_jsD{`q^FecPF)xn#meM&R5tqAOCx%R-p^Sb9CA! z@+p=dA+rPJwhQqR+w)j*2r2V2k9N&Q!E<-XN#nPSd5z#tgUQ(Ehz-)Ih|9bZ*RzhgL(c-@Mc0^mj)XV-E zapkGgkL>+hOZNky8O*+ys~^3OkOL_Eje+u$Wj9XUwWb;<<45f5TXy3AAKV{J32W=! zfbi(z8M^gCEzQjaV~viC+aANkk}-0|%8hZ%~4hFVE?c>s9FBXcaQZO{?#(S3ukn6qJ^ z0i+D9BpmspnHV;<0fybws5ajUR(5e7qWvW5#IWqY+B^~=B0(2DTW!k0sD;MM z7bequ?}2!^T|(WU20_BrlBUdokxB4|-b0LCu?!+&0MgN>_)oS8pu6z^RkUQ_CdYjI z#pVKo&wecCAl+JrK=o{QR|syXa@i}T=deV}sWi)}Jb!P`$xs%FK@T8*RUOu-FrWfF zyThg)bVUW4*69BYt0K0EpTvv8_i`^YX6(DXTrjztkyhpkPiEk7v%bcG>8j=NXf!$z zo66xghX<-XcLwQ5;LQ|ia{W&~n**D3vp29eRiEBF?IJ{YkfnSjt6eeQc%W|f{&i>u zqc$wrvHyM}f&6>>mh@bO0_ocYeEP~!YwP}zz`ORA)$6e^(PlHZdyX8sI})zsXO{<8 z#<_eAYbNBl7o+c81%MiT4~w8WV|Gp=fAFwWCMB|#$qq?zbhA!4PYKf%GIV=GMu0`v zW%@tx{eJ_8B7h+tS${4N(G3C#&$xG+y?vn|BHi+XdsGTK>ajKQX~?tg%WUV7FaY~e zF_us+-4wohPs~lP8wRju|g7R>y9MLaZ{MFz`*lIf`*vVVR*Z?_j{n5L^r^Inl zflPgLYG}8Q#kjdUEj>V8SZI_5=;?{nURGw2W1n|kK6VYH(ukoleiz$bSVQo&!}Ud= zy=zMjC58p$z9(a;{5x*`kZ>$Hg4-`Uw3EmUWEJGHx7<)vcYd;27@@coK8wo zAJ{*9(WYc_NtKbJMIaDFuUtYs?LLHg?zfVt_C+&j4zx~9Z-qbleS3D7yT`W2rYR5c zyR2F~F5k12jyInCl;PgCap{gQK&#mEwod0f3i{&yqkF@XI{%PyyKU{q3~`2=*!`So zOzoR;u3Jz>%Odir3kEX@%Hd2L0a1?YQf~)b zZXQRWXT5noHd&A?P=@`;unGa+jvnEL7yf|M;7bLMz6||29tTl*0r!VrjQD9Blyaz1 zEQ6onLH_1}qFVu5$q|SW1#>{X(#FztXo-G?m9vGyH6~N(S$H?gIv*M8cLn(|2W+W5 z=5T8-M2CPXjQqjX*zAtB%|d6>XL!-K;whLz*u@{v*+>$IbM4VRPkOPL>s`v1%#t!= zd|OzL7PdEuO;LR^@B{Lf(aI%sVuvG%uYEJ>2OC@8NSC~Th!+DocC*(CH z>~9{(f+RTUFX!gA>JNxU+Wh@z;IpJ3W+Ag?7IyuGcN`J!j3}KKwfGd4=(gX4XY3wk;2Iek&v2rth&07wBU8 z_4EC*ve$Aeu&;RWyY2m*$r9l%X?JB?UJ5V3TG|0xmTeZKJ5*oXmIneVe1K-E{K1iY za8R@46pidhtAp3>WulZYj2TGFm}g7rQ(@Nu)Z-AK)d1q}9txbn2iK!7w?e*|XWRB! zRQGAjJvH-mFf-2(r9|?ie}31hpwu9#hO=H>?mux9T^lp7PB>s@kk84{s+EHSMsQPl zCM>?6EzPW@)`VIGJa;KeC$1SzC*~Q8C*DnRMK4;+jPh{&{G^K_7lrMDPrbapPEQsO z2=7kZi>}wS`51nzthm}rWM50UtlTC2vselosCpp6^euO*f(Yv`KiWT@2EHuC@LSfp zcNSFzGc%>0#%mL~;Y8XGkzbB)T<9_yZsuvG2mWe({0K7aCw>>jbie7~lRZZK!}8#w zO{l$nhS`v~6Ea~Q-a63E5->=w>HqulQj3L8(9M}k0g=dG!QjsmGb)7`UlJxbHfon2 zQo@d$ql!~_Tr&wjfSv$DdH(m~U<&{ioWoD0jm+IWnUb`b$bOHNmeJYHUGzH&QXvIK zY!~nhMVsqN`iZ2VmLuersO@rp)zDGrm;tjDxqO3st^N;72pMoy*@i$}nLpiRD?GL| zlU!FZqcn4kt`~c-+26w){ZnUVGK&-no4mIPe-cs9MP}g7LG+U#h^;I{Lyfqxl-WvC zw?DKvk(i8RpzM(iE&5>x4~id2p^ymgZe#kD7JcuZR3Unn`5wAS{6p(^+(k zvA27O$GfqWbfAu9njKjZrs(0P-Pl&g7+B?*(g~}_R~MbH!=fwK4n9A}VEU}3N7zca zyPfE&%uV&SsWXvW1*f!&7xe@+z|;>}osVGxk$GUlZn`Z#t3gQzeHQ*mcjK7lFK@oLYUXu`bzEY)XHN*R|R8NAD{o1-(t z`;ZD03%PLE-;>EtcdEsb^5wuo`IT~Q?z7F2y%S+!;2&V^hR`$GDPEYr`mFx-O3`cO z^!?vhynk3hWI^yBvsaQ|Z5iokQ8-fDzUc1%)i!iZ@cUV^p=Sh-;OXS7G==MAm1FcP zCX2le6(~*horde>)gpGOe13t~f?_zzp!R`c03e!nM-JF$n|W(s+r5Bt?} zvV7ywzi>5P#v}<7p6c`XNUKwloP*R>NQY0mXkSIIk$HQV()tWjeL1$YLMpCLF7a(X z8x-rB-cSz`J-b$LjlEhxdKkr~e%jgPuH-Yzo?&O288WF?5(nm`ntI(Ctlfv|4$D3@ z&)^>M622H!Ggqeh2*0rXK&%p=ILJ2hq`Z$QcLmJs7~p!XM8D@-DVk$MaJGRPYQ^67 z_X-Utc?M7L!F#{Tl7!<0sj!q5q?(cy_hg-IjkC3H+Ofq>T?8fEFv`*{+}3W4?7%_FOw;sc@raelLu=w2f6tD->H2zN(Q6JzwYJQ z^|wpe)uJGKf_Lp?>$qZr%vF#>S;l#i-4V9yk zTb%GQEy7^?v|rEIKGbpnd3B1W_M-rc_!^ipko;hO@D;GBA;jTA=$o26*gVtL5r))| z&wIIJDF!V_js5+$3kn7T#l1sdc;S(|YxU4zP8%ev?Qo>6;MTjIO7s>LKi1BDd>Q9A zbjOndnDR; zPsMqn_n<-B&-A)|+*iol{vvMUaufcW2 zZ%YSmtY*b*FUC9fj3kYQu%r~7-HGJ07yP$5XP>_`&XgEg<3)|r^6?m4Wu(JFXQ8c8 zLn)i1TI3J++0Q!Em{^42WO^vT%<2yDvz;~^q<*c>hf8@(9yes2v%oX%xxSr1&ZJtM zGt<%9P9*p6AhtmV79V)WZGMk54x^PON42aFWBg`aC|W1{Ez5oxv!{7sU?eI8cC4z3 znCHcI3_wu^jXKnbV6wLmgn|Fo@B9%{Q1Ah4>NF@K8dYbDhAR)WclBwrG>=k!6Ns5} zW+CUO@}&A%UR=`fBFPkI5^ZW2i7wN})6QJbPjt3lCu$FQEqHXSc@%906iqoaj5(Cd zKVyP8k2-~czGoO9qzp=PL$6U(6N+mW8P6g$fNeF5F30QfdW#_7he=bW$CtuI%?@`v z@Ri@HoKrBe6*_DC;;Gjdfx6!6a1_v7*wxwX)>ZtG597{HSDNXL8=4Ft6}b*TvT*LB zbK|TP6i9<|r>Z3v+3keSla;4g>iiS|9&&)#jKLepp}g%32z?9mOM~!{cP3iGKDPQ5 zA|bbb|C;soCGt(VDA7K3OtVPVUs6!mQ*ufLn}&SaYs5~w?4$F018+v@(K|V4oDAX9 z{}5xd1I;&}4iq8Z3qs+fOl``no22IMxDIWWb|UJdiP0Sit+xiFZrxKY-{aIQQ{9imP`8iL zg!0-QbX5C`T=9myj3wsDZ18WO5opKamBOicfSY?{mnhA^Fz6TFmVt5=4WQd$+U;QK z`Qu{Dog6u!4WwHVluPvMSTax}8?@0=U}(3M{dJ&MwsmZ#oXU{QuLVLZ-mEfT@&>n_ z(V>cRzj-b#E{IE5ZyHAEK4n5D+hbjSB&+vB1MRW>pw4#Kc{=GupDG4Hq zqI;eiYSuN-gyD(u0*GHW1-j9e1WF_I;%Sm}VcY)J64>ZAd-te=JSR#h2Bo!v(xS^m z^W&l{=T5fZOR=neWMv;w`y{?s$GX1tN3}IE^~}fsoes2^zwihxxYiV%?PLkt$n%{J zbWaodJ+Rt8fLs%*rEcE_RhgkH9!H2@mnEDfenKCn0KO=^bV!_!^vC@n5I3U?f+;fa z-ko!-5GCi~2OrqKV^Fb3KfGMMmXW*gw%bc}>PiP8(H?ETY>SZt%5FrChGG4)cI@N* zJ$_t>FPP^<}NbyoL)_@xMKOSsFM*{Si zWsffp-eQxl0Q2z_%TTmxoK^x@j|@w?coO--1nVYL%W+?V_|xK6=T6RITA@v)nfd%u zz>+sc{5?$2<$#rY)|jD(^Hlkp@D}>2fzL5|bfATQO%-9HPZi&YBT02~#u3|iC_)st zu7vMtD)+?s_@?qJ?QBPqe&Ey<7bsGH)jD!n;I}pP+~0bS_uUMq$F)XY6V>_1s+Y7AI$l3%QOFgn>s{0!4QcM`= z`-TE*rF}PY5VMAY9_*V#0$iN7ZKM^E9&J>wkz2>*SATL3-?8kf)AO{;y z4;ovw;m>tYr$bF>IQ2X4D*y3L+7~QRF{I->7{CkvO2mtOac-sgi_EHTQ(*}5D8*6# zLtU1nukh`dpg5Sin|TCFbF7Xy{p!WRmMO zOF^C@ZreI#q8L5wKgcOEKeBz#RYIcFLHuvm1l}-c3fh-6K1h^n?f9Wp2Y0&dDYvgoVJ6QeoH*9d`W1a zbm?O+@h+22$I$cgC962{N7v2r9vrs{1CU3`t`axdf&0h#V#ad7oLYYLwf^RX8cO8% zKw?GQ-%_mOd$@N4FKB%WV{-rUR24PM;LAABu*4-oxWi%D)-_&QN9;o!^AtGDq)#A! zn=YW(zraEC`c@l?@HD$OZCLC-KPFVCr+sY_v37ow1do?GJh2CT&FTX)Yn#-(LNM5( zd&g1GqnG&6K2iclWINdcFiMA2z*mfzPiECGN==MGT$Nc(6Pjo!SVBkBcBsHu)(77I&5 zd@6D3l;16aC1k&CqIia_=|;sKgu44#7n$K)f#Y_}#B62HtvCi5_f}H*PSH;_yo_61 zfcXgrGJQI=%E1sK(n=H3(^e(jBPPOOcOX~4wEXoY?!$k?P5=9G$0dOHlr3voM%H39 zcSad7_>k^h7ALzW6_aCl<+seTnSIz)S%DwC&^0L1!C%GgjUsAP+cNXHCJTE974pcL zLlUI2tca_|%)MYHxM1bS&14fKgtz`UP`~Hpm^u23PaQuKiN{B2tzO2w0WCMprFPnC zH{et}J@d2rU7shs|8}uaz~?nBI5bTYGthLdIhis~_;Hd+K&fj-X{Mx6Bp*v53b#D| zv?AKbf4I$h88GNr8N<6yM?*rAfLvVuz?jq>z=338oa?aWpJMot>$FiEW8BYiW*TTn z9WW*SIv+I!Z5<<2xqH`151x^{POYC0=s2a2;VtYZ{7?S<6FhO)nXS1jT6dMcoB!$4 zWU0P>)3tRZjLv5(AlT&bZbK%4%xA5`3kZ%AV}5uYTOtM`!@! zl#29HNo+4DS(HF>MfZ@T5bJPPpiP*?mD;5_E&XwSyc_AlnR%$djLWDI4wuKD__Ee< zed3fQ*TK=P&`|Q+a|~WD7)B2S(b!R}Nj8qK&m^ZmLX7*o`)8u)^_CK;=(2H$9i$Jx z2Kw0U`uVL8zqRSrM9;|qtUrgV8;?JeGB8iWN&xY|cG*sLW_I08;<}OXo!0pQ-3Ivg z(0g9tq&4@f-(vCb#L`4z9po!jmdO}+q9BK7i;P=gWP%{ao9Ev?-)Y)!>>ypX@3fq~ z!R?}RrT_A`3uH(qz7oE{$;L)f@u5>i;0S#$G#wDMBS42WthY!U*k zwOTtQ96;@M6$|_$Mx2W#d>Xa_lLlNspsHjptY!C55U~=TFAmlNf{fnUBvY-^I+|XB zUgOSl{xh7N7-F7+0qo`S%pm?kZWaM40Jd9`UefHK%YFtio^wkXp#ScYJ>bzY;ZZZ= zP}7AS0)I^xen-?z08yU{g|0IcB9c(wm9F}-Ji zeMRh<4_nJ2pwM%^n`ZM-cO&b&$N8cPI9{B1E^Ew6?k!m;{zwKHv>32YZ> zKPd6oDT;3=ZsqlXN9{qMtP?3p)8o7kBzW99@?L!p`?=Ku{nuIDP$He*D1QZd0)ZEF zb4Z9q?suNxQ3H+Yx6o$7|D0Bi-6k)|ZiC-f*LCGC$j$B?&$92$C}*Eb7d5kq2n-LU z&yVhxP>aiYhrbFA`f$yk&UV#G{DWVsip~WJI7lZWS(}Alsqm$tWutSV4oJ%|Z~o91 z{LdYqbpH7c<6V&0`5qP_U9wv}@0(z@9-1(0+>b=D@kz2W{hr08#B1xfwS2m@DPfJg zV#;`iO_>D+KRj|5O+omFKegNZa`n!wd8>U(>}t zKe2AQayK(91WRI*p^A_ASe~pe_qaTBltPD=Mal(T9c881nCD%myP|*|92vGBr~mWL z%Mu|D&hKp$2amc3h>$PRuH_bnOj3*|LvHlg;GhZGPa;x_w<`aYUeT}w+b?kD(T;aO zK9lt5xpw%d`}7?3_b{LR$yR|*bT15FJ9ig~qPCjwF7AKc891L6ErSXC4_xET3(+3& zX{va+@UWR%EJvAuu%H(-T@c|Z*6WKBq9gsS=(MjwT!^pPPh!R{+p7iOJ~E+3q4uEf z?(p8JnI|QlsmPLl=6Q+$FF%luIYM*H35BLNY2`C$?%#4cs&u?a-n?ilyCAQMNb_QDOx%!fj`N{nx_u<4A|z`66f>H zOs9_MG(0TRIq}3iqX8_1BXrxeYv#v;e}!Y7EV`BOMh1%ShSzJzp_ITts}$w8IuHCi zDhd)CWK3q{YG&#j+UDoGGUafTs{N-KFa0|80zCsdMd>c?04vpDzu(tB$Z~u619Wdg zp(sF~FY=lR>0Il^-GV2RVWN|0ul z*$uExr9NvF>%ZbT3h@jV4>m{BIG3tlJ~34w4hCZ*??2$?4S*l6#Xl#z;VL*CVCz*r zp@=XSCcuMCKyDP4z*?BG;(N9pLierg1aWv-XE-Pn!PWFk5Kko=YYkMDzM13W1!4P<3r{(xB>xGI zi!`BQKpf@pW%HpXln%�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 Ll%>lg-}wDMc%05e literal 0 HcmV?d00001 diff --git a/blog/docs/releases/images/release1.15-serving.png b/blog/docs/releases/images/release1.15-serving.png new file mode 100644 index 0000000000000000000000000000000000000000..e80e69bd62bdd3d3982b7997eb917a59cfe14630 GIT binary patch literal 172363 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%0AZr-d837y$PB=iu1h)tB>#r?*BS#mj(1~Ri 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 literal 0 HcmV?d00001 From 15f935324197790ef1aeb97f4986867eba5a36c8 Mon Sep 17 00:00:00 2001 From: Knative Automation Date: Tue, 30 Jul 2024 04:05:59 -0400 Subject: [PATCH 13/26] upgrade to latest dependencies (#6081) bumping knative.dev/hack b979959...9c9eed6: > 9c9eed6 :gift_heart: Vendorless codegen via shell scripting (# 386) Signed-off-by: Knative Automation --- go.mod | 4 +- go.sum | 14 +- vendor/knative.dev/hack/boilerplate.go.txt | 15 ++ vendor/knative.dev/hack/codegen-library.sh | 159 +++++++++++++++++-- vendor/knative.dev/hack/embed.go | 2 +- vendor/knative.dev/hack/go.work | 2 +- vendor/knative.dev/hack/go.work.sum | 143 ++++++++++------- vendor/knative.dev/hack/library.sh | 169 +++++++++++++++++---- vendor/knative.dev/hack/presubmit-tests.sh | 8 +- vendor/knative.dev/hack/release.sh | 6 +- vendor/modules.txt | 4 +- 11 files changed, 418 insertions(+), 108 deletions(-) create mode 100644 vendor/knative.dev/hack/boilerplate.go.txt diff --git a/go.mod b/go.mod index 577042ca69b..3d7fe53f49d 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/knative/docs -go 1.18 +go 1.21 require ( cloud.google.com/go/storage v1.10.0 @@ -14,7 +14,7 @@ require ( google.golang.org/grpc v1.36.0 gopkg.in/go-playground/webhooks.v3 v3.13.0 gopkg.in/yaml.v2 v2.3.0 - knative.dev/hack v0.0.0-20240704013904-b9799599afcf + knative.dev/hack v0.0.0-20240719133331-9c9eed6f6679 ) require ( diff --git a/go.sum b/go.sum index d77e752e739..a4f373c40c6 100644 --- a/go.sum +++ b/go.sum @@ -111,6 +111,7 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-github/v32 v32.1.0 h1:GWkQOdXqviCPx7Q7Fj+KyPoGm4SwHRh8rheoPhd27II= @@ -162,6 +163,7 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 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/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -169,6 +171,7 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLD github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 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/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= @@ -177,6 +180,7 @@ github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/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_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -197,7 +201,9 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= 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= @@ -305,6 +311,7 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/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-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -350,6 +357,7 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -497,6 +505,7 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-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/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= @@ -509,6 +518,7 @@ gopkg.in/yaml.v2 v2.2.2/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= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -519,8 +529,8 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.5 h1:nI5egYTGJakVyOryqLs1cQO5dO0ksin5XXs2pspk75k= honnef.co/go/tools v0.0.1-2020.1.5/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -knative.dev/hack v0.0.0-20240704013904-b9799599afcf h1:n92FmZRywgtHso7pFAku7CW0qvRAs1hXtMQqO0R6eiE= -knative.dev/hack v0.0.0-20240704013904-b9799599afcf/go.mod h1:yk2OjGDsbEnQjfxdm0/HJKS2WqTLEFg/N6nUs6Rqx3Q= +knative.dev/hack v0.0.0-20240719133331-9c9eed6f6679 h1:tvbANb4KIO91DT1FGR4yCLA5E0qAmIeQ3DAGOkZGg4k= +knative.dev/hack v0.0.0-20240719133331-9c9eed6f6679/go.mod h1:R0ritgYtjLDO9527h5vb5X6gfvt5LCrJ55BNbVDsWiY= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/vendor/knative.dev/hack/boilerplate.go.txt b/vendor/knative.dev/hack/boilerplate.go.txt new file mode 100644 index 00000000000..8fb5f9cdf5c --- /dev/null +++ b/vendor/knative.dev/hack/boilerplate.go.txt @@ -0,0 +1,15 @@ +/* +Copyright #{YEAR} The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ diff --git a/vendor/knative.dev/hack/codegen-library.sh b/vendor/knative.dev/hack/codegen-library.sh index 5f713dd4364..01a43132dc6 100644 --- a/vendor/knative.dev/hack/codegen-library.sh +++ b/vendor/knative.dev/hack/codegen-library.sh @@ -16,21 +16,156 @@ # Setup the env for doing Knative style codegen. -kn_hack_library=${kn_hack_library:-"$(dirname $0)/../vendor/knative.dev/hack/library.sh"} +# Store Bash options +oldstate="$(set +o)" + +set -Eeuo pipefail + +export repodir kn_hack_dir kn_hack_library \ + MODULE_NAME CODEGEN_TMP_GOPATH CODEGEN_ORIGINAL_GOPATH GOPATH GOBIN \ + CODEGEN_PKG KNATIVE_CODEGEN_PKG + +kn_hack_dir="$(realpath "$(dirname "${BASH_SOURCE[0]:-$0}")")" +kn_hack_library=${kn_hack_library:-"${kn_hack_dir}/library.sh"} if [[ -f "$kn_hack_library" ]]; then - source $kn_hack_library + # shellcheck disable=SC1090 + source "$kn_hack_library" else - echo "this file is intended to be imported from a golang project that vendors knative.dev/hack" - exit + echo "The \$kn_hack_library points to a non-existent file: $kn_hack_library" >&2 + exit 42 fi -export MODULE_NAME=$(go_mod_module_name) -export GOPATH=$(go_mod_gopath_hack) -export GOBIN=${GOPATH}/bin # Set GOBIN explicitly as deepcopy-gen is installed by go install. -export CODEGEN_PKG=${CODEGEN_PKG:-$(cd ${REPO_ROOT_DIR}; ls -d -1 ./vendor/k8s.io/code-generator 2>/dev/null || echo ../code-generator)} -export KNATIVE_CODEGEN_PKG=${KNATIVE_CODEGEN_PKG:-$(cd ${REPO_ROOT_DIR}; ls -d -1 ./vendor/knative.dev/pkg 2>/dev/null || echo "${REPO_ROOT_DIR}")} +repodir="$(go_run knative.dev/toolbox/modscope@latest current --path)" + +function go-resolve-pkg-dir() { + local pkg="${1:?Pass the package name}" + local pkgdir + if [ -d "${repodir}/vendor" ]; then + pkgdir="${repodir}/vendor/${pkg}" + if [ -d "${pkgdir}" ]; then + echo "${pkgdir}" + return 0 + else + return 1 + fi + else + go mod download -x > /dev/stderr + go list -m -f '{{.Dir}}' "${pkg}" 2>/dev/null + return $? + fi +} + +# Change dir to the original executing script's directory, not the current source! +pushd "$(dirname "$(realpath "$0")")" > /dev/null + +if ! CODEGEN_PKG="${CODEGEN_PKG:-"$(go-resolve-pkg-dir k8s.io/code-generator)"}"; then + warning "Failed to determine the k8s.io/code-generator package" +fi +if ! KNATIVE_CODEGEN_PKG="${KNATIVE_CODEGEN_PKG:-"$(go-resolve-pkg-dir knative.dev/pkg)"}"; then + warning "Failed to determine the knative.dev/pkg package" +fi + +popd > /dev/null + +CODEGEN_ORIGINAL_GOPATH="$(go env GOPATH)" +CODEGEN_TMP_GOPATH=$(go_mod_gopath_hack) +GOPATH="${CODEGEN_TMP_GOPATH}" +GOBIN="${GOPATH}/bin" # Set GOBIN explicitly as k8s-gen' are installed by go install. + +if [[ -n "${CODEGEN_PKG}" ]] && ! [ -x "${CODEGEN_PKG}/generate-groups.sh" ]; then + chmod +x "${CODEGEN_PKG}/generate-groups.sh" + chmod +x "${CODEGEN_PKG}/generate-internal-groups.sh" +fi +if [[ -n "${KNATIVE_CODEGEN_PKG}" ]] && ! [ -x "${KNATIVE_CODEGEN_PKG}/hack/generate-knative.sh" ]; then + chmod +x "${KNATIVE_CODEGEN_PKG}/hack/generate-knative.sh" +fi + +# Generate boilerplate file with the current year +function boilerplate() { + local go_header_file="${kn_hack_dir}/boilerplate.go.txt" + local current_boilerplate_file="${TMPDIR}/boilerplate.go.txt" + # Replace #{YEAR} with the current year + sed "s/#{YEAR}/$(date +%Y)/" \ + < "${go_header_file}" \ + > "${current_boilerplate_file}" + echo "${current_boilerplate_file}" +} + +# Generate K8s' groups codegen +function generate-groups() { + if [[ -z "${CODEGEN_PKG}" ]]; then + abort "CODEGEN_PKG is not set" + fi + "${CODEGEN_PKG}"/generate-groups.sh \ + "$@" \ + --go-header-file "$(boilerplate)" +} + +# Generate K8s' internal groups codegen +function generate-internal-groups() { + if [[ -z "${CODEGEN_PKG}" ]]; then + abort "CODEGEN_PKG is not set" + fi + "${CODEGEN_PKG}"/generate-internal-groups.sh \ + "$@" \ + --go-header-file "$(boilerplate)" +} + +# Generate Knative style codegen +function generate-knative() { + if [[ -z "${KNATIVE_CODEGEN_PKG}" ]]; then + abort "KNATIVE_CODEGEN_PKG is not set" + fi + "${KNATIVE_CODEGEN_PKG}/hack/generate-knative.sh" \ + "$@" \ + --go-header-file "$(boilerplate)" +} + +# Cleanup after generating code +function cleanup-codegen() { + restore-changes-if-its-copyright-year-only + restore-gopath +} + +# Restore changes if the file contains only the change in the copyright year +function restore-changes-if-its-copyright-year-only() { + local difflist + log "Cleaning up generated code" + difflist="$(mktemp)" + git diff --exit-code --name-only > "$difflist" + # list git changes and skip those which differ only in the boilerplate year + while read -r file; do + # check if the file contains just the change in the boilerplate year + if [ "$(LANG=C git diff --exit-code --shortstat -- "$file")" = ' 1 file changed, 1 insertion(+), 1 deletion(-)' ] && \ + [[ "$(git diff --exit-code -U1 -- "$file" | grep -Ec '^[+-]\s*[*#]?\s*Copyright 2[0-9]{3}')" -eq 2 ]]; then + # restore changes to that file + git checkout -- "$file" + fi + done < "$difflist" + rm -f "$difflist" +} + +# Restore the GOPATH and clean up the temporary directory +function restore-gopath() { + # Skip this if the directory is already checked out onto the GOPATH. + if __is_checkout_onto_gopath; then + return + fi + if [ -d "$CODEGEN_TMP_GOPATH" ]; then + chmod -R u+w "${CODEGEN_TMP_GOPATH}" + rm -rf "${CODEGEN_TMP_GOPATH}" + unset CODEGEN_TMP_GOPATH + fi + unset GOPATH GOBIN + # Restore the original GOPATH, if it was different from the default one. + if [ "$CODEGEN_ORIGINAL_GOPATH" != "$(go env GOPATH)" ]; then + export GOPATH="$CODEGEN_ORIGINAL_GOPATH" + fi + unset CODEGEN_ORIGINAL_GOPATH +} + +add_trap cleanup-codegen EXIT -[ -x ${CODEGEN_PKG}/generate-groups.sh ] || chmod +x ${CODEGEN_PKG}/generate-groups.sh -[ -x ${CODEGEN_PKG}/generate-internal-groups.sh ] || chmod +x ${CODEGEN_PKG}/generate-internal-groups.sh -[ -x ${KNATIVE_CODEGEN_PKG}/hack/generate-knative.sh ] || chmod +x ${KNATIVE_CODEGEN_PKG}/hack/generate-knative.sh +# Restore Bash options +eval "$oldstate" diff --git a/vendor/knative.dev/hack/embed.go b/vendor/knative.dev/hack/embed.go index 62f856ec68c..aedb546df13 100644 --- a/vendor/knative.dev/hack/embed.go +++ b/vendor/knative.dev/hack/embed.go @@ -20,5 +20,5 @@ import ( "embed" ) -//go:embed *.sh +//go:embed *.sh *.go.txt var Scripts embed.FS diff --git a/vendor/knative.dev/hack/go.work b/vendor/knative.dev/hack/go.work index b6265ad9e26..0c69c9e28d6 100644 --- a/vendor/knative.dev/hack/go.work +++ b/vendor/knative.dev/hack/go.work @@ -1,4 +1,4 @@ -go 1.18 +go 1.21 use ( . diff --git a/vendor/knative.dev/hack/go.work.sum b/vendor/knative.dev/hack/go.work.sum index 1cc0cde9370..f8a39b236e2 100644 --- a/vendor/knative.dev/hack/go.work.sum +++ b/vendor/knative.dev/hack/go.work.sum @@ -1,61 +1,102 @@ -cloud.google.com/go v0.26.0 h1:e0WKqKTd5BnrG8aKH3J3h+QvEIQtSUcf2n5UZ5ZgLtQ= -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46 h1:lsxEuwrXEAokXB9qhlbKWPpo3KMLZQ5WB5WLQRW1uq0= -github.com/PuerkitoBio/purell v1.0.0 h1:0GoNN3taZV6QI81IXgCbxMyEaJDXMSIjArYBCYzVVvs= -github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2 h1:JCHLVE3B+kJde7bIEo5N4J+ZbLhp0J1Fs+ulyRws4gE= -github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk= -github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/alecthomas/chroma/v2 v2.14.0 h1:R3+wzpnUArGcQz7fCETQBzO5n9IMNi13iIs46aU4V9E= +github.com/alecthomas/chroma/v2 v2.14.0/go.mod h1:QolEbTfmUHIMVpBqxeDnNBj2uoeI4EbYP4i6n68SG4I= +github.com/alecthomas/kong v0.9.0 h1:G5diXxc85KvoV2f0ZRVuMsi45IrBgx9zDNGNj165aPA= +github.com/alecthomas/kong v0.9.0/go.mod h1:Y47y5gKfHp1hDc7CH7OeXgLIpp+Q2m1Ni0L5s3bI8Os= +github.com/alecthomas/mango-kong v0.1.0 h1:iFVfP1k1K4qpml3JUQmD5I8MCQYfIvsD9mRdrw7jJC4= +github.com/alecthomas/mango-kong v0.1.0/go.mod h1:t+TYVdsONUolf/BwVcm+15eqcdAj15h4Qe9MMFAwwT4= +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/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= +github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= +github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= +github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= +github.com/catppuccin/go v0.2.0 h1:ktBeIrIP42b/8FGiScP9sgrWOss3lw0Z5SktRoithGA= +github.com/catppuccin/go v0.2.0/go.mod h1:8IHJuMGaUUjQM82qBrGNBv7LFq6JI3NnQCF6MOlZjpc= +github.com/charmbracelet/bubbles v0.18.0 h1:PYv1A036luoBGroX6VWjQIE9Syf2Wby2oOl/39KLfy0= +github.com/charmbracelet/bubbles v0.18.0/go.mod h1:08qhZhtIwzgrtBjAcJnij1t1H0ZRjwHyGsy6AL11PSw= +github.com/charmbracelet/bubbletea v0.26.3 h1:iXyGvI+FfOWqkB2V07m1DF3xxQijxjY2j8PqiXYqasg= +github.com/charmbracelet/bubbletea v0.26.3/go.mod h1:bpZHfDHTYJC5g+FBK+ptJRCQotRC+Dhh3AoMxa/2+3Q= +github.com/charmbracelet/glamour v0.7.0 h1:2BtKGZ4iVJCDfMF229EzbeR1QRKLWztO9dMtjmqZSng= +github.com/charmbracelet/glamour v0.7.0/go.mod h1:jUMh5MeihljJPQbJ/wf4ldw2+yBP59+ctV36jASy7ps= +github.com/charmbracelet/huh v0.4.2 h1:5wLkwrA58XDAfEZsJzNQlfJ+K8N9+wYwvR5FOM7jXFM= +github.com/charmbracelet/huh v0.4.2/go.mod h1:g9OXBgtY3zRV4ahnVih9bZE+1yGYN+y2C9Q6L2P+WM0= +github.com/charmbracelet/log v0.4.0 h1:G9bQAcx8rWA2T3pWvx7YtPTPwgqpk7D68BX21IRW8ZM= +github.com/charmbracelet/log v0.4.0/go.mod h1:63bXt/djrizTec0l11H20t8FDSvA4CRZJ1KH22MdptM= +github.com/charmbracelet/x/exp/strings v0.0.0-20240525152034-77596eb8760e h1:DhvN6ye3nHLhRtNHtlrQ0Zk+vmeN7YtEnyIRfcl7e0E= +github.com/charmbracelet/x/exp/strings v0.0.0-20240525152034-77596eb8760e/go.mod h1:pBhA0ybfXv6hDjQUZ7hk1lVxBiUbupdw5R31yPUViVQ= +github.com/charmbracelet/x/input v0.1.1 h1:YDOJaTUKCqtGnq9PHzx3pkkl4pXDOANUHmhH3DqMtM4= +github.com/charmbracelet/x/input v0.1.1/go.mod h1:jvdTVUnNWj/RD6hjC4FsoB0SeZCJ2ZBkiuFP9zXvZI0= +github.com/charmbracelet/x/term v0.1.1 h1:3cosVAiPOig+EV4X9U+3LDgtwwAoEzJjNdwbXDjF6yI= +github.com/charmbracelet/x/term v0.1.1/go.mod h1:wB1fHt5ECsu3mXYusyzcngVWWlu1KKUmmLhfgr/Flxw= +github.com/charmbracelet/x/windows v0.1.2 h1:Iumiwq2G+BRmgoayww/qfcvof7W/3uLoelhxojXlRWg= +github.com/charmbracelet/x/windows v0.1.2/go.mod h1:GLEO/l+lizvFDBPLIOk+49gdX49L9YWMB5t+DZd0jkQ= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w= -github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96 h1:cenwrSVm+Z7QLSV/BsnenAOcDXdX4cMv4wP0B/5QbPg= -github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 h1:bWDMxwH3px2JBh6AyO7hdCn/PkvCZXii8TGj7sbtEbQ= -github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc= -github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633 h1:H2pdYOb3KQ1/YsqVWoWNLQO+fusocsw354rqGTZtAgw= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473 h1:4cmBvAEBNJaGARUEs3/suWRyfyBfhf7I60WBZq+bv2w= -github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A= -github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= -github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680 h1:ZktWZesgun21uEDrwW7iEV1zPCGQldM2atlJZ3TdvVM= -github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1 h1:wSt/4CYxs70xbATrGXhokKF1i0tZjENLOo1ioIO13zk= -github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9 h1:tF+augKRWlWx0J0B7ZyyKSiTyV6E1zZe+7b3qQlcEf8= -github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501 h1:C1JKChikHGpXwT5UQDFaryIpDtyyGL/CR6C2kB7F1oc= -github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87 h1:zP3nY8Tk2E6RTkqGYrarZXuzh+ffyLDljLxCy1iJw80= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7 h1:5ZkaAPbicIKTF2I64qf5Fh8Aa83Q/dnOafMYV0OMwjA= -github.com/golang/mock v1.1.1 h1:G5FRp8JnTd7RQH5kemVNlMeyXQAztQ3mOWV95KxsXH8= -github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= -github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= -github.com/googleapis/gnostic v0.4.1 h1:DLJCy1n/vrD4HPjOvYcT8aYQXpPIzoRZONaYwyycI+I= -github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= -github.com/kisielk/errcheck v1.2.0 h1:reN85Pxc5larApoH1keMBiu2GWtPqXQ1nc9gx+jOU+E= +github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= +github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= +github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= +github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= +github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8= +github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0= +github.com/kisielk/errcheck v1.5.0 h1:e8esj/e4R+SAOwFwN+n3zr0nYeCyeweozKfO23MvHzY= github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= -github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw= -github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a h1:TpvdAwDAt1K4ANVOfcihouRdvP+MgAfDWwBuct4l6ZY= +github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= +github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= +github.com/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58= +github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs= +github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= +github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= +github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= +github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= +github.com/muesli/mango v0.2.0 h1:iNNc0c5VLQ6fsMgAqGQofByNUBH2Q2nEbD6TaI+5yyQ= +github.com/muesli/mango v0.2.0/go.mod h1:5XFpbC8jY5UUv89YQciiXNlbi+iJgt29VDC5xbzrLL4= +github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= +github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= +github.com/muesli/roff v0.1.0 h1:YD0lalCotmYuF5HhZliKWlIx7IEhiXeSfq7hNjFqGF8= +github.com/muesli/roff v0.1.0/go.mod h1:pjAHQM9hdUUwm/krAfrLGgJkXJ+YuhtsfZ42kieB2Ig= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d h1:7PxY7LVfSZm7PEeBTyK1rj1gABdCO2mbri6GKO1cMDs= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= -github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw= -github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA= +github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4 h1:c2HOrn5iMezYjSlGPncknSEr/8x5LELb/ilJbXi9DEA= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3 h1:XQyxROzUlZH+WIQwySDgnISgOivlhjIEwaQaJEJrrN0= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs= -golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= -golang.org/x/sys v0.0.0-20201112073958-5cba982894dd h1:5CtCZbICpIOFdgO940moixOPjc0178IU44m4EjOO5IY= -golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= -google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg= -google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc h1:/hemPrYIhOhy8zYrNj+069zDB68us2sMGsfkFJO0iZs= -k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac h1:sAvhNk5RRuc6FNYGqe7Ygz3PSo/2wGWbulskmzRX8Vs= -k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6 h1:+WnxoVtG8TMiudHBSEtrVL1egv36TkkJm+bA8AxicmQ= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= +github.com/yuin/goldmark v1.7.1 h1:3bajkSilaCbjdKVsKdZjZCLBNPL9pYzrCakKaf4U49U= +github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= +github.com/yuin/goldmark-emoji v1.0.2 h1:c/RgTShNgHTtc6xdz2KKI74jJr6rWi7FPgnP9GAsO5s= +github.com/yuin/goldmark-emoji v1.0.2/go.mod h1:RhP/RWpexdp+KHs7ghKnifRoIs/Bq4nDS7tRbCkOwKY= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/exp v0.0.0-20240525044651-4c93da0ed11d h1:N0hmiNbwsSNwHBAvR3QB5w25pUwH4tK0Y/RltD1j1h4= +golang.org/x/exp v0.0.0-20240525044651-4c93da0ed11d/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= +golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= diff --git a/vendor/knative.dev/hack/library.sh b/vendor/knative.dev/hack/library.sh index e5d21b70e67..08f2dba16f1 100644 --- a/vendor/knative.dev/hack/library.sh +++ b/vendor/knative.dev/hack/library.sh @@ -138,18 +138,72 @@ function calcRetcode() { echo "$rc" } +# Print error message. +# Parameters: $* - error message to be displayed +function error() { + local first="$1" + shift + local args=("ERROR: $first" "$@") + gum_banner \ + --color '#D00' \ + --padding '1 3' \ + --border double \ + "${args[@]}" > /dev/stderr +} + # Print error message and call exit(n) where n calculated from the error message. # Parameters: $1..$n - error message to be displayed # Globals: abort_retcode will change the default retcode to be returned function abort() { - make_banner '*' "ERROR: $*" >&2 + error "$@" readonly abort_retcode="${abort_retcode:-$(calcRetcode "$*")}" exit "$abort_retcode" } +# Simple header for logging purposes. +function header() { + local upper + upper="$(echo "$*" | tr '[:lower:]' '[:upper:]')" + gum_banner \ + --border double \ + --color 44 \ + --padding '1 3' \ + "$upper" +} + +# Simple subheader for logging purposes. +function subheader() { + gum_banner \ + --color 45 \ + "$@" +} + +# Simple log step for logging purposes. +function log.step() { + echo "=== $*" | gum_style --foreground 44 +} + +# Simple log for logging purposes. +function log() { + echo "--- $*" | gum_style --foreground 45 +} + +# Simple warning banner for logging purposes. +function warning() { + local first="$1" + shift + local args=("WARN: $first" "$@") + gum_banner \ + --color '#DD0' \ + --padding '1 3' \ + --border rounded \ + "${args[@]}" > /dev/stderr +} + # Display a box banner. # Parameters: $1 - character to use for the box. # $2 - banner message. +# Deprecated: Use `gum_banner` instead. function make_banner() { local msg="$1$1$1$1 $2 $1$1$1$1" local border="${msg//[^$1]/$1}" @@ -161,25 +215,62 @@ function make_banner() { fi } -# Simple header for logging purposes. -function header() { - local upper="$(echo $1 | tr a-z A-Z)" - make_banner "=" "${upper}" -} - -# Simple subheader for logging purposes. -function subheader() { - make_banner "-" "$1" +# Display a fancy box banner. +# Parameters: +# [--border ] - a gum border type for the box, defaults to 'rounded' +# [--color ] - a gum color for the box, defaults to '0'' +# [--padding ] - a gum padding for the box, defaults to '0 1' +# $* - banner message. +function gum_banner() { + local border='rounded' + local color='0' + local padding='0 1' + while [[ $# -gt 0 ]]; do + case "$1" in + --border) + border="$2" + shift 2 + ;; + --color) + color="$2" + shift 2 + ;; + --padding) + padding="$2" + shift 2 + ;; + *) + break + ;; + esac + done + local args=( + --align center + --border "$border" + --foreground "$color" + --border-foreground "$color" + --padding "$padding" + "$@" + ) + # TODO: Remove once logs have timestamps on Prow, details see: + # https://github.com/kubernetes/test-infra/issues/10100 + if (( IS_PROW )); then + local dt + # RFC3339Nano format with 3 digits of ns without timezone offset + dt="$(TZ='UTC' date --rfc-3339=ns | sed -E 's/\.([0-9]{3})[0-9]+.+$/.\1/')" + args+=('' "at $dt") + fi + gum_style "${args[@]}" } -# Simple warning banner for logging purposes. -function warning() { - make_banner '!' "WARN: $*" >&2 +# Simple info banner for logging purposes. +function gum_style() { + go_run github.com/charmbracelet/gum@v0.14.1 style "$@" } # Checks whether the given function exists. function function_exists() { - [[ "$(type -t $1)" == "function" ]] + [[ "$(type -t "$1")" == "function" ]] } # GitHub Actions aware output grouping. @@ -187,7 +278,7 @@ function group() { # End the group is there is already a group. if [ -z ${__GROUP_TRACKER+x} ]; then export __GROUP_TRACKER="grouping" - trap end_group EXIT + add_trap end_group EXIT else end_group fi @@ -198,10 +289,10 @@ function group() { # GitHub Actions aware output grouping. function start_group() { if [[ -n ${GITHUB_WORKFLOW:-} ]]; then - echo "::group::$@" - trap end_group EXIT + echo "::group::$*" + add_trap end_group EXIT else - echo "--- $@" + log "$@" fi } @@ -517,7 +608,7 @@ function report_go_test() { echo "Test log (ANSI) written to ${ansilog}" htmllog="${logfile/.jsonl/.html}" - go_run github.com/buildkite/terminal-to-html/v3/cmd/terminal-to-html@v3.11.0 \ + go_run github.com/buildkite/terminal-to-html/v3/cmd/terminal-to-html@v3.10.0 \ --preview < "$ansilog" > "$htmllog" echo "Test log (HTML) written to ${htmllog}" @@ -682,18 +773,18 @@ function go_update_deps() { function __clean_goworksum_if_exists() { if [ -f "$REPO_ROOT_DIR/go.work.sum" ]; then - echo "=== Cleaning the go.work.sum file" - true > "$REPO_ROOT_DIR/go.work.sum" + log.step 'Cleaning the go.work.sum file' + truncate --size 0 "$REPO_ROOT_DIR/go.work.sum" fi } function __remove_goworksum_if_empty() { if [ -f "$REPO_ROOT_DIR/go.work" ]; then - echo "=== Syncing the go workspace" + log.step 'Syncing the go workspace' go work sync fi if ! [ -s "$REPO_ROOT_DIR/go.work.sum" ]; then - echo "=== Removing empty go.work.sum" + log.step 'Removing empty go.work.sum' rm -f "$REPO_ROOT_DIR/go.work.sum" fi } @@ -706,7 +797,7 @@ function __go_update_deps_for_module() { export GONOSUMDB="${GONOSUMDB:-},knative.dev/*" export GONOPROXY="${GONOPROXY:-},knative.dev/*" - echo "=== Update Deps for Golang module: $(go_mod_module_name)" + log.step "Update Deps for Golang module: $(go_mod_module_name)" local UPGRADE=0 local RELEASE="v9000.1" # release v9000 is so far in the future, it will always pick the default branch. @@ -752,7 +843,12 @@ function __go_update_deps_for_module() { if [[ "${FORCE_VENDOR:-false}" == "true" ]] || [ -d vendor ]; then group "Go mod vendor" - go mod vendor 2>&1 | grep -v "ignoring symlink" || true + # Call go work vendor for Go 1.22+ and go.work file exists. + if [ -f "$REPO_ROOT_DIR/go.work" ] && go help work vendor &>/dev/null; then + go work vendor + else + go mod vendor + fi else go mod download -x fi @@ -785,22 +881,32 @@ function go_mod_module_name() { go_run knative.dev/toolbox/modscope@latest current } +function __is_checkout_onto_gopath() { + ! [ "${REPO_ROOT_DIR##"$(go env GOPATH)"}" = "$REPO_ROOT_DIR" ] +} + # Return a GOPATH to a temp directory. Works around the out-of-GOPATH issues # for k8s client gen mixed with go mod. # Intended to be used like: # export GOPATH=$(go_mod_gopath_hack) function go_mod_gopath_hack() { - # Skip this if the directory is already checked out onto the GOPATH. - if [[ "${REPO_ROOT_DIR##$(go env GOPATH)}" != "$REPO_ROOT_DIR" ]]; then + # Skip this if the directory is already checked out onto the GOPATH. + if __is_checkout_onto_gopath; then go env GOPATH return fi - local TMP_DIR="$(mktemp -d)" - local TMP_REPO_PATH="${TMP_DIR}/src/$(go_mod_module_name)" - mkdir -p "$(dirname "${TMP_REPO_PATH}")" && ln -s "${REPO_ROOT_DIR}" "${TMP_REPO_PATH}" + local TMP_GOPATH TMP_REPO_PATH + TMP_GOPATH="$TMPDIR/go" + TMP_REPO_PATH="${TMP_GOPATH}/src/$(go_mod_module_name)" + if [ -d "${TMP_REPO_PATH}" ]; then + echo "${TMP_GOPATH}" + return + fi + mkdir -p "$(dirname "${TMP_REPO_PATH}")" + ln -s "${REPO_ROOT_DIR}" "${TMP_REPO_PATH}" - echo "${TMP_DIR}" + echo "${TMP_GOPATH}" } # Run kntest tool @@ -1014,6 +1120,7 @@ function latest_version() { # Initializations that depend on previous functions. # These MUST come last. +MODULE_NAME="$(go_mod_module_name)" readonly _TEST_INFRA_SCRIPTS_DIR="$(dirname $(get_canonical_path "${BASH_SOURCE[0]}"))" readonly REPO_NAME_FORMATTED="Knative $(capitalize "${REPO_NAME//-/ }")" diff --git a/vendor/knative.dev/hack/presubmit-tests.sh b/vendor/knative.dev/hack/presubmit-tests.sh index d210dc703f3..b96ffadf43e 100644 --- a/vendor/knative.dev/hack/presubmit-tests.sh +++ b/vendor/knative.dev/hack/presubmit-tests.sh @@ -72,9 +72,11 @@ function initialize_environment() { # Parameters: $1 - test group name (e.g., build) # $2 - result (0=passed, 1=failed) function results_banner() { - local result - [[ $2 -eq 0 ]] && result="PASSED" || result="FAILED" - header "$1 tests ${result}" + if [[ $2 -eq 0 ]]; then + header "$1 tests PASSED" + else + error "$1 tests FAILED" + fi } # Run build tests. If there's no `build_tests` function, run the default diff --git a/vendor/knative.dev/hack/release.sh b/vendor/knative.dev/hack/release.sh index cbc20f69016..7c5c2ba5227 100644 --- a/vendor/knative.dev/hack/release.sh +++ b/vendor/knative.dev/hack/release.sh @@ -17,7 +17,7 @@ # This is a helper script for Knative release scripts. # See README.md for instructions on how to use it. -source $(dirname "${BASH_SOURCE[0]}")/library.sh +source "$(dirname "${BASH_SOURCE[0]}")/library.sh" # Organization name in GitHub; defaults to Knative. readonly ORG_NAME="${ORG_NAME:-knative}" @@ -37,9 +37,9 @@ readonly RELEASE_SIGNING_IDENTITY="signer@knative-releases.iam.gserviceaccount.c readonly GEO_REPLICATION=(us eu asia) # Simple banner for logging purposes. -# Parameters: $1 - message to display. +# Parameters: $* - message to display. function banner() { - make_banner "@" "$1" + subheader "$*" } # Tag images in the yaml files if $TAG is not empty. diff --git a/vendor/modules.txt b/vendor/modules.txt index 5db94568bba..2841dca8c03 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -300,7 +300,7 @@ gopkg.in/go-playground/webhooks.v3/github gopkg.in/yaml.v2 # honnef.co/go/tools v0.0.1-2020.1.5 ## explicit; go 1.11 -# knative.dev/hack v0.0.0-20240704013904-b9799599afcf -## explicit; go 1.18 +# knative.dev/hack v0.0.0-20240719133331-9c9eed6f6679 +## explicit; go 1.21 knative.dev/hack # go.opencensus.io => go.opencensus.io v0.20.2 From 94e8559cf45e5abdb3a481bc8d0196d86323e199 Mon Sep 17 00:00:00 2001 From: Knative Automation Date: Tue, 30 Jul 2024 09:16:03 -0400 Subject: [PATCH 14/26] Update community files (#6082) Signed-off-by: Knative Automation --- OWNERS_ALIASES | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/OWNERS_ALIASES b/OWNERS_ALIASES index 51a9e498393..c6c29092ba3 100644 --- a/OWNERS_ALIASES +++ b/OWNERS_ALIASES @@ -49,9 +49,6 @@ aliases: - lkingland - salaboy knative-admin: - - Cali0707 - - Leo6Leo - - ReToCode - aliok - cardil - davidhadas @@ -66,14 +63,8 @@ aliases: - nainaz - psschwei - salaboy - - skonto - upodroid - knative-release-leads: - - Cali0707 - - Leo6Leo - - ReToCode - - dsimansk - - skonto + knative-release-leads: [] knative-robots: - knative-automation - knative-prow-releaser-robot From 7917d73d5728a1c6f9bf6470d89c6c12225d7db8 Mon Sep 17 00:00:00 2001 From: Stavros Kontopoulos Date: Wed, 31 Jul 2024 01:03:40 +0300 Subject: [PATCH 15/26] fix http1 metadata (#6083) --- docs/serving/services/http-protocol.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/serving/services/http-protocol.md b/docs/serving/services/http-protocol.md index 8a0eba2577c..7dfddf9132f 100644 --- a/docs/serving/services/http-protocol.md +++ b/docs/serving/services/http-protocol.md @@ -77,7 +77,7 @@ metadata: namespace: default spec: template: - spec: + metadata: annotations: features.knative.dev/http-full-duplex: "Enabled" ... From 3b1b9711082b179916dba78b46221ea9d17abac0 Mon Sep 17 00:00:00 2001 From: Knative Automation Date: Mon, 5 Aug 2024 01:59:34 -0400 Subject: [PATCH 16/26] upgrade to latest dependencies (#6087) bumping knative.dev/hack 9c9eed6...441a19f: > 441a19f remove geo replication (# 389) > 0a23232 Update community files (# 388) Signed-off-by: Knative Automation --- go.mod | 2 +- go.sum | 4 ++-- vendor/knative.dev/hack/release.sh | 25 ------------------------- vendor/modules.txt | 2 +- 4 files changed, 4 insertions(+), 29 deletions(-) diff --git a/go.mod b/go.mod index 3d7fe53f49d..a359806c4ad 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( google.golang.org/grpc v1.36.0 gopkg.in/go-playground/webhooks.v3 v3.13.0 gopkg.in/yaml.v2 v2.3.0 - knative.dev/hack v0.0.0-20240719133331-9c9eed6f6679 + knative.dev/hack v0.0.0-20240801232131-441a19fc9ead ) require ( diff --git a/go.sum b/go.sum index a4f373c40c6..ae6236712f1 100644 --- a/go.sum +++ b/go.sum @@ -529,8 +529,8 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.5 h1:nI5egYTGJakVyOryqLs1cQO5dO0ksin5XXs2pspk75k= honnef.co/go/tools v0.0.1-2020.1.5/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -knative.dev/hack v0.0.0-20240719133331-9c9eed6f6679 h1:tvbANb4KIO91DT1FGR4yCLA5E0qAmIeQ3DAGOkZGg4k= -knative.dev/hack v0.0.0-20240719133331-9c9eed6f6679/go.mod h1:R0ritgYtjLDO9527h5vb5X6gfvt5LCrJ55BNbVDsWiY= +knative.dev/hack v0.0.0-20240801232131-441a19fc9ead h1:ViH1OEO0LViKa6W61YKUpLzOp7CJCFL9yLyIojHIuQ8= +knative.dev/hack v0.0.0-20240801232131-441a19fc9ead/go.mod h1:R0ritgYtjLDO9527h5vb5X6gfvt5LCrJ55BNbVDsWiY= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/vendor/knative.dev/hack/release.sh b/vendor/knative.dev/hack/release.sh index 7c5c2ba5227..5cc8f323585 100644 --- a/vendor/knative.dev/hack/release.sh +++ b/vendor/knative.dev/hack/release.sh @@ -33,36 +33,12 @@ readonly RELEASE_GCR="gcr.io/knative-releases/github.com/${ORG_NAME}/${REPO_NAME readonly NIGHTLY_SIGNING_IDENTITY="signer@knative-nightly.iam.gserviceaccount.com" readonly RELEASE_SIGNING_IDENTITY="signer@knative-releases.iam.gserviceaccount.com" -# Georeplicate images to {us,eu,asia}.gcr.io -readonly GEO_REPLICATION=(us eu asia) - # Simple banner for logging purposes. # Parameters: $* - message to display. function banner() { subheader "$*" } -# Tag images in the yaml files if $TAG is not empty. -# $KO_DOCKER_REPO is the registry containing the images to tag with $TAG. -# Parameters: $1..$n - files to parse for images (non .yaml files are ignored). -function tag_images_in_yamls() { - [[ -z ${TAG} ]] && return 0 - local SRC_DIR="${GOPATH}/src/" - local DOCKER_BASE="${KO_DOCKER_REPO}/${REPO_ROOT_DIR/$SRC_DIR}" - local GEO_REGIONS="${GEO_REPLICATION[@]} " - echo "Tagging any images under '${DOCKER_BASE}' with ${TAG}" - # shellcheck disable=SC2068 - for file in $@; do - [[ "${file##*.}" != "yaml" ]] && continue - echo "Inspecting ${file}" - for image in $(grep -o "${DOCKER_BASE}/[a-z\./-]\+@sha256:[0-9a-f]\+" "${file}"); do - for region in "" ${GEO_REGIONS// /. }; do - gcloud -q container images add-tag "${image}" "${region}${image%%@*}:${TAG}" - done - done - done -} - # Copy the given files to the $RELEASE_GCS_BUCKET bucket's "latest" directory. # If $TAG is not empty, also copy them to $RELEASE_GCS_BUCKET bucket's "previous" directory. # Parameters: $1..$n - files to copy. @@ -646,7 +622,6 @@ function run_validation_tests() { # Parameters: $1..$n - files to add to the release. function publish_artifacts() { (( ! PUBLISH_RELEASE )) && return - tag_images_in_yamls "${ARTIFACTS_TO_PUBLISH}" if [[ -n "${RELEASE_DIR}" ]]; then cp "${ARTIFACTS_TO_PUBLISH}" "${RELEASE_DIR}" || abort "cannot copy release to '${RELEASE_DIR}'" fi diff --git a/vendor/modules.txt b/vendor/modules.txt index 2841dca8c03..6c3c5875fb0 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -300,7 +300,7 @@ gopkg.in/go-playground/webhooks.v3/github gopkg.in/yaml.v2 # honnef.co/go/tools v0.0.1-2020.1.5 ## explicit; go 1.11 -# knative.dev/hack v0.0.0-20240719133331-9c9eed6f6679 +# knative.dev/hack v0.0.0-20240801232131-441a19fc9ead ## explicit; go 1.21 knative.dev/hack # go.opencensus.io => go.opencensus.io v0.20.2 From 84895b77df5e10163ffe16926b29c32fc0379396 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Aug 2024 06:28:45 +0000 Subject: [PATCH 17/26] Bump google.golang.org/grpc from 1.36.0 to 1.56.3 (#6088) Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.36.0 to 1.56.3. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.36.0...v1.56.3) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 27 +- go.sum | 355 +- vendor/cloud.google.com/go/.gitignore | 12 - vendor/cloud.google.com/go/CHANGES.md | 1762 --- vendor/cloud.google.com/go/CODE_OF_CONDUCT.md | 44 - vendor/cloud.google.com/go/CONTRIBUTING.md | 261 - vendor/cloud.google.com/go/README.md | 177 - vendor/cloud.google.com/go/RELEASING.md | 149 - vendor/cloud.google.com/go/compute/LICENSE | 202 + .../go/compute/internal/version.go | 18 + .../go/compute/metadata/CHANGES.md | 19 + .../go/compute/metadata/LICENSE | 202 + .../go/compute/metadata/README.md | 27 + .../go/compute/metadata/metadata.go | 52 +- .../go/compute/metadata/retry.go | 114 + .../go/compute/metadata/retry_linux.go | 26 + .../metadata/tidyfix.go} | 9 +- vendor/cloud.google.com/go/doc.go | 109 - vendor/cloud.google.com/go/iam/CHANGES.md | 97 + vendor/cloud.google.com/go/iam/LICENSE | 202 + vendor/cloud.google.com/go/iam/README.md | 40 + .../go/iam/apiv1/iampb}/iam_policy.pb.go | 108 +- .../go/iam/apiv1/iampb}/options.pb.go | 65 +- .../go/iam/apiv1/iampb/policy.pb.go | 1169 ++ vendor/cloud.google.com/go/iam/iam.go | 2 +- .../go/internal/.repo-metadata-full.json | 1665 ++- vendor/cloud.google.com/go/internal/README.md | 27 +- .../cloud.google.com/go/internal/annotate.go | 3 +- .../go/internal/cloudbuild.yaml | 25 + vendor/cloud.google.com/go/internal/retry.go | 37 +- .../go/internal/trace/trace.go | 4 +- vendor/cloud.google.com/go/storage/CHANGES.md | 247 + vendor/cloud.google.com/go/storage/README.md | 10 +- vendor/cloud.google.com/go/storage/acl.go | 193 +- vendor/cloud.google.com/go/storage/bucket.go | 1325 +- vendor/cloud.google.com/go/storage/client.go | 333 + vendor/cloud.google.com/go/storage/copy.go | 151 +- vendor/cloud.google.com/go/storage/doc.go | 368 +- .../go/storage/emulator_test.sh | 92 + vendor/cloud.google.com/go/storage/go110.go | 48 - .../go/storage/grpc_client.go | 1751 +++ vendor/cloud.google.com/go/storage/hmac.go | 169 +- .../go/storage/http_client.go | 1351 ++ vendor/cloud.google.com/go/storage/iam.go | 51 +- .../go/storage/internal/apiv2/doc.go | 174 + .../internal/apiv2/gapic_metadata.json | 168 + .../go/storage/internal/apiv2/metadata.go | 26 + .../storage/internal/apiv2/storage_client.go | 1605 +++ .../internal/apiv2/stubs/storage.pb.go | 10652 +++++++++++++++ .../go/storage/internal/apiv2/version.go | 23 + .../go/storage/internal/version.go | 18 + vendor/cloud.google.com/go/storage/invoke.go | 129 +- .../cloud.google.com/go/storage/not_go110.go | 42 - .../go/storage/notifications.go | 72 +- .../go/storage/post_policy_v4.go | 119 +- vendor/cloud.google.com/go/storage/reader.go | 263 +- vendor/cloud.google.com/go/storage/storage.go | 1039 +- vendor/cloud.google.com/go/storage/writer.go | 217 +- vendor/cloud.google.com/go/testing.md | 236 - vendor/cloud.google.com/go/tools.go | 31 - .../protobuf/internal/gengogrpc/grpc.go | 398 - .../golang/protobuf/jsonpb/decode.go | 531 + .../golang/protobuf/jsonpb/encode.go | 560 + .../github.com/golang/protobuf/jsonpb/json.go | 69 + .../protoc-gen-go/descriptor/descriptor.pb.go | 324 - .../golang/protobuf/protoc-gen-go/main.go | 78 - .../lint => github.com/google/go-cmp}/LICENSE | 2 +- .../github.com/google/go-cmp/cmp/compare.go | 669 + .../google/go-cmp/cmp/export_panic.go | 16 + .../google/go-cmp/cmp/export_unsafe.go | 36 + .../go-cmp/cmp/internal/diff/debug_disable.go | 18 + .../go-cmp/cmp/internal/diff/debug_enable.go | 123 + .../google/go-cmp/cmp/internal/diff/diff.go | 402 + .../google/go-cmp/cmp/internal/flags/flags.go | 9 + .../go-cmp/cmp/internal/function/func.go | 99 + .../google/go-cmp/cmp/internal/value/name.go | 164 + .../cmp/internal/value/pointer_purego.go | 34 + .../cmp/internal/value/pointer_unsafe.go | 37 + .../google/go-cmp/cmp/internal/value/sort.go | 106 + .../github.com/google/go-cmp/cmp/options.go | 554 + vendor/github.com/google/go-cmp/cmp/path.go | 380 + vendor/github.com/google/go-cmp/cmp/report.go | 54 + .../google/go-cmp/cmp/report_compare.go | 433 + .../google/go-cmp/cmp/report_references.go | 264 + .../google/go-cmp/cmp/report_reflect.go | 414 + .../google/go-cmp/cmp/report_slices.go | 614 + .../google/go-cmp/cmp/report_text.go | 432 + .../google/go-cmp/cmp/report_value.go | 121 + vendor/github.com/google/uuid/null.go | 118 + vendor/github.com/google/uuid/uuid.go | 45 +- vendor/github.com/google/uuid/version4.go | 27 +- .../enterprise-certificate-proxy/LICENSE | 202 + .../client/client.go | 185 + .../client/util/util.go | 91 + .../gax-go/v2/.release-please-manifest.json | 3 + .../googleapis/gax-go/v2/CHANGES.md | 54 + .../googleapis/gax-go/v2/apierror/apierror.go | 347 + .../v2/apierror/internal/proto/README.md | 30 + .../internal/proto/custom_error.pb.go | 256 + .../internal/proto/custom_error.proto | 50 + .../v2/apierror/internal/proto/error.pb.go | 280 + .../v2/apierror/internal/proto/error.proto | 46 + .../googleapis/gax-go/v2/call_option.go | 101 +- .../googleapis/gax-go/v2/content_type.go | 112 + vendor/github.com/googleapis/gax-go/v2/gax.go | 4 +- .../googleapis/gax-go/v2/internal/version.go | 33 + .../github.com/googleapis/gax-go/v2/invoke.go | 15 +- .../googleapis/gax-go/v2/proto_json_stream.go | 126 + .../gax-go/v2/release-please-config.json | 10 + .../jstemmer/go-junit-report/.gitignore | 1 - .../jstemmer/go-junit-report/.travis.yml | 16 - .../jstemmer/go-junit-report/LICENSE | 20 - .../jstemmer/go-junit-report/README.md | 49 - .../go-junit-report/formatter/formatter.go | 182 - .../go-junit-report/go-junit-report.go | 45 - .../jstemmer/go-junit-report/parser/parser.go | 319 - .../go.opencensus.io/plugin/ocgrpc/client.go | 56 + .../plugin/ocgrpc/client_metrics.go | 107 + .../plugin/ocgrpc/client_stats_handler.go | 49 + vendor/go.opencensus.io/plugin/ocgrpc/doc.go | 19 + .../go.opencensus.io/plugin/ocgrpc/server.go | 80 + .../plugin/ocgrpc/server_metrics.go | 97 + .../plugin/ocgrpc/server_stats_handler.go | 63 + .../plugin/ocgrpc/stats_common.go | 208 + .../plugin/ocgrpc/trace_common.go | 107 + vendor/golang.org/x/lint/.travis.yml | 19 - vendor/golang.org/x/lint/CONTRIBUTING.md | 15 - vendor/golang.org/x/lint/README.md | 88 - vendor/golang.org/x/lint/golint/golint.go | 159 - vendor/golang.org/x/lint/golint/import.go | 309 - .../golang.org/x/lint/golint/importcomment.go | 13 - vendor/golang.org/x/lint/lint.go | 1615 --- .../x/mod/internal/lazyregexp/lazyre.go | 78 - vendor/golang.org/x/mod/module/module.go | 841 -- vendor/golang.org/x/mod/module/pseudo.go | 250 - vendor/golang.org/x/mod/semver/semver.go | 401 - .../x/net/context/ctxhttp/ctxhttp.go | 71 - vendor/golang.org/x/oauth2/AUTHORS | 3 - vendor/golang.org/x/oauth2/CONTRIBUTORS | 3 - vendor/golang.org/x/oauth2/README.md | 12 +- .../x/oauth2/authhandler/authhandler.go | 94 + .../x/oauth2/google/appengine_gen1.go | 1 + .../x/oauth2/google/appengine_gen2_flex.go | 1 + vendor/golang.org/x/oauth2/google/default.go | 143 +- vendor/golang.org/x/oauth2/google/doc.go | 101 +- vendor/golang.org/x/oauth2/google/error.go | 64 + vendor/golang.org/x/oauth2/google/google.go | 101 +- .../google/internal/externalaccount/aws.go | 595 + .../externalaccount/basecredentials.go | 269 + .../internal/externalaccount/clientauth.go | 45 + .../google/internal/externalaccount/err.go | 18 + .../externalaccount/executablecredsource.go | 309 + .../externalaccount/filecredsource.go | 57 + .../internal/externalaccount/impersonate.go | 105 + .../internal/externalaccount/sts_exchange.go | 107 + .../internal/externalaccount/urlcredsource.go | 75 + vendor/golang.org/x/oauth2/google/jwt.go | 40 +- .../x/oauth2/internal/client_appengine.go | 1 + vendor/golang.org/x/oauth2/internal/token.go | 4 +- vendor/golang.org/x/oauth2/jws/jws.go | 2 +- vendor/golang.org/x/oauth2/oauth2.go | 33 +- vendor/golang.org/x/oauth2/token.go | 14 +- vendor/golang.org/x/sys/execabs/execabs.go | 102 - .../golang.org/x/sys/execabs/execabs_go118.go | 17 - .../golang.org/x/sys/execabs/execabs_go119.go | 20 - vendor/golang.org/x/tools/LICENSE | 27 - vendor/golang.org/x/tools/PATENTS | 22 - .../golang.org/x/tools/cmd/goimports/doc.go | 50 - .../x/tools/cmd/goimports/goimports.go | 380 - .../x/tools/cmd/goimports/goimports_gc.go | 27 - .../x/tools/cmd/goimports/goimports_not_gc.go | 12 - .../x/tools/go/ast/astutil/enclosing.go | 636 - .../x/tools/go/ast/astutil/imports.go | 485 - .../x/tools/go/ast/astutil/rewrite.go | 488 - .../golang.org/x/tools/go/ast/astutil/util.go | 18 - .../x/tools/go/gcexportdata/gcexportdata.go | 187 - .../x/tools/go/gcexportdata/importer.go | 75 - .../x/tools/internal/event/core/event.go | 85 - .../x/tools/internal/event/core/export.go | 70 - .../x/tools/internal/event/core/fast.go | 77 - .../golang.org/x/tools/internal/event/doc.go | 7 - .../x/tools/internal/event/event.go | 127 - .../x/tools/internal/event/keys/keys.go | 564 - .../x/tools/internal/event/keys/standard.go | 22 - .../x/tools/internal/event/label/label.go | 215 - .../x/tools/internal/fastwalk/fastwalk.go | 196 - .../internal/fastwalk/fastwalk_darwin.go | 119 - .../fastwalk/fastwalk_dirent_fileno.go | 14 - .../internal/fastwalk/fastwalk_dirent_ino.go | 15 - .../fastwalk/fastwalk_dirent_namlen_bsd.go | 14 - .../fastwalk/fastwalk_dirent_namlen_linux.go | 29 - .../internal/fastwalk/fastwalk_portable.go | 38 - .../tools/internal/fastwalk/fastwalk_unix.go | 153 - .../x/tools/internal/gcimporter/bexport.go | 852 -- .../x/tools/internal/gcimporter/bimport.go | 1053 -- .../x/tools/internal/gcimporter/exportdata.go | 99 - .../x/tools/internal/gcimporter/gcimporter.go | 265 - .../x/tools/internal/gcimporter/iexport.go | 1180 -- .../x/tools/internal/gcimporter/iimport.go | 976 -- .../internal/gcimporter/newInterface10.go | 22 - .../internal/gcimporter/newInterface11.go | 14 - .../internal/gcimporter/support_go117.go | 16 - .../internal/gcimporter/support_go118.go | 37 - .../x/tools/internal/gcimporter/unified_no.go | 10 - .../tools/internal/gcimporter/unified_yes.go | 10 - .../x/tools/internal/gcimporter/ureader_no.go | 19 - .../tools/internal/gcimporter/ureader_yes.go | 738 - .../x/tools/internal/gocommand/invoke.go | 356 - .../x/tools/internal/gocommand/vendor.go | 109 - .../x/tools/internal/gocommand/version.go | 81 - .../x/tools/internal/gopathwalk/walk.go | 254 - .../x/tools/internal/imports/fix.go | 1738 --- .../x/tools/internal/imports/imports.go | 351 - .../x/tools/internal/imports/mod.go | 716 - .../x/tools/internal/imports/mod_cache.go | 236 - .../x/tools/internal/imports/sortimports.go | 297 - .../x/tools/internal/imports/zstdlib.go | 11115 ---------------- .../x/tools/internal/pkgbits/codes.go | 77 - .../x/tools/internal/pkgbits/decoder.go | 517 - .../x/tools/internal/pkgbits/doc.go | 32 - .../x/tools/internal/pkgbits/encoder.go | 383 - .../x/tools/internal/pkgbits/flags.go | 9 - .../x/tools/internal/pkgbits/frames_go1.go | 21 - .../x/tools/internal/pkgbits/frames_go17.go | 28 - .../x/tools/internal/pkgbits/reloc.go | 42 - .../x/tools/internal/pkgbits/support.go | 17 - .../x/tools/internal/pkgbits/sync.go | 113 - .../internal/pkgbits/syncmarker_string.go | 89 - .../internal/tokeninternal/tokeninternal.go | 59 - .../x/tools/internal/typeparams/common.go | 179 - .../x/tools/internal/typeparams/coretype.go | 122 - .../internal/typeparams/enabled_go117.go | 12 - .../internal/typeparams/enabled_go118.go | 15 - .../x/tools/internal/typeparams/normalize.go | 218 - .../x/tools/internal/typeparams/termlist.go | 163 - .../internal/typeparams/typeparams_go117.go | 197 - .../internal/typeparams/typeparams_go118.go | 151 - .../x/tools/internal/typeparams/typeterm.go | 170 - vendor/golang.org/x/{mod => xerrors}/LICENSE | 2 +- vendor/golang.org/x/{mod => xerrors}/PATENTS | 0 vendor/golang.org/x/xerrors/README | 2 + vendor/golang.org/x/xerrors/adaptor.go | 193 + vendor/golang.org/x/xerrors/codereview.cfg | 1 + vendor/golang.org/x/xerrors/doc.go | 23 + vendor/golang.org/x/xerrors/errors.go | 33 + vendor/golang.org/x/xerrors/fmt.go | 190 + vendor/golang.org/x/xerrors/format.go | 34 + vendor/golang.org/x/xerrors/frame.go | 56 + .../golang.org/x/xerrors/internal/internal.go | 8 + vendor/golang.org/x/xerrors/wrap.go | 112 + .../api/googleapi/googleapi.go | 73 +- .../api/googleapi/transport/apikey.go | 2 +- .../iamcredentials/v1/iamcredentials-api.json | 372 + .../iamcredentials/v1/iamcredentials-gen.go | 1094 ++ .../api/internal/cert/default_cert.go | 58 + .../api/internal/cert/enterprise_cert.go | 54 + .../cert/secureconnect_cert.go} | 84 +- .../google.golang.org/api/internal/creds.go | 151 +- .../internal/dca => internal}/dca.go | 33 +- .../api/internal/gensupport/error.go | 24 + .../api/internal/gensupport/json.go | 33 +- .../api/internal/gensupport/media.go | 140 +- .../api/internal/gensupport/params.go | 10 +- .../api/internal/gensupport/resumable.go | 128 +- .../api/internal/gensupport/retry.go | 121 + .../internal/gensupport/retryable_linux.go | 1 + .../api/internal/gensupport/send.go | 126 +- .../api/internal/settings.go | 66 +- .../google.golang.org/api/internal/version.go | 8 + .../api/option/credentials_go19.go | 23 - .../api/option/credentials_notgo19.go | 22 - .../option/internaloption/internaloption.go | 47 + vendor/google.golang.org/api/option/option.go | 33 +- .../api/storage/v1/storage-api.json | 307 +- .../api/storage/v1/storage-gen.go | 2041 ++- .../google.golang.org/api/transport/dial.go | 48 + vendor/google.golang.org/api/transport/doc.go | 11 + .../api/transport/grpc/dial.go | 328 + .../api/transport/grpc/dial_appengine.go | 32 + .../api/transport/grpc/dial_socketopt.go | 52 + .../api/transport/grpc/pool.go | 92 + .../transport/http/default_transport_go113.go | 20 - .../http/default_transport_not_go113.go | 15 - .../api/transport/http/dial.go | 39 +- .../api/transport/http/dial_appengine.go | 1 + .../http/internal/propagation/http.go | 1 + .../internal/socket/socket_service.pb.go | 2822 ++++ .../internal/socket/socket_service.proto | 460 + .../google.golang.org/appengine/socket/doc.go | 10 + .../appengine/socket/socket_classic.go | 290 + .../appengine/socket/socket_vm.go | 64 + .../api/annotations/annotations.pb.go | 11 +- .../googleapis/api/annotations/client.pb.go | 1679 ++- .../api/annotations/field_behavior.pb.go | 66 +- .../googleapis/api/annotations/http.pb.go | 195 +- .../googleapis/api/annotations/resource.pb.go | 188 +- .../googleapis/api/annotations/routing.pb.go | 693 + .../googleapis/api/launch_stage.pb.go | 203 + .../genproto/googleapis/iam/v1/alias.go | 208 + .../genproto/googleapis/iam/v1/policy.pb.go | 818 -- .../genproto/googleapis/rpc/code/code.pb.go | 35 +- .../rpc/errdetails/error_details.pb.go | 1314 ++ .../googleapis/rpc/status/status.pb.go | 17 +- .../genproto/googleapis/type/date/date.pb.go | 200 + .../genproto/googleapis/type/expr/expr.pb.go | 35 +- vendor/google.golang.org/grpc/.travis.yml | 42 - vendor/google.golang.org/grpc/CONTRIBUTING.md | 32 +- vendor/google.golang.org/grpc/MAINTAINERS.md | 5 +- vendor/google.golang.org/grpc/Makefile | 2 - vendor/google.golang.org/grpc/NOTICE.txt | 13 + vendor/google.golang.org/grpc/README.md | 2 +- .../grpc/attributes/attributes.go | 109 +- vendor/google.golang.org/grpc/backoff.go | 2 +- .../grpc/balancer/balancer.go | 152 +- .../grpc/balancer/base/balancer.go | 73 +- .../grpc/balancer/conn_state_evaluator.go | 74 + .../grpclb/grpc_lb_v1/load_balancer.pb.go | 957 ++ .../grpc_lb_v1/load_balancer_grpc.pb.go | 160 + .../grpc/balancer/grpclb/grpclb.go | 520 + .../grpc/balancer/grpclb/grpclb_config.go | 67 + .../grpc/balancer/grpclb/grpclb_picker.go | 202 + .../balancer/grpclb/grpclb_remote_balancer.go | 449 + .../grpc/balancer/grpclb/grpclb_util.go | 208 + .../grpc/balancer/grpclb/state/state.go | 2 +- .../grpc/balancer/roundrobin/roundrobin.go | 20 +- .../grpc/balancer_conn_wrappers.go | 475 +- .../grpc_binarylog_v1/binarylog.pb.go | 22 +- vendor/google.golang.org/grpc/call.go | 5 + .../grpc/channelz/channelz.go | 36 + vendor/google.golang.org/grpc/clientconn.go | 1356 +- .../grpc/codes/code_string.go | 51 +- .../grpc/connectivity/connectivity.go | 35 +- .../grpc/credentials/alts/alts.go | 332 + .../alts/internal/authinfo/authinfo.go | 95 + .../grpc/credentials/alts/internal/common.go | 67 + .../alts/internal/conn/aeadrekey.go | 131 + .../alts/internal/conn/aes128gcm.go | 105 + .../alts/internal/conn/aes128gcmrekey.go | 116 + .../credentials/alts/internal/conn/common.go | 70 + .../credentials/alts/internal/conn/counter.go | 62 + .../credentials/alts/internal/conn/record.go | 275 + .../credentials/alts/internal/conn/utils.go | 63 + .../alts/internal/handshaker/handshaker.go | 393 + .../internal/handshaker/service/service.go | 78 + .../internal/proto/grpc_gcp/altscontext.pb.go | 259 + .../internal/proto/grpc_gcp/handshaker.pb.go | 1423 ++ .../proto/grpc_gcp/handshaker_grpc.pb.go | 170 + .../grpc_gcp/transport_security_common.pb.go | 321 + .../grpc/credentials/alts/utils.go | 70 + .../grpc/credentials/credentials.go | 69 +- .../grpc/credentials/google/google.go | 145 + .../grpc/credentials/google/xds.go | 128 + .../grpc/credentials/insecure/insecure.go | 98 + .../grpc/credentials/oauth/oauth.go | 244 + .../google.golang.org/grpc/credentials/tls.go | 9 +- vendor/google.golang.org/grpc/dialoptions.go | 229 +- .../grpc/encoding/encoding.go | 9 +- .../grpc/grpclog/loggerv2.go | 103 +- vendor/google.golang.org/grpc/idle.go | 287 + vendor/google.golang.org/grpc/install_gae.sh | 6 - vendor/google.golang.org/grpc/interceptor.go | 9 +- .../balancer/gracefulswitch/gracefulswitch.go | 384 + .../grpc/internal/binarylog/binarylog.go | 118 +- .../grpc/internal/binarylog/env_config.go | 26 +- .../grpc/internal/binarylog/method_logger.go | 161 +- .../grpc/internal/binarylog/sink.go | 53 +- .../grpc/internal/buffer/unbounded.go | 26 +- .../grpc/internal/channelz/funcs.go | 240 +- .../grpc/internal/channelz/id.go | 75 + .../grpc/internal/channelz/logging.go | 91 +- .../grpc/internal/channelz/types.go | 39 +- .../grpc/internal/channelz/types_linux.go | 2 - .../grpc/internal/channelz/types_nonlinux.go | 5 +- .../grpc/internal/channelz/util_linux.go | 2 - .../grpc/internal/channelz/util_nonlinux.go | 3 +- .../grpc/internal/credentials/credentials.go | 49 + .../grpc/internal/credentials/spiffe.go | 2 - .../grpc/internal/credentials/syscallconn.go | 2 - .../grpc/internal/credentials/util.go | 4 +- .../grpc/internal/envconfig/envconfig.go | 46 +- .../grpc/internal/envconfig/observability.go | 42 + .../grpc/internal/envconfig/xds.go | 95 + .../grpc/internal/googlecloud/googlecloud.go | 72 + .../manufacturer.go} | 17 +- .../manufacturer_linux.go} | 17 +- .../googlecloud/manufacturer_windows.go | 50 + .../grpc/internal/grpclog/grpclog.go | 10 +- .../grpc/internal/grpclog/prefixLogger.go | 12 + .../grpc/internal/grpcrand/grpcrand.go | 50 +- .../internal/grpcsync/callback_serializer.go | 119 + .../go12.go => internal/grpcsync/oncefunc.go} | 22 +- .../grpc/internal/grpcutil/compressor.go | 47 + .../dns/go113.go => grpcutil/grpcutil.go} | 19 +- .../grpc/internal/grpcutil/method.go | 6 +- .../grpc/internal/grpcutil/regex.go | 31 + .../grpc/internal/grpcutil/target.go | 89 - .../grpc/internal/internal.go | 125 +- .../grpc/internal/metadata/metadata.go | 88 +- .../grpc/internal/pretty/pretty.go | 82 + .../grpc/internal/resolver/config_selector.go | 74 +- .../internal/resolver/dns/dns_resolver.go | 58 +- .../resolver/passthrough/passthrough.go | 11 +- .../grpc/internal/resolver/unix/unix.go | 21 +- .../grpc/internal/serviceconfig/duration.go | 130 + .../internal/serviceconfig/serviceconfig.go | 28 +- .../grpc/internal/status/status.go | 24 +- .../grpc/internal/syscall/syscall_linux.go | 2 - .../grpc/internal/syscall/syscall_nonlinux.go | 21 +- .../grpc/internal/transport/controlbuf.go | 197 +- .../grpc/internal/transport/defaults.go | 6 + .../grpc/internal/transport/flowcontrol.go | 4 +- .../grpc/internal/transport/handler_server.go | 81 +- .../grpc/internal/transport/http2_client.go | 689 +- .../grpc/internal/transport/http2_server.go | 598 +- .../grpc/internal/transport/http_util.go | 281 +- .../grpc/internal/transport/logging.go | 40 + .../transport/networktype/networktype.go | 4 +- .../grpc/internal/transport/proxy.go | 4 +- .../grpc/internal/transport/transport.go | 78 +- .../grpc/internal/xds_handshake_cluster.go | 40 + .../grpc/metadata/metadata.go | 174 +- .../google.golang.org/grpc/picker_wrapper.go | 77 +- vendor/google.golang.org/grpc/pickfirst.go | 181 +- vendor/google.golang.org/grpc/preloader.go | 2 +- .../grpc_reflection_v1alpha/reflection.pb.go | 447 +- .../grpc_reflection_v1alpha/reflection.proto | 138 - .../reflection_grpc.pb.go | 30 +- .../grpc/reflection/serverreflection.go | 478 +- vendor/google.golang.org/grpc/regenerate.sh | 54 +- vendor/google.golang.org/grpc/resolver/map.go | 138 + .../grpc/resolver/resolver.go | 112 +- .../grpc/resolver_conn_wrapper.go | 273 +- vendor/google.golang.org/grpc/rpc_util.go | 171 +- vendor/google.golang.org/grpc/server.go | 756 +- .../google.golang.org/grpc/service_config.go | 95 +- .../grpc/serviceconfig/serviceconfig.go | 2 +- vendor/google.golang.org/grpc/stats/stats.go | 33 +- .../google.golang.org/grpc/status/status.go | 83 +- vendor/google.golang.org/grpc/stream.go | 662 +- vendor/google.golang.org/grpc/tap/tap.go | 18 +- vendor/google.golang.org/grpc/version.go | 2 +- vendor/google.golang.org/grpc/vet.sh | 114 +- .../cmd/protoc-gen-go/internal_gengo/init.go | 168 - .../cmd/protoc-gen-go/internal_gengo/main.go | 904 -- .../protoc-gen-go/internal_gengo/reflect.go | 372 - .../internal_gengo/well_known_types.go | 1079 -- .../protobuf/compiler/protogen/protogen.go | 1391 -- .../protobuf/encoding/protojson/decode.go | 685 + .../protobuf/encoding/protojson/doc.go | 11 + .../protobuf/encoding/protojson/encode.go | 378 + .../encoding/protojson/well_known_types.go | 876 ++ .../protobuf/internal/encoding/json/decode.go | 340 + .../internal/encoding/json/decode_number.go | 254 + .../internal/encoding/json/decode_string.go | 91 + .../internal/encoding/json/decode_token.go | 192 + .../protobuf/internal/encoding/json/encode.go | 278 + .../protobuf/internal/msgfmt/format.go | 261 - .../protobuf/reflect/protopath/path.go | 122 - .../protobuf/reflect/protopath/step.go | 241 - .../protobuf/reflect/protorange/range.go | 316 - .../protobuf/types/dynamicpb/dynamic.go | 718 - .../protobuf/types/dynamicpb/types.go | 184 - .../protobuf/types/known/emptypb/empty.pb.go | 166 + .../types/known/fieldmaskpb/field_mask.pb.go | 588 + .../protobuf/types/pluginpb/plugin.pb.go | 690 - vendor/knative.dev/hack/OWNERS | 8 + vendor/knative.dev/hack/OWNERS_ALIASES | 140 + vendor/modules.txt | 142 +- 468 files changed, 66149 insertions(+), 51198 deletions(-) delete mode 100644 vendor/cloud.google.com/go/.gitignore delete mode 100644 vendor/cloud.google.com/go/CHANGES.md delete mode 100644 vendor/cloud.google.com/go/CODE_OF_CONDUCT.md delete mode 100644 vendor/cloud.google.com/go/CONTRIBUTING.md delete mode 100644 vendor/cloud.google.com/go/README.md delete mode 100644 vendor/cloud.google.com/go/RELEASING.md create mode 100644 vendor/cloud.google.com/go/compute/LICENSE create mode 100644 vendor/cloud.google.com/go/compute/internal/version.go create mode 100644 vendor/cloud.google.com/go/compute/metadata/CHANGES.md create mode 100644 vendor/cloud.google.com/go/compute/metadata/LICENSE create mode 100644 vendor/cloud.google.com/go/compute/metadata/README.md create mode 100644 vendor/cloud.google.com/go/compute/metadata/retry.go create mode 100644 vendor/cloud.google.com/go/compute/metadata/retry_linux.go rename vendor/cloud.google.com/go/{storage/go_mod_tidy_hack.go => compute/metadata/tidyfix.go} (80%) delete mode 100644 vendor/cloud.google.com/go/doc.go create mode 100644 vendor/cloud.google.com/go/iam/CHANGES.md create mode 100644 vendor/cloud.google.com/go/iam/LICENSE create mode 100644 vendor/cloud.google.com/go/iam/README.md rename vendor/{google.golang.org/genproto/googleapis/iam/v1 => cloud.google.com/go/iam/apiv1/iampb}/iam_policy.pb.go (85%) rename vendor/{google.golang.org/genproto/googleapis/iam/v1 => cloud.google.com/go/iam/apiv1/iampb}/options.pb.go (70%) create mode 100644 vendor/cloud.google.com/go/iam/apiv1/iampb/policy.pb.go create mode 100644 vendor/cloud.google.com/go/internal/cloudbuild.yaml create mode 100644 vendor/cloud.google.com/go/storage/client.go create mode 100644 vendor/cloud.google.com/go/storage/emulator_test.sh delete mode 100644 vendor/cloud.google.com/go/storage/go110.go create mode 100644 vendor/cloud.google.com/go/storage/grpc_client.go create mode 100644 vendor/cloud.google.com/go/storage/http_client.go create mode 100644 vendor/cloud.google.com/go/storage/internal/apiv2/doc.go create mode 100644 vendor/cloud.google.com/go/storage/internal/apiv2/gapic_metadata.json create mode 100644 vendor/cloud.google.com/go/storage/internal/apiv2/metadata.go create mode 100644 vendor/cloud.google.com/go/storage/internal/apiv2/storage_client.go create mode 100644 vendor/cloud.google.com/go/storage/internal/apiv2/stubs/storage.pb.go create mode 100644 vendor/cloud.google.com/go/storage/internal/apiv2/version.go create mode 100644 vendor/cloud.google.com/go/storage/internal/version.go delete mode 100644 vendor/cloud.google.com/go/storage/not_go110.go delete mode 100644 vendor/cloud.google.com/go/testing.md delete mode 100644 vendor/cloud.google.com/go/tools.go delete mode 100644 vendor/github.com/golang/protobuf/internal/gengogrpc/grpc.go create mode 100644 vendor/github.com/golang/protobuf/jsonpb/decode.go create mode 100644 vendor/github.com/golang/protobuf/jsonpb/encode.go create mode 100644 vendor/github.com/golang/protobuf/jsonpb/json.go delete mode 100644 vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.pb.go delete mode 100644 vendor/github.com/golang/protobuf/protoc-gen-go/main.go rename vendor/{golang.org/x/lint => github.com/google/go-cmp}/LICENSE (96%) create mode 100644 vendor/github.com/google/go-cmp/cmp/compare.go create mode 100644 vendor/github.com/google/go-cmp/cmp/export_panic.go create mode 100644 vendor/github.com/google/go-cmp/cmp/export_unsafe.go create mode 100644 vendor/github.com/google/go-cmp/cmp/internal/diff/debug_disable.go create mode 100644 vendor/github.com/google/go-cmp/cmp/internal/diff/debug_enable.go create mode 100644 vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go create mode 100644 vendor/github.com/google/go-cmp/cmp/internal/flags/flags.go create mode 100644 vendor/github.com/google/go-cmp/cmp/internal/function/func.go create mode 100644 vendor/github.com/google/go-cmp/cmp/internal/value/name.go create mode 100644 vendor/github.com/google/go-cmp/cmp/internal/value/pointer_purego.go create mode 100644 vendor/github.com/google/go-cmp/cmp/internal/value/pointer_unsafe.go create mode 100644 vendor/github.com/google/go-cmp/cmp/internal/value/sort.go create mode 100644 vendor/github.com/google/go-cmp/cmp/options.go create mode 100644 vendor/github.com/google/go-cmp/cmp/path.go create mode 100644 vendor/github.com/google/go-cmp/cmp/report.go create mode 100644 vendor/github.com/google/go-cmp/cmp/report_compare.go create mode 100644 vendor/github.com/google/go-cmp/cmp/report_references.go create mode 100644 vendor/github.com/google/go-cmp/cmp/report_reflect.go create mode 100644 vendor/github.com/google/go-cmp/cmp/report_slices.go create mode 100644 vendor/github.com/google/go-cmp/cmp/report_text.go create mode 100644 vendor/github.com/google/go-cmp/cmp/report_value.go create mode 100644 vendor/github.com/google/uuid/null.go create mode 100644 vendor/github.com/googleapis/enterprise-certificate-proxy/LICENSE create mode 100644 vendor/github.com/googleapis/enterprise-certificate-proxy/client/client.go create mode 100644 vendor/github.com/googleapis/enterprise-certificate-proxy/client/util/util.go create mode 100644 vendor/github.com/googleapis/gax-go/v2/.release-please-manifest.json create mode 100644 vendor/github.com/googleapis/gax-go/v2/CHANGES.md create mode 100644 vendor/github.com/googleapis/gax-go/v2/apierror/apierror.go create mode 100644 vendor/github.com/googleapis/gax-go/v2/apierror/internal/proto/README.md create mode 100644 vendor/github.com/googleapis/gax-go/v2/apierror/internal/proto/custom_error.pb.go create mode 100644 vendor/github.com/googleapis/gax-go/v2/apierror/internal/proto/custom_error.proto create mode 100644 vendor/github.com/googleapis/gax-go/v2/apierror/internal/proto/error.pb.go create mode 100644 vendor/github.com/googleapis/gax-go/v2/apierror/internal/proto/error.proto create mode 100644 vendor/github.com/googleapis/gax-go/v2/content_type.go create mode 100644 vendor/github.com/googleapis/gax-go/v2/internal/version.go create mode 100644 vendor/github.com/googleapis/gax-go/v2/proto_json_stream.go create mode 100644 vendor/github.com/googleapis/gax-go/v2/release-please-config.json delete mode 100644 vendor/github.com/jstemmer/go-junit-report/.gitignore delete mode 100644 vendor/github.com/jstemmer/go-junit-report/.travis.yml delete mode 100644 vendor/github.com/jstemmer/go-junit-report/LICENSE delete mode 100644 vendor/github.com/jstemmer/go-junit-report/README.md delete mode 100644 vendor/github.com/jstemmer/go-junit-report/formatter/formatter.go delete mode 100644 vendor/github.com/jstemmer/go-junit-report/go-junit-report.go delete mode 100644 vendor/github.com/jstemmer/go-junit-report/parser/parser.go create mode 100644 vendor/go.opencensus.io/plugin/ocgrpc/client.go create mode 100644 vendor/go.opencensus.io/plugin/ocgrpc/client_metrics.go create mode 100644 vendor/go.opencensus.io/plugin/ocgrpc/client_stats_handler.go create mode 100644 vendor/go.opencensus.io/plugin/ocgrpc/doc.go create mode 100644 vendor/go.opencensus.io/plugin/ocgrpc/server.go create mode 100644 vendor/go.opencensus.io/plugin/ocgrpc/server_metrics.go create mode 100644 vendor/go.opencensus.io/plugin/ocgrpc/server_stats_handler.go create mode 100644 vendor/go.opencensus.io/plugin/ocgrpc/stats_common.go create mode 100644 vendor/go.opencensus.io/plugin/ocgrpc/trace_common.go delete mode 100644 vendor/golang.org/x/lint/.travis.yml delete mode 100644 vendor/golang.org/x/lint/CONTRIBUTING.md delete mode 100644 vendor/golang.org/x/lint/README.md delete mode 100644 vendor/golang.org/x/lint/golint/golint.go delete mode 100644 vendor/golang.org/x/lint/golint/import.go delete mode 100644 vendor/golang.org/x/lint/golint/importcomment.go delete mode 100644 vendor/golang.org/x/lint/lint.go delete mode 100644 vendor/golang.org/x/mod/internal/lazyregexp/lazyre.go delete mode 100644 vendor/golang.org/x/mod/module/module.go delete mode 100644 vendor/golang.org/x/mod/module/pseudo.go delete mode 100644 vendor/golang.org/x/mod/semver/semver.go delete mode 100644 vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go delete mode 100644 vendor/golang.org/x/oauth2/AUTHORS delete mode 100644 vendor/golang.org/x/oauth2/CONTRIBUTORS create mode 100644 vendor/golang.org/x/oauth2/authhandler/authhandler.go create mode 100644 vendor/golang.org/x/oauth2/google/error.go create mode 100644 vendor/golang.org/x/oauth2/google/internal/externalaccount/aws.go create mode 100644 vendor/golang.org/x/oauth2/google/internal/externalaccount/basecredentials.go create mode 100644 vendor/golang.org/x/oauth2/google/internal/externalaccount/clientauth.go create mode 100644 vendor/golang.org/x/oauth2/google/internal/externalaccount/err.go create mode 100644 vendor/golang.org/x/oauth2/google/internal/externalaccount/executablecredsource.go create mode 100644 vendor/golang.org/x/oauth2/google/internal/externalaccount/filecredsource.go create mode 100644 vendor/golang.org/x/oauth2/google/internal/externalaccount/impersonate.go create mode 100644 vendor/golang.org/x/oauth2/google/internal/externalaccount/sts_exchange.go create mode 100644 vendor/golang.org/x/oauth2/google/internal/externalaccount/urlcredsource.go delete mode 100644 vendor/golang.org/x/sys/execabs/execabs.go delete mode 100644 vendor/golang.org/x/sys/execabs/execabs_go118.go delete mode 100644 vendor/golang.org/x/sys/execabs/execabs_go119.go delete mode 100644 vendor/golang.org/x/tools/LICENSE delete mode 100644 vendor/golang.org/x/tools/PATENTS delete mode 100644 vendor/golang.org/x/tools/cmd/goimports/doc.go delete mode 100644 vendor/golang.org/x/tools/cmd/goimports/goimports.go delete mode 100644 vendor/golang.org/x/tools/cmd/goimports/goimports_gc.go delete mode 100644 vendor/golang.org/x/tools/cmd/goimports/goimports_not_gc.go delete mode 100644 vendor/golang.org/x/tools/go/ast/astutil/enclosing.go delete mode 100644 vendor/golang.org/x/tools/go/ast/astutil/imports.go delete mode 100644 vendor/golang.org/x/tools/go/ast/astutil/rewrite.go delete mode 100644 vendor/golang.org/x/tools/go/ast/astutil/util.go delete mode 100644 vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go delete mode 100644 vendor/golang.org/x/tools/go/gcexportdata/importer.go delete mode 100644 vendor/golang.org/x/tools/internal/event/core/event.go delete mode 100644 vendor/golang.org/x/tools/internal/event/core/export.go delete mode 100644 vendor/golang.org/x/tools/internal/event/core/fast.go delete mode 100644 vendor/golang.org/x/tools/internal/event/doc.go delete mode 100644 vendor/golang.org/x/tools/internal/event/event.go delete mode 100644 vendor/golang.org/x/tools/internal/event/keys/keys.go delete mode 100644 vendor/golang.org/x/tools/internal/event/keys/standard.go delete mode 100644 vendor/golang.org/x/tools/internal/event/label/label.go delete mode 100644 vendor/golang.org/x/tools/internal/fastwalk/fastwalk.go delete mode 100644 vendor/golang.org/x/tools/internal/fastwalk/fastwalk_darwin.go delete mode 100644 vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_fileno.go delete mode 100644 vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_ino.go delete mode 100644 vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_bsd.go delete mode 100644 vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_linux.go delete mode 100644 vendor/golang.org/x/tools/internal/fastwalk/fastwalk_portable.go delete mode 100644 vendor/golang.org/x/tools/internal/fastwalk/fastwalk_unix.go delete mode 100644 vendor/golang.org/x/tools/internal/gcimporter/bexport.go delete mode 100644 vendor/golang.org/x/tools/internal/gcimporter/bimport.go delete mode 100644 vendor/golang.org/x/tools/internal/gcimporter/exportdata.go delete mode 100644 vendor/golang.org/x/tools/internal/gcimporter/gcimporter.go delete mode 100644 vendor/golang.org/x/tools/internal/gcimporter/iexport.go delete mode 100644 vendor/golang.org/x/tools/internal/gcimporter/iimport.go delete mode 100644 vendor/golang.org/x/tools/internal/gcimporter/newInterface10.go delete mode 100644 vendor/golang.org/x/tools/internal/gcimporter/newInterface11.go delete mode 100644 vendor/golang.org/x/tools/internal/gcimporter/support_go117.go delete mode 100644 vendor/golang.org/x/tools/internal/gcimporter/support_go118.go delete mode 100644 vendor/golang.org/x/tools/internal/gcimporter/unified_no.go delete mode 100644 vendor/golang.org/x/tools/internal/gcimporter/unified_yes.go delete mode 100644 vendor/golang.org/x/tools/internal/gcimporter/ureader_no.go delete mode 100644 vendor/golang.org/x/tools/internal/gcimporter/ureader_yes.go delete mode 100644 vendor/golang.org/x/tools/internal/gocommand/invoke.go delete mode 100644 vendor/golang.org/x/tools/internal/gocommand/vendor.go delete mode 100644 vendor/golang.org/x/tools/internal/gocommand/version.go delete mode 100644 vendor/golang.org/x/tools/internal/gopathwalk/walk.go delete mode 100644 vendor/golang.org/x/tools/internal/imports/fix.go delete mode 100644 vendor/golang.org/x/tools/internal/imports/imports.go delete mode 100644 vendor/golang.org/x/tools/internal/imports/mod.go delete mode 100644 vendor/golang.org/x/tools/internal/imports/mod_cache.go delete mode 100644 vendor/golang.org/x/tools/internal/imports/sortimports.go delete mode 100644 vendor/golang.org/x/tools/internal/imports/zstdlib.go delete mode 100644 vendor/golang.org/x/tools/internal/pkgbits/codes.go delete mode 100644 vendor/golang.org/x/tools/internal/pkgbits/decoder.go delete mode 100644 vendor/golang.org/x/tools/internal/pkgbits/doc.go delete mode 100644 vendor/golang.org/x/tools/internal/pkgbits/encoder.go delete mode 100644 vendor/golang.org/x/tools/internal/pkgbits/flags.go delete mode 100644 vendor/golang.org/x/tools/internal/pkgbits/frames_go1.go delete mode 100644 vendor/golang.org/x/tools/internal/pkgbits/frames_go17.go delete mode 100644 vendor/golang.org/x/tools/internal/pkgbits/reloc.go delete mode 100644 vendor/golang.org/x/tools/internal/pkgbits/support.go delete mode 100644 vendor/golang.org/x/tools/internal/pkgbits/sync.go delete mode 100644 vendor/golang.org/x/tools/internal/pkgbits/syncmarker_string.go delete mode 100644 vendor/golang.org/x/tools/internal/tokeninternal/tokeninternal.go delete mode 100644 vendor/golang.org/x/tools/internal/typeparams/common.go delete mode 100644 vendor/golang.org/x/tools/internal/typeparams/coretype.go delete mode 100644 vendor/golang.org/x/tools/internal/typeparams/enabled_go117.go delete mode 100644 vendor/golang.org/x/tools/internal/typeparams/enabled_go118.go delete mode 100644 vendor/golang.org/x/tools/internal/typeparams/normalize.go delete mode 100644 vendor/golang.org/x/tools/internal/typeparams/termlist.go delete mode 100644 vendor/golang.org/x/tools/internal/typeparams/typeparams_go117.go delete mode 100644 vendor/golang.org/x/tools/internal/typeparams/typeparams_go118.go delete mode 100644 vendor/golang.org/x/tools/internal/typeparams/typeterm.go rename vendor/golang.org/x/{mod => xerrors}/LICENSE (96%) rename vendor/golang.org/x/{mod => xerrors}/PATENTS (100%) create mode 100644 vendor/golang.org/x/xerrors/README create mode 100644 vendor/golang.org/x/xerrors/adaptor.go create mode 100644 vendor/golang.org/x/xerrors/codereview.cfg create mode 100644 vendor/golang.org/x/xerrors/doc.go create mode 100644 vendor/golang.org/x/xerrors/errors.go create mode 100644 vendor/golang.org/x/xerrors/fmt.go create mode 100644 vendor/golang.org/x/xerrors/format.go create mode 100644 vendor/golang.org/x/xerrors/frame.go create mode 100644 vendor/golang.org/x/xerrors/internal/internal.go create mode 100644 vendor/golang.org/x/xerrors/wrap.go create mode 100644 vendor/google.golang.org/api/iamcredentials/v1/iamcredentials-api.json create mode 100644 vendor/google.golang.org/api/iamcredentials/v1/iamcredentials-gen.go create mode 100644 vendor/google.golang.org/api/internal/cert/default_cert.go create mode 100644 vendor/google.golang.org/api/internal/cert/enterprise_cert.go rename vendor/google.golang.org/api/{transport/cert/default_cert.go => internal/cert/secureconnect_cert.go} (55%) rename vendor/google.golang.org/api/{transport/internal/dca => internal}/dca.go (78%) create mode 100644 vendor/google.golang.org/api/internal/gensupport/error.go create mode 100644 vendor/google.golang.org/api/internal/gensupport/retry.go create mode 100644 vendor/google.golang.org/api/internal/version.go delete mode 100644 vendor/google.golang.org/api/option/credentials_go19.go delete mode 100644 vendor/google.golang.org/api/option/credentials_notgo19.go create mode 100644 vendor/google.golang.org/api/transport/dial.go create mode 100644 vendor/google.golang.org/api/transport/doc.go create mode 100644 vendor/google.golang.org/api/transport/grpc/dial.go create mode 100644 vendor/google.golang.org/api/transport/grpc/dial_appengine.go create mode 100644 vendor/google.golang.org/api/transport/grpc/dial_socketopt.go create mode 100644 vendor/google.golang.org/api/transport/grpc/pool.go delete mode 100644 vendor/google.golang.org/api/transport/http/default_transport_go113.go delete mode 100644 vendor/google.golang.org/api/transport/http/default_transport_not_go113.go create mode 100644 vendor/google.golang.org/appengine/internal/socket/socket_service.pb.go create mode 100644 vendor/google.golang.org/appengine/internal/socket/socket_service.proto create mode 100644 vendor/google.golang.org/appengine/socket/doc.go create mode 100644 vendor/google.golang.org/appengine/socket/socket_classic.go create mode 100644 vendor/google.golang.org/appengine/socket/socket_vm.go create mode 100644 vendor/google.golang.org/genproto/googleapis/api/annotations/routing.pb.go create mode 100644 vendor/google.golang.org/genproto/googleapis/api/launch_stage.pb.go create mode 100644 vendor/google.golang.org/genproto/googleapis/iam/v1/alias.go delete mode 100644 vendor/google.golang.org/genproto/googleapis/iam/v1/policy.pb.go create mode 100644 vendor/google.golang.org/genproto/googleapis/rpc/errdetails/error_details.pb.go create mode 100644 vendor/google.golang.org/genproto/googleapis/type/date/date.pb.go delete mode 100644 vendor/google.golang.org/grpc/.travis.yml create mode 100644 vendor/google.golang.org/grpc/NOTICE.txt create mode 100644 vendor/google.golang.org/grpc/balancer/conn_state_evaluator.go create mode 100644 vendor/google.golang.org/grpc/balancer/grpclb/grpc_lb_v1/load_balancer.pb.go create mode 100644 vendor/google.golang.org/grpc/balancer/grpclb/grpc_lb_v1/load_balancer_grpc.pb.go create mode 100644 vendor/google.golang.org/grpc/balancer/grpclb/grpclb.go create mode 100644 vendor/google.golang.org/grpc/balancer/grpclb/grpclb_config.go create mode 100644 vendor/google.golang.org/grpc/balancer/grpclb/grpclb_picker.go create mode 100644 vendor/google.golang.org/grpc/balancer/grpclb/grpclb_remote_balancer.go create mode 100644 vendor/google.golang.org/grpc/balancer/grpclb/grpclb_util.go create mode 100644 vendor/google.golang.org/grpc/channelz/channelz.go create mode 100644 vendor/google.golang.org/grpc/credentials/alts/alts.go create mode 100644 vendor/google.golang.org/grpc/credentials/alts/internal/authinfo/authinfo.go create mode 100644 vendor/google.golang.org/grpc/credentials/alts/internal/common.go create mode 100644 vendor/google.golang.org/grpc/credentials/alts/internal/conn/aeadrekey.go create mode 100644 vendor/google.golang.org/grpc/credentials/alts/internal/conn/aes128gcm.go create mode 100644 vendor/google.golang.org/grpc/credentials/alts/internal/conn/aes128gcmrekey.go create mode 100644 vendor/google.golang.org/grpc/credentials/alts/internal/conn/common.go create mode 100644 vendor/google.golang.org/grpc/credentials/alts/internal/conn/counter.go create mode 100644 vendor/google.golang.org/grpc/credentials/alts/internal/conn/record.go create mode 100644 vendor/google.golang.org/grpc/credentials/alts/internal/conn/utils.go create mode 100644 vendor/google.golang.org/grpc/credentials/alts/internal/handshaker/handshaker.go create mode 100644 vendor/google.golang.org/grpc/credentials/alts/internal/handshaker/service/service.go create mode 100644 vendor/google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp/altscontext.pb.go create mode 100644 vendor/google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp/handshaker.pb.go create mode 100644 vendor/google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp/handshaker_grpc.pb.go create mode 100644 vendor/google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp/transport_security_common.pb.go create mode 100644 vendor/google.golang.org/grpc/credentials/alts/utils.go create mode 100644 vendor/google.golang.org/grpc/credentials/google/google.go create mode 100644 vendor/google.golang.org/grpc/credentials/google/xds.go create mode 100644 vendor/google.golang.org/grpc/credentials/insecure/insecure.go create mode 100644 vendor/google.golang.org/grpc/credentials/oauth/oauth.go create mode 100644 vendor/google.golang.org/grpc/idle.go delete mode 100644 vendor/google.golang.org/grpc/install_gae.sh create mode 100644 vendor/google.golang.org/grpc/internal/balancer/gracefulswitch/gracefulswitch.go create mode 100644 vendor/google.golang.org/grpc/internal/channelz/id.go create mode 100644 vendor/google.golang.org/grpc/internal/credentials/credentials.go create mode 100644 vendor/google.golang.org/grpc/internal/envconfig/observability.go create mode 100644 vendor/google.golang.org/grpc/internal/envconfig/xds.go create mode 100644 vendor/google.golang.org/grpc/internal/googlecloud/googlecloud.go rename vendor/google.golang.org/grpc/internal/{credentials/spiffe_appengine.go => googlecloud/manufacturer.go} (70%) rename vendor/google.golang.org/grpc/internal/{credentials/syscallconn_appengine.go => googlecloud/manufacturer_linux.go} (72%) create mode 100644 vendor/google.golang.org/grpc/internal/googlecloud/manufacturer_windows.go create mode 100644 vendor/google.golang.org/grpc/internal/grpcsync/callback_serializer.go rename vendor/google.golang.org/grpc/{credentials/go12.go => internal/grpcsync/oncefunc.go} (58%) create mode 100644 vendor/google.golang.org/grpc/internal/grpcutil/compressor.go rename vendor/google.golang.org/grpc/internal/{resolver/dns/go113.go => grpcutil/grpcutil.go} (67%) create mode 100644 vendor/google.golang.org/grpc/internal/grpcutil/regex.go delete mode 100644 vendor/google.golang.org/grpc/internal/grpcutil/target.go create mode 100644 vendor/google.golang.org/grpc/internal/pretty/pretty.go create mode 100644 vendor/google.golang.org/grpc/internal/serviceconfig/duration.go create mode 100644 vendor/google.golang.org/grpc/internal/transport/logging.go create mode 100644 vendor/google.golang.org/grpc/internal/xds_handshake_cluster.go delete mode 100644 vendor/google.golang.org/grpc/reflection/grpc_reflection_v1alpha/reflection.proto create mode 100644 vendor/google.golang.org/grpc/resolver/map.go delete mode 100644 vendor/google.golang.org/protobuf/cmd/protoc-gen-go/internal_gengo/init.go delete mode 100644 vendor/google.golang.org/protobuf/cmd/protoc-gen-go/internal_gengo/main.go delete mode 100644 vendor/google.golang.org/protobuf/cmd/protoc-gen-go/internal_gengo/reflect.go delete mode 100644 vendor/google.golang.org/protobuf/cmd/protoc-gen-go/internal_gengo/well_known_types.go delete mode 100644 vendor/google.golang.org/protobuf/compiler/protogen/protogen.go create mode 100644 vendor/google.golang.org/protobuf/encoding/protojson/decode.go create mode 100644 vendor/google.golang.org/protobuf/encoding/protojson/doc.go create mode 100644 vendor/google.golang.org/protobuf/encoding/protojson/encode.go create mode 100644 vendor/google.golang.org/protobuf/encoding/protojson/well_known_types.go create mode 100644 vendor/google.golang.org/protobuf/internal/encoding/json/decode.go create mode 100644 vendor/google.golang.org/protobuf/internal/encoding/json/decode_number.go create mode 100644 vendor/google.golang.org/protobuf/internal/encoding/json/decode_string.go create mode 100644 vendor/google.golang.org/protobuf/internal/encoding/json/decode_token.go create mode 100644 vendor/google.golang.org/protobuf/internal/encoding/json/encode.go delete mode 100644 vendor/google.golang.org/protobuf/internal/msgfmt/format.go delete mode 100644 vendor/google.golang.org/protobuf/reflect/protopath/path.go delete mode 100644 vendor/google.golang.org/protobuf/reflect/protopath/step.go delete mode 100644 vendor/google.golang.org/protobuf/reflect/protorange/range.go delete mode 100644 vendor/google.golang.org/protobuf/types/dynamicpb/dynamic.go delete mode 100644 vendor/google.golang.org/protobuf/types/dynamicpb/types.go create mode 100644 vendor/google.golang.org/protobuf/types/known/emptypb/empty.pb.go create mode 100644 vendor/google.golang.org/protobuf/types/known/fieldmaskpb/field_mask.pb.go delete mode 100644 vendor/google.golang.org/protobuf/types/pluginpb/plugin.pb.go create mode 100644 vendor/knative.dev/hack/OWNERS create mode 100644 vendor/knative.dev/hack/OWNERS_ALIASES diff --git a/go.mod b/go.mod index a359806c4ad..81f4e959eff 100644 --- a/go.mod +++ b/go.mod @@ -3,43 +3,46 @@ module github.com/knative/docs go 1.21 require ( - cloud.google.com/go/storage v1.10.0 + cloud.google.com/go/storage v1.28.1 github.com/cloudevents/sdk-go/v2 v2.15.2 github.com/golang/protobuf v1.5.4 github.com/google/go-github v17.0.0+incompatible github.com/google/go-github/v32 v32.1.0 github.com/kelseyhightower/envconfig v1.4.0 golang.org/x/net v0.23.0 - golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5 - google.golang.org/grpc v1.36.0 + golang.org/x/oauth2 v0.7.0 + google.golang.org/grpc v1.56.3 gopkg.in/go-playground/webhooks.v3 v3.13.0 gopkg.in/yaml.v2 v2.3.0 knative.dev/hack v0.0.0-20240801232131-441a19fc9ead ) require ( - cloud.google.com/go v0.72.0 // indirect + cloud.google.com/go v0.110.0 // indirect + cloud.google.com/go/compute v1.19.1 // indirect + cloud.google.com/go/compute/metadata v0.2.3 // indirect + cloud.google.com/go/iam v0.13.0 // indirect + github.com/google/go-cmp v0.5.9 // indirect github.com/google/go-querystring v1.0.0 // indirect - github.com/google/uuid v1.2.0 // indirect - github.com/googleapis/gax-go/v2 v2.0.5 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect + github.com/googleapis/gax-go/v2 v2.7.1 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/json-iterator/go v1.1.10 // indirect - github.com/jstemmer/go-junit-report v0.9.1 // indirect github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect - go.opencensus.io v0.23.0 // indirect + go.opencensus.io v0.24.0 // indirect go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.16.0 // indirect golang.org/x/crypto v0.21.0 // indirect golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect - golang.org/x/mod v0.8.0 // indirect golang.org/x/sys v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect - golang.org/x/tools v0.6.0 // indirect - google.golang.org/api v0.36.0 // indirect + golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect + google.golang.org/api v0.114.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d // indirect + google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/go-playground/assert.v1 v1.2.1 // indirect honnef.co/go/tools v0.0.1-2020.1.5 // indirect diff --git a/go.sum b/go.sum index ae6236712f1..9e3b4a10a27 100644 --- a/go.sum +++ b/go.sum @@ -1,117 +1,51 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.72.0 h1:eWRCuwubtDrCJG0oSUMgnsbD4CmPFQF2ei4OFbXvwww= -cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0 h1:STgFzyU5/8miMl0//zKh2aQeTyeaUH3WN9bSUiJ09bA= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +cloud.google.com/go v0.110.0 h1:Zc8gqp3+a9/Eyph2KDmcGaPtbKRIoqq4YTlL4NMD0Ys= +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go/compute v1.19.1 h1:am86mquDUgjGNWxiGn+5PGLbmgiWXlE/yNWpIpNvuXY= +cloud.google.com/go/compute v1.19.1/go.mod h1:6ylj3a05WF8leseCdIf77NK0g1ey+nj5IKd5/kvShxE= +cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/iam v0.13.0 h1:+CmB+K0J/33d0zSQ9SlFWUeCCEn5XJA0ZMZ3pHE9u8k= +cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= +cloud.google.com/go/longrunning v0.4.1 h1:v+yFJOfKC3yZdY6ZUI933pIYdhyhV8S3NpWrXWmg7jM= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/storage v1.28.1 h1:F5QDG5ChchaAVQhINh24U99OWHURqrW8OmQcGKXcbgI= +cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= 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/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -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/cloudevents/sdk-go/v2 v2.15.2 h1:54+I5xQEnI73RBhWHxbI1XJcqOFOVJN85vb41+8mHUc= github.com/cloudevents/sdk-go/v2 v2.15.2/go.mod h1:lL7kSWAE/V8VI4Wh0jbL2v/jvqsm6tjmaQBSvxcv4uE= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 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/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/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.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/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-github/v32 v32.1.0 h1:GWkQOdXqviCPx7Q7Fj+KyPoGm4SwHRh8rheoPhd27II= @@ -119,40 +53,23 @@ github.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3 github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.1.0 h1:wCKgOCHuUEVfsaQLpPSJb7VdYCdTVZQAuOdYm1yc/60= -github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= +github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= -github.com/google/uuid v1.2.0/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 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k= +github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +github.com/googleapis/gax-go/v2 v2.7.1 h1:gF4c0zjUP2H/s/hEGyLA3I0fA2ZWjzYiONAD6cvPr8A= +github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -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 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= @@ -187,7 +104,6 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -199,15 +115,10 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.opencensus.io v0.20.2 h1:NAfh7zF0/3/HqtMvJNZ/RFrSlCE6ZTlHmKfhL/Dm1Jk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -222,42 +133,18 @@ go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/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-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -269,93 +156,32 @@ golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= 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-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5 h1:Lm4OryKCca1vehdsWogr9N4t7NfZxLbJoc/H0w4K4S4= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g= +golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sync v0.1.0/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-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/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-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/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= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 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/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -363,142 +189,33 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0 h1:l2Nfbl2GPXdWorv+dT2XfinX2jOOw4zv1VhLstx+6rE= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.114.0 h1:1xQPji6cO2E2vLiI+C/XiFAnsn1WV3mjaEwGLhi3grE= +google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-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-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d h1:HV9Z9qMhQEsdlvxNFELgQ11RkMzO3CMkjEySjCtuLes= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= +google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.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.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.36.0 h1:o1bcQ6imQMIOpdrO3SWf2z5RV72WbDwdXuK0MDlc8As= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/grpc v1.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc= +google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= @@ -521,16 +238,8 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.5 h1:nI5egYTGJakVyOryqLs1cQO5dO0ksin5XXs2pspk75k= honnef.co/go/tools v0.0.1-2020.1.5/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= knative.dev/hack v0.0.0-20240801232131-441a19fc9ead h1:ViH1OEO0LViKa6W61YKUpLzOp7CJCFL9yLyIojHIuQ8= knative.dev/hack v0.0.0-20240801232131-441a19fc9ead/go.mod h1:R0ritgYtjLDO9527h5vb5X6gfvt5LCrJ55BNbVDsWiY= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/vendor/cloud.google.com/go/.gitignore b/vendor/cloud.google.com/go/.gitignore deleted file mode 100644 index cc7e53b46c0..00000000000 --- a/vendor/cloud.google.com/go/.gitignore +++ /dev/null @@ -1,12 +0,0 @@ -# Editors -.idea -.vscode -*.swp -.history - -# Test files -*.test -coverage.txt - -# Other -.DS_Store diff --git a/vendor/cloud.google.com/go/CHANGES.md b/vendor/cloud.google.com/go/CHANGES.md deleted file mode 100644 index 4c762e636bd..00000000000 --- a/vendor/cloud.google.com/go/CHANGES.md +++ /dev/null @@ -1,1762 +0,0 @@ -# Changes - - -## [0.72.0](https://www.github.com/googleapis/google-cloud-go/compare/v0.71.0...v0.72.0) (2020-11-10) - - -### Features - -* **all:** auto-regenerate gapics , refs [#3177](https://www.github.com/googleapis/google-cloud-go/issues/3177) [#3164](https://www.github.com/googleapis/google-cloud-go/issues/3164) [#3149](https://www.github.com/googleapis/google-cloud-go/issues/3149) [#3142](https://www.github.com/googleapis/google-cloud-go/issues/3142) [#3136](https://www.github.com/googleapis/google-cloud-go/issues/3136) [#3130](https://www.github.com/googleapis/google-cloud-go/issues/3130) [#3121](https://www.github.com/googleapis/google-cloud-go/issues/3121) [#3119](https://www.github.com/googleapis/google-cloud-go/issues/3119) - - -### Bug Fixes - -* **all:** Update hand-written clients to not use WithEndpoint override ([#3111](https://www.github.com/googleapis/google-cloud-go/issues/3111)) ([f0cfd05](https://www.github.com/googleapis/google-cloud-go/commit/f0cfd0532f5204ff16f7bae406efa72603d16f44)) -* **internal/godocfx:** rename README files to pkg-readme ([#3185](https://www.github.com/googleapis/google-cloud-go/issues/3185)) ([d3a8571](https://www.github.com/googleapis/google-cloud-go/commit/d3a85719be411b692aede3331abb29b5a7b3da9a)) - - -## [0.71.0](https://www.github.com/googleapis/google-cloud-go/compare/v0.70.0...v0.71.0) (2020-10-30) - - -### Features - -* **all:** auto-regenerate gapics , refs [#3115](https://www.github.com/googleapis/google-cloud-go/issues/3115) [#3106](https://www.github.com/googleapis/google-cloud-go/issues/3106) [#3102](https://www.github.com/googleapis/google-cloud-go/issues/3102) [#3083](https://www.github.com/googleapis/google-cloud-go/issues/3083) [#3073](https://www.github.com/googleapis/google-cloud-go/issues/3073) [#3057](https://www.github.com/googleapis/google-cloud-go/issues/3057) [#3044](https://www.github.com/googleapis/google-cloud-go/issues/3044) -* **billing/budgets:** start generating apiv1 ([#3099](https://www.github.com/googleapis/google-cloud-go/issues/3099)) ([e760c85](https://www.github.com/googleapis/google-cloud-go/commit/e760c859de88a6e79b6dffc653dbf75f1630d8e3)) -* **internal:** auto-run godocfx on new mods ([#3069](https://www.github.com/googleapis/google-cloud-go/issues/3069)) ([49f497e](https://www.github.com/googleapis/google-cloud-go/commit/49f497eab80ce34dfb4ca41f033a5c0429ff5e42)) -* **pubsublite:** Added Pub/Sub Lite clients and routing headers ([#3105](https://www.github.com/googleapis/google-cloud-go/issues/3105)) ([98668fa](https://www.github.com/googleapis/google-cloud-go/commit/98668fa5457d26ed34debee708614f027020e5bc)) -* **pubsublite:** Message type and message routers ([#3077](https://www.github.com/googleapis/google-cloud-go/issues/3077)) ([179fc55](https://www.github.com/googleapis/google-cloud-go/commit/179fc550b545a5344358a243da7007ffaa7b5171)) -* **pubsublite:** Pub/Sub Lite admin client ([#3036](https://www.github.com/googleapis/google-cloud-go/issues/3036)) ([749473e](https://www.github.com/googleapis/google-cloud-go/commit/749473ead30bf1872634821d3238d1299b99acc6)) -* **pubsublite:** Publish settings and errors ([#3075](https://www.github.com/googleapis/google-cloud-go/issues/3075)) ([9eb9fcb](https://www.github.com/googleapis/google-cloud-go/commit/9eb9fcb79f17ad7c08c77c455ba3e8d89e3bdbf2)) -* **pubsublite:** Retryable stream wrapper ([#3068](https://www.github.com/googleapis/google-cloud-go/issues/3068)) ([97cfd45](https://www.github.com/googleapis/google-cloud-go/commit/97cfd4587f2f51996bd685ff486308b70eb51900)) - - -### Bug Fixes - -* **internal/kokoro:** remove unnecessary cd ([#3071](https://www.github.com/googleapis/google-cloud-go/issues/3071)) ([c1a4c3e](https://www.github.com/googleapis/google-cloud-go/commit/c1a4c3eaffcdc3cffe0e223fcfa1f60879cd23bb)) -* **pubsublite:** Disable integration tests for project id ([#3087](https://www.github.com/googleapis/google-cloud-go/issues/3087)) ([a0982f7](https://www.github.com/googleapis/google-cloud-go/commit/a0982f79d6461feabdf31363f29fed7dc5677fe7)) - -## [0.70.0](https://www.github.com/googleapis/google-cloud-go/compare/v0.69.0...v0.70.0) (2020-10-19) - - -### Features - -* **all:** auto-regenerate gapics , refs [#3047](https://www.github.com/googleapis/google-cloud-go/issues/3047) [#3035](https://www.github.com/googleapis/google-cloud-go/issues/3035) [#3025](https://www.github.com/googleapis/google-cloud-go/issues/3025) -* **managedidentities:** start generating apiv1 ([#3032](https://www.github.com/googleapis/google-cloud-go/issues/3032)) ([10ccca2](https://www.github.com/googleapis/google-cloud-go/commit/10ccca238074d24fea580a4cd8e64478818b0b44)) -* **pubsublite:** Types for resource paths and topic/subscription configs ([#3026](https://www.github.com/googleapis/google-cloud-go/issues/3026)) ([6f7fa86](https://www.github.com/googleapis/google-cloud-go/commit/6f7fa86ed906258f98d996aab40184f3a46f9714)) - -## [0.69.1](https://www.github.com/googleapis/google-cloud-go/compare/v0.69.0...v0.69.1) (2020-10-14) - -This is an empty release that was created solely to aid in pubsublite's module -carve out. See: https://github.com/golang/go/wiki/Modules#is-it-possible-to-add-a-module-to-a-multi-module-repository. - -## [0.69.0](https://www.github.com/googleapis/google-cloud-go/compare/v0.68.0...v0.69.0) (2020-10-14) - - -### Features - -* **accessapproval:** start generating apiv1 ([#3002](https://www.github.com/googleapis/google-cloud-go/issues/3002)) ([709d6e7](https://www.github.com/googleapis/google-cloud-go/commit/709d6e76393e6ac00ff488efd83bfe873173b045)) -* **all:** auto-regenerate gapics , refs [#3010](https://www.github.com/googleapis/google-cloud-go/issues/3010) [#3005](https://www.github.com/googleapis/google-cloud-go/issues/3005) [#2993](https://www.github.com/googleapis/google-cloud-go/issues/2993) [#2989](https://www.github.com/googleapis/google-cloud-go/issues/2989) [#2981](https://www.github.com/googleapis/google-cloud-go/issues/2981) [#2976](https://www.github.com/googleapis/google-cloud-go/issues/2976) [#2968](https://www.github.com/googleapis/google-cloud-go/issues/2968) [#2958](https://www.github.com/googleapis/google-cloud-go/issues/2958) -* **cmd/go-cloud-debug-agent:** mark as deprecated ([#2964](https://www.github.com/googleapis/google-cloud-go/issues/2964)) ([276ec88](https://www.github.com/googleapis/google-cloud-go/commit/276ec88b05852c33a3ba437e18d072f7ffd8fd33)) -* **godocfx:** add nesting to TOC ([#2972](https://www.github.com/googleapis/google-cloud-go/issues/2972)) ([3a49b2d](https://www.github.com/googleapis/google-cloud-go/commit/3a49b2d142a353f98429235c3f380431430b4dbf)) -* **internal/godocfx:** HTML-ify package summary ([#2986](https://www.github.com/googleapis/google-cloud-go/issues/2986)) ([9e64b01](https://www.github.com/googleapis/google-cloud-go/commit/9e64b018255bd8d9b31d60e8f396966251de946b)) -* **internal/kokoro:** make publish_docs VERSION optional ([#2979](https://www.github.com/googleapis/google-cloud-go/issues/2979)) ([76e35f6](https://www.github.com/googleapis/google-cloud-go/commit/76e35f689cb60bd5db8e14b8c8d367c5902bcb0e)) -* **websecurityscanner:** start generating apiv1 ([#3006](https://www.github.com/googleapis/google-cloud-go/issues/3006)) ([1d92e20](https://www.github.com/googleapis/google-cloud-go/commit/1d92e2062a13f62d7a96be53a7354c0cacca6a85)) - - -### Bug Fixes - -* **godocfx:** make extra files optional, filter out third_party ([#2985](https://www.github.com/googleapis/google-cloud-go/issues/2985)) ([f268921](https://www.github.com/googleapis/google-cloud-go/commit/f2689214a24b2e325d3e8f54441bb11fbef925f0)) - -## [0.68.0](https://www.github.com/googleapis/google-cloud-go/compare/v0.67.0...v0.68.0) (2020-10-02) - - -### Features - -* **all:** auto-regenerate gapics , refs [#2952](https://www.github.com/googleapis/google-cloud-go/issues/2952) [#2944](https://www.github.com/googleapis/google-cloud-go/issues/2944) [#2935](https://www.github.com/googleapis/google-cloud-go/issues/2935) - -## [0.67.0](https://www.github.com/googleapis/google-cloud-go/compare/v0.66.0...v0.67.0) (2020-09-29) - - -### Features - -* **all:** auto-regenerate gapics , refs [#2933](https://www.github.com/googleapis/google-cloud-go/issues/2933) [#2919](https://www.github.com/googleapis/google-cloud-go/issues/2919) [#2913](https://www.github.com/googleapis/google-cloud-go/issues/2913) [#2910](https://www.github.com/googleapis/google-cloud-go/issues/2910) [#2899](https://www.github.com/googleapis/google-cloud-go/issues/2899) [#2897](https://www.github.com/googleapis/google-cloud-go/issues/2897) [#2886](https://www.github.com/googleapis/google-cloud-go/issues/2886) [#2877](https://www.github.com/googleapis/google-cloud-go/issues/2877) [#2869](https://www.github.com/googleapis/google-cloud-go/issues/2869) [#2864](https://www.github.com/googleapis/google-cloud-go/issues/2864) -* **assuredworkloads:** start generating apiv1beta1 ([#2866](https://www.github.com/googleapis/google-cloud-go/issues/2866)) ([7598c4d](https://www.github.com/googleapis/google-cloud-go/commit/7598c4dd2462e8270a2c7b1f496af58ca81ff568)) -* **dialogflow/cx:** start generating apiv3beta1 ([#2875](https://www.github.com/googleapis/google-cloud-go/issues/2875)) ([37ca93a](https://www.github.com/googleapis/google-cloud-go/commit/37ca93ad69eda363d956f0174d444ed5914f5a72)) -* **docfx:** add support for examples ([#2884](https://www.github.com/googleapis/google-cloud-go/issues/2884)) ([0cc0de3](https://www.github.com/googleapis/google-cloud-go/commit/0cc0de300d58be6d3b7eeb2f1baebfa6df076830)) -* **godocfx:** include README in output ([#2927](https://www.github.com/googleapis/google-cloud-go/issues/2927)) ([f084690](https://www.github.com/googleapis/google-cloud-go/commit/f084690a2ea08ce73bafaaced95ad271fd01e11e)) -* **talent:** start generating apiv4 ([#2871](https://www.github.com/googleapis/google-cloud-go/issues/2871)) ([5c98071](https://www.github.com/googleapis/google-cloud-go/commit/5c98071b03822c58862d1fa5442ff36d627f1a61)) - - -### Bug Fixes - -* **godocfx:** filter out other modules, sort pkgs ([#2894](https://www.github.com/googleapis/google-cloud-go/issues/2894)) ([868db45](https://www.github.com/googleapis/google-cloud-go/commit/868db45e2e6f4e9ad48432be86c849f335e1083d)) -* **godocfx:** shorten function names ([#2880](https://www.github.com/googleapis/google-cloud-go/issues/2880)) ([48a0217](https://www.github.com/googleapis/google-cloud-go/commit/48a0217930750c1f4327f2622b0f2a3ec8afc0b7)) -* **translate:** properly name examples ([#2892](https://www.github.com/googleapis/google-cloud-go/issues/2892)) ([c19e141](https://www.github.com/googleapis/google-cloud-go/commit/c19e1415e6fa76b7ea66a7fc67ad3ba22670a2ba)), refs [#2883](https://www.github.com/googleapis/google-cloud-go/issues/2883) - -## [0.66.0](https://www.github.com/googleapis/google-cloud-go/compare/v0.65.0...v0.66.0) (2020-09-15) - - -### Features - -* **all:** auto-regenerate gapics , refs [#2849](https://www.github.com/googleapis/google-cloud-go/issues/2849) [#2843](https://www.github.com/googleapis/google-cloud-go/issues/2843) [#2841](https://www.github.com/googleapis/google-cloud-go/issues/2841) [#2819](https://www.github.com/googleapis/google-cloud-go/issues/2819) [#2816](https://www.github.com/googleapis/google-cloud-go/issues/2816) [#2809](https://www.github.com/googleapis/google-cloud-go/issues/2809) [#2801](https://www.github.com/googleapis/google-cloud-go/issues/2801) [#2795](https://www.github.com/googleapis/google-cloud-go/issues/2795) [#2791](https://www.github.com/googleapis/google-cloud-go/issues/2791) [#2788](https://www.github.com/googleapis/google-cloud-go/issues/2788) [#2781](https://www.github.com/googleapis/google-cloud-go/issues/2781) -* **analytics/data:** start generating apiv1alpha ([#2796](https://www.github.com/googleapis/google-cloud-go/issues/2796)) ([e93132c](https://www.github.com/googleapis/google-cloud-go/commit/e93132c77725de3c80c34d566df269eabfcfde93)) -* **area120/tables:** start generating apiv1alpha1 ([#2807](https://www.github.com/googleapis/google-cloud-go/issues/2807)) ([9e5a4d0](https://www.github.com/googleapis/google-cloud-go/commit/9e5a4d0dee0d83be0c020797a2f579d9e42ef521)) -* **cloudbuild:** Start generating apiv1/v3 ([#2830](https://www.github.com/googleapis/google-cloud-go/issues/2830)) ([358a536](https://www.github.com/googleapis/google-cloud-go/commit/358a5368da64cf4868551652e852ceb453504f64)) -* **godocfx:** create Go DocFX YAML generator ([#2854](https://www.github.com/googleapis/google-cloud-go/issues/2854)) ([37c70ac](https://www.github.com/googleapis/google-cloud-go/commit/37c70acd91768567106ff3b2b130835998d974c5)) -* **security/privateca:** start generating apiv1beta1 ([#2806](https://www.github.com/googleapis/google-cloud-go/issues/2806)) ([f985141](https://www.github.com/googleapis/google-cloud-go/commit/f9851412183989dc69733a7e61ad39a9378cd893)) -* **video/transcoder:** start generating apiv1beta1 ([#2797](https://www.github.com/googleapis/google-cloud-go/issues/2797)) ([390dda8](https://www.github.com/googleapis/google-cloud-go/commit/390dda8ff2c526e325e434ad0aec778b7aa97ea4)) -* **workflows:** start generating apiv1beta ([#2799](https://www.github.com/googleapis/google-cloud-go/issues/2799)) ([0e39665](https://www.github.com/googleapis/google-cloud-go/commit/0e39665ccb788caec800e2887d433ca6e0cf9901)) -* **workflows/executions:** start generating apiv1beta ([#2800](https://www.github.com/googleapis/google-cloud-go/issues/2800)) ([7eaa0d1](https://www.github.com/googleapis/google-cloud-go/commit/7eaa0d184c6a2141d8bf4514b3fd20715b50a580)) - - -### Bug Fixes - -* **internal/kokoro:** install the right version of docuploader ([#2861](https://www.github.com/googleapis/google-cloud-go/issues/2861)) ([d8489c1](https://www.github.com/googleapis/google-cloud-go/commit/d8489c141b8b02e83d6426f4baebd3658ae11639)) -* **internal/kokoro:** remove extra dash in doc tarball ([#2862](https://www.github.com/googleapis/google-cloud-go/issues/2862)) ([690ddcc](https://www.github.com/googleapis/google-cloud-go/commit/690ddccc5202b5a70f1afa5c518dca37b6a0861c)) -* **profiler:** do not collect disabled profile types ([#2836](https://www.github.com/googleapis/google-cloud-go/issues/2836)) ([faeb498](https://www.github.com/googleapis/google-cloud-go/commit/faeb4985bf6afdcddba4553efa874642bf7f08ed)), refs [#2835](https://www.github.com/googleapis/google-cloud-go/issues/2835) - - -### Reverts - -* **cloudbuild): "feat(cloudbuild:** Start generating apiv1/v3" ([#2840](https://www.github.com/googleapis/google-cloud-go/issues/2840)) ([3aaf755](https://www.github.com/googleapis/google-cloud-go/commit/3aaf755476dfea1700986fc086f53fc1ab756557)) - -## [0.65.0](https://www.github.com/googleapis/google-cloud-go/compare/v0.64.0...v0.65.0) (2020-08-27) - - -### Announcements - -The following changes will be included in an upcoming release and are not -included in this one. - -#### Default Deadlines - -By default, non-streaming methods, like Create or Get methods, will have a -default deadline applied to the context provided at call time, unless a context -deadline is already set. Streaming methods have no default deadline and will run -indefinitely, unless the context provided at call time contains a deadline. - -To opt-out of this behavior, set the environment variable -`GOOGLE_API_GO_EXPERIMENTAL_DISABLE_DEFAULT_DEADLINE` to `true` prior to -initializing a client. This opt-out mechanism will be removed in a later -release, with a notice similar to this one ahead of its removal. - - -### Features - -* **all:** auto-regenerate gapics , refs [#2774](https://www.github.com/googleapis/google-cloud-go/issues/2774) [#2764](https://www.github.com/googleapis/google-cloud-go/issues/2764) - - -### Bug Fixes - -* **all:** correct minor typos ([#2756](https://www.github.com/googleapis/google-cloud-go/issues/2756)) ([03d78b5](https://www.github.com/googleapis/google-cloud-go/commit/03d78b5627819cb64d1f3866f90043f709e825e1)) -* **compute/metadata:** remove leading slash for Get suffix ([#2760](https://www.github.com/googleapis/google-cloud-go/issues/2760)) ([f0d605c](https://www.github.com/googleapis/google-cloud-go/commit/f0d605ccf32391a9da056a2c551158bd076c128d)) - -## [0.64.0](https://www.github.com/googleapis/google-cloud-go/compare/v0.63.0...v0.64.0) (2020-08-18) - - -### Features - -* **all:** auto-regenerate gapics , refs [#2734](https://www.github.com/googleapis/google-cloud-go/issues/2734) [#2731](https://www.github.com/googleapis/google-cloud-go/issues/2731) [#2730](https://www.github.com/googleapis/google-cloud-go/issues/2730) [#2725](https://www.github.com/googleapis/google-cloud-go/issues/2725) [#2722](https://www.github.com/googleapis/google-cloud-go/issues/2722) [#2706](https://www.github.com/googleapis/google-cloud-go/issues/2706) -* **pubsublite:** start generating v1 ([#2700](https://www.github.com/googleapis/google-cloud-go/issues/2700)) ([d2e777f](https://www.github.com/googleapis/google-cloud-go/commit/d2e777f56e08146646b3ffb7a78856795094ab4e)) - -## [0.63.0](https://www.github.com/googleapis/google-cloud-go/compare/v0.62.0...v0.63.0) (2020-08-05) - - -### Features - -* **all:** auto-regenerate gapics ([#2682](https://www.github.com/googleapis/google-cloud-go/issues/2682)) ([63bfd63](https://www.github.com/googleapis/google-cloud-go/commit/63bfd638da169e0f1f4fa4a5125da2955022dc04)) -* **analytics/admin:** start generating apiv1alpha ([#2670](https://www.github.com/googleapis/google-cloud-go/issues/2670)) ([268199e](https://www.github.com/googleapis/google-cloud-go/commit/268199e5350a64a83ecf198e0e0fa4863f00fa6c)) -* **functions/metadata:** Special-case marshaling ([#2669](https://www.github.com/googleapis/google-cloud-go/issues/2669)) ([d8d7fc6](https://www.github.com/googleapis/google-cloud-go/commit/d8d7fc66cbc42f79bec25fb0daaf53d926e3645b)) -* **gaming:** start generate apiv1 ([#2681](https://www.github.com/googleapis/google-cloud-go/issues/2681)) ([1adfd0a](https://www.github.com/googleapis/google-cloud-go/commit/1adfd0aed6b2c0e1dd0c575a5ec0f49388fa5601)) -* **internal/kokoro:** add script to test compatibility with samples ([#2637](https://www.github.com/googleapis/google-cloud-go/issues/2637)) ([f2aa76a](https://www.github.com/googleapis/google-cloud-go/commit/f2aa76a0058e86c1c33bb634d2c084b58f77ab32)) - -## v0.62.0 - -### Announcements - -- There was a breaking change to `cloud.google.com/go/dataproc/apiv1` that was - merged in [this PR](https://github.com/googleapis/google-cloud-go/pull/2606). - This fixed a broken API response for `DiagnoseCluster`. When polling on the - Long Running Operation(LRO), the API now returns - `(*dataprocpb.DiagnoseClusterResults, error)` whereas it only returned an - `error` before. - -### Changes - -- all: - - Updated all direct dependencies. - - Updated contributing guidelines to suggest allowing edits from maintainers. -- billing/budgets: - - Start generating client for apiv1beta1. -- functions: - - Start generating client for apiv1. -- notebooks: - - Start generating client apiv1beta1. -- profiler: - - update proftest to support parsing floating-point backoff durations. - - Fix the regexp used to parse backoff duration. -- Various updates to autogenerated clients. - -## v0.61.0 - -### Changes - -- all: - - Update all direct dependencies. -- dashboard: - - Start generating client for apiv1. -- policytroubleshooter: - - Start generating client for apiv1. -- profiler: - - Disable OpenCensus Telemetry for requests made by the profiler package by default. You can re-enable it using `profiler.Config.EnableOCTelemetry`. -- Various updates to autogenerated clients. - -## v0.60.0 - -### Changes - -- all: - - Refactored examples to reduce module dependencies. - - Update sub-modules to use cloud.google.com/go v0.59.0. -- internal: - - Start generating client for gaming apiv1beta. -- Various updates to autogenerated clients. - -## v0.59.0 - -### Announcements - -goolgeapis/google-cloud-go has moved its source of truth to GitHub and is no longer a mirror. This means that our -contributing process has changed a bit. We will now be conducting all code reviews on GitHub which means we now accept -pull requests! If you have a version of the codebase previously checked out you may wish to update your git remote to -point to GitHub. - -### Changes - -- all: - - Remove dependency on honnef.co/go/tools. - - Update our contributing instructions now that we use GitHub for reviews. - - Remove some un-inclusive terminology. -- compute/metadata: - - Pass cancelable context to DNS lookup. -- .github: - - Update templates issue/PR templates. -- internal: - - Bump several clients to GA. - - Fix GoDoc badge source. - - Several automation changes related to the move to GitHub. - - Start generating a client for asset v1p5beta1. -- Various updates to autogenerated clients. - -## v0.58.0 - -### Deprecation notice - -- `cloud.google.com/go/monitoring/apiv3` has been deprecated due to breaking - changes in the API. Please migrate to `cloud.google.com/go/monitoring/apiv3/v2`. - -### Changes - -- all: - - The remaining uses of gtransport.Dial have been removed. - - The `genproto` dependency has been updated to a version that makes use of - new `protoreflect` library. For more information on these protobuf changes - please see the following post from the official Go blog: - https://blog.golang.org/protobuf-apiv2. -- internal: - - Started generation of datastore admin v1 client. - - Updated protofuf version used for generation to 3.12.X. - - Update the release levels for several APIs. - - Generate clients with protoc-gen-go@v1.4.1. -- monitoring: - - Re-enable generation of monitoring/apiv3 under v2 directory (see deprecation - notice above). -- profiler: - - Fixed flakiness in tests. -- Various updates to autogenerated clients. - -## v0.57.0 - -- all: - - Update module dependency `google.golang.org/api` to `v0.21.0`. -- errorreporting: - - Add exported SetGoogleClientInfo wrappers to manual file. -- expr/v1alpha1: - - Deprecate client. This client will be removed in a future release. -- internal: - - Fix possible data race in TestTracer. - - Pin versions of tools used for generation. - - Correct the release levels for BigQuery APIs. - - Start generation osconfig v1. -- longrunning: - - Add exported SetGoogleClientInfo wrappers to manual file. -- monitoring: - - Stop generation of monitoring/apiv3 because of incoming breaking change. -- trace: - - Add exported SetGoogleClientInfo wrappers to manual file. -- Various updates to autogenerated clients. - -## v0.56.0 - -- secretmanager: - - add IAM helper -- profiler: - - try all us-west1 zones for integration tests -- internal: - - add config to generate webrisk v1 - - add repo and commit to buildcop invocation - - add recaptchaenterprise v1 generation config - - update microgenerator to v0.12.5 - - add datacatalog client - - start generating security center settings v1beta - - start generating osconfig agentendpoint v1 - - setup generation for bigquery/connection/v1beta1 -- all: - - increase continous testing timeout to 45m - - various updates to autogenerated clients. - -## v0.55.0 - -- Various updates to autogenerated clients. - -## v0.54.0 - -- all: - - remove unused golang.org/x/exp from mod file - - update godoc.org links to pkg.go.dev -- compute/metadata: - - use defaultClient when http.Client is nil - - remove subscribeClient -- iam: - - add support for v3 policy and IAM conditions -- Various updates to autogenerated clients. - -## v0.53.0 - -- all: most clients now use transport/grpc.DialPool rather than Dial (see #1777 for outliers). - - Connection pooling now does not use the deprecated (and soon to be removed) gRPC load balancer API. -- profiler: remove symbolization (drops support for go1.10) -- Various updates to autogenerated clients. - -## v0.52.0 - -- internal/gapicgen: multiple improvements related to library generation. -- compute/metadata: unset ResponseHeaderTimeout in defaultClient -- docs: fix link to KMS in README.md -- Various updates to autogenerated clients. - -## v0.51.0 - -- secretmanager: - - add IAM helper for generic resource IAM handle -- cloudbuild: - - migrate to microgen in a major version -- Various updates to autogenerated clients. - -## v0.50.0 - -- profiler: - - Support disabling CPU profile collection. - - Log when a profile creation attempt begins. -- compute/metadata: - - Fix panic on malformed URLs. - - InstanceName returns actual instance name. -- Various updates to autogenerated clients. - -## v0.49.0 - -- functions/metadata: - - Handle string resources in JSON unmarshaller. -- Various updates to autogenerated clients. - -## v0.48.0 - -- Various updates to autogenerated clients - -## v0.47.0 - -This release drops support for Go 1.9 and Go 1.10: we continue to officially -support Go 1.11, Go 1.12, and Go 1.13. - -- Various updates to autogenerated clients. -- Add cloudbuild/apiv1 client. - -## v0.46.3 - -This is an empty release that was created solely to aid in storage's module -carve-out. See: https://github.com/golang/go/wiki/Modules#is-it-possible-to-add-a-module-to-a-multi-module-repository. - -## v0.46.2 - -This is an empty release that was created solely to aid in spanner's module -carve-out. See: https://github.com/golang/go/wiki/Modules#is-it-possible-to-add-a-module-to-a-multi-module-repository. - -## v0.46.1 - -This is an empty release that was created solely to aid in firestore's module -carve-out. See: https://github.com/golang/go/wiki/Modules#is-it-possible-to-add-a-module-to-a-multi-module-repository. - -## v0.46.0 - -- spanner: - - Retry "Session not found" for read-only transactions. - - Retry aborted PDMLs. -- spanner/spannertest: - - Fix a bug that was causing 0X-prefixed number to be parsed incorrectly. -- storage: - - Add HMACKeyOptions. - - Remove *REGIONAL from StorageClass documentation. Using MULTI_REGIONAL, - DURABLE_REDUCED_AVAILABILITY, and REGIONAL are no longer best practice - StorageClasses but they are still acceptable values. -- trace: - - Remove cloud.google.com/go/trace. Package cloud.google.com/go/trace has been - marked OBSOLETE for several years: it is now no longer provided. If you - relied on this package, please vendor it or switch to using - https://cloud.google.com/trace/docs/setup/go (which obsoleted it). - -## v0.45.1 - -This is an empty release that was created solely to aid in pubsub's module -carve-out. See: https://github.com/golang/go/wiki/Modules#is-it-possible-to-add-a-module-to-a-multi-module-repository. - -## v0.45.0 - -- compute/metadata: - - Add Email method. -- storage: - - Fix duplicated retry logic. - - Add ReaderObjectAttrs.StartOffset. - - Support reading last N bytes of a file when a negative range is given, such - as `obj.NewRangeReader(ctx, -10, -1)`. - - Add HMACKey listing functionality. -- spanner/spannertest: - - Support primary keys with no columns. - - Fix MinInt64 parsing. - - Implement deletion of key ranges. - - Handle reads during a read-write transaction. - - Handle returning DATE values. -- pubsub: - - Fix Ack/Modack request size calculation. -- logging: - - Add auto-detection of monitored resources on GAE Standard. - -## v0.44.3 - -This is an empty release that was created solely to aid in bigtable's module -carve-out. See: https://github.com/golang/go/wiki/Modules#is-it-possible-to-add-a-module-to-a-multi-module-repository. - -## v0.44.2 - -This is an empty release that was created solely to aid in bigquery's module -carve-out. See: https://github.com/golang/go/wiki/Modules#is-it-possible-to-add-a-module-to-a-multi-module-repository. - -## v0.44.1 - -This is an empty release that was created solely to aid in datastore's module -carve-out. See: https://github.com/golang/go/wiki/Modules#is-it-possible-to-add-a-module-to-a-multi-module-repository. - -## v0.44.0 - -- datastore: - - Interface elements whose underlying types are supported, are now supported. - - Reduce time to initial retry from 1s to 100ms. -- firestore: - - Add Increment transformation. -- storage: - - Allow emulator with STORAGE_EMULATOR_HOST. - - Add methods for HMAC key management. -- pubsub: - - Add PublishCount and PublishLatency measurements. - - Add DefaultPublishViews and DefaultSubscribeViews for convenience of - importing all views. - - Add add Subscription.PushConfig.AuthenticationMethod. -- spanner: - - Allow emulator usage with SPANNER_EMULATOR_HOST. - - Add cloud.google.com/go/spanner/spannertest, a spanner emulator. - - Add cloud.google.com/go/spanner/spansql which contains types and a parser - for the Cloud Spanner SQL dialect. -- asset: - - Add apiv1p2beta1 client. - -## v0.43.0 - -This is an empty release that was created solely to aid in logging's module -carve-out. See: https://github.com/golang/go/wiki/Modules#is-it-possible-to-add-a-module-to-a-multi-module-repository. - -## v0.42.0 - -- bigtable: - - Add an admin method to update an instance and clusters. - - Fix bttest regex matching behavior for alternations (things like `|a`). - - Expose BlockAllFilter filter. -- bigquery: - - Add Routines API support. -- storage: - - Add read-only Bucket.LocationType. -- logging: - - Add TraceSampled to Entry. - - Fix to properly extract {Trace, Span}Id from X-Cloud-Trace-Context. -- pubsub: - - Add Cloud Key Management to TopicConfig. - - Change ExpirationPolicy to optional.Duration. -- automl: - - Add apiv1beta1 client. -- iam: - - Fix compilation problem with iam/credentials/apiv1. - -## v0.41.0 - -- bigtable: - - Check results from PredicateFilter in bttest, which fixes certain false matches. -- profiler: - - debugLog checks user defined logging options before logging. -- spanner: - - PartitionedUpdates respect query parameters. - - StartInstance allows specifying cloud API access scopes. -- bigquery: - - Use empty slice instead of nil for ValueSaver, fixing an issue with zero-length, repeated, nested fields causing panics. -- firestore: - - Return same number of snapshots as doc refs (in the form of duplicate records) during GetAll. -- replay: - - Change references to IPv4 addresses to localhost, making replay compatible with IPv6. - -## v0.40.0 - -- all: - - Update to protobuf-golang v1.3.1. -- datastore: - - Attempt to decode GAE-encoded keys if initial decoding attempt fails. - - Support integer time conversion. -- pubsub: - - Add PublishSettings.BundlerByteLimit. If users receive pubsub.ErrOverflow, - this value should be adjusted higher. - - Use IPv6 compatible target in testutil. -- bigtable: - - Fix Latin-1 regexp filters in bttest, allowing \C. - - Expose PassAllFilter. -- profiler: - - Add log messages for slow path in start. - - Fix start to allow retry until success. -- firestore: - - Add admin client. -- containeranalysis: - - Add apiv1 client. -- grafeas: - - Add apiv1 client. - -## 0.39.0 - -- bigtable: - - Implement DeleteInstance in bttest. - - Return an error on invalid ReadRowsRequest.RowRange key ranges in bttest. -- bigquery: - - Move RequirePartitionFilter outside of TimePartioning. - - Expose models API. -- firestore: - - Allow array values in create and update calls. - - Add CollectionGroup method. -- pubsub: - - Add ExpirationPolicy to Subscription. -- storage: - - Add V4 signing. -- rpcreplay: - - Match streams by first sent request. This further improves rpcreplay's - ability to distinguish streams. -- httpreplay: - - Set up Man-In-The-Middle config only once. This should improve proxy - creation when multiple proxies are used in a single process. - - Remove error on empty Content-Type, allowing requests with no Content-Type - header but a non-empty body. -- all: - - Fix an edge case bug in auto-generated library pagination by properly - propagating pagetoken. - -## 0.38.0 - -This update includes a substantial reduction in our transitive dependency list -by way of updating to opencensus@v0.21.0. - -- spanner: - - Error implements GRPCStatus, allowing status.Convert. -- bigtable: - - Fix a bug in bttest that prevents single column queries returning results - that match other filters. - - Remove verbose retry logging. -- logging: - - Ensure RequestUrl has proper UTF-8, removing the need for users to wrap and - rune replace manually. -- recaptchaenterprise: - - Add v1beta1 client. -- phishingprotection: - - Add v1beta1 client. - -## 0.37.4 - -This patch releases re-builds the go.sum. This was not possible in the -previous release. - -- firestore: - - Add sentinel value DetectProjectID for auto-detecting project ID. - - Add OpenCensus tracing for public methods. - - Marked stable. All future changes come with a backwards compatibility - guarantee. - - Removed firestore/apiv1beta1. All users relying on this low-level library - should migrate to firestore/apiv1. Note that most users should use the - high-level firestore package instead. -- pubsub: - - Allow large messages in synchronous pull case. - - Cap bundler byte limit. This should prevent OOM conditions when there are - a very large number of message publishes occurring. -- storage: - - Add ETag to BucketAttrs and ObjectAttrs. -- datastore: - - Removed some non-sensical OpenCensus traces. -- webrisk: - - Add v1 client. -- asset: - - Add v1 client. -- cloudtasks: - - Add v2 client. - -## 0.37.3 - -This patch release removes github.com/golang/lint from the transitive -dependency list, resolving `go get -u` problems. - -Note: this release intentionally has a broken go.sum. Please use v0.37.4. - -## 0.37.2 - -This patch release is mostly intended to bring in v0.3.0 of -google.golang.org/api, which fixes a GCF deployment issue. - -Note: we had to-date accidentally marked Redis as stable. In this release, we've -fixed it by downgrading its documentation to alpha, as it is in other languages -and docs. - -- all: - - Document context in generated libraries. - -## 0.37.1 - -Small go.mod version bumps to bring in v0.2.0 of google.golang.org/api, which -introduces a new oauth2 url. - -## 0.37.0 - -- spanner: - - Add BatchDML method. - - Reduced initial time between retries. -- bigquery: - - Produce better error messages for InferSchema. - - Add logical type control for avro loads. - - Add support for the GEOGRAPHY type. -- datastore: - - Add sentinel value DetectProjectID for auto-detecting project ID. - - Allow flatten tag on struct pointers. - - Fixed a bug that caused queries to panic with invalid queries. Instead they - will now return an error. -- profiler: - - Add ability to override GCE zone and instance. -- pubsub: - - BEHAVIOR CHANGE: Refactor error code retry logic. RPCs should now more - consistently retry specific error codes based on whether they're idempotent - or non-idempotent. -- httpreplay: Fixed a bug when a non-GET request had a zero-length body causing - the Content-Length header to be dropped. -- iot: - - Add new apiv1 client. -- securitycenter: - - Add new apiv1 client. -- cloudscheduler: - - Add new apiv1 client. - -## 0.36.0 - -- spanner: - - Reduce minimum retry backoff from 1s to 100ms. This makes time between - retries much faster and should improve latency. -- storage: - - Add support for Bucket Policy Only. -- kms: - - Add ResourceIAM helper method. - - Deprecate KeyRingIAM and CryptoKeyIAM. Please use ResourceIAM. -- firestore: - - Switch from v1beta1 API to v1 API. - - Allow emulator with FIRESTORE_EMULATOR_HOST. -- bigquery: - - Add NumLongTermBytes to Table. - - Add TotalBytesProcessedAccuracy to QueryStatistics. -- irm: - - Add new v1alpha2 client. -- talent: - - Add new v4beta1 client. -- rpcreplay: - - Fix connection to work with grpc >= 1.17. - - It is now required for an actual gRPC server to be running for Dial to - succeed. - -## 0.35.1 - -- spanner: - - Adds OpenCensus views back to public API. - -## v0.35.0 - -- all: - - Add go.mod and go.sum. - - Switch usage of gax-go to gax-go/v2. -- bigquery: - - Fix bug where time partitioning could not be removed from a table. - - Fix panic that occurred with empty query parameters. -- bttest: - - Fix bug where deleted rows were returned by ReadRows. -- bigtable/emulator: - - Configure max message size to 256 MiB. -- firestore: - - Allow non-transactional queries in transactions. - - Allow StartAt/EndBefore on direct children at any depth. - - QuerySnapshotIterator.Stop may be called in an error state. - - Fix bug the prevented reset of transaction write state in between retries. -- functions/metadata: - - Make Metadata.Resource a pointer. -- logging: - - Make SpanID available in logging.Entry. -- metadata: - - Wrap !200 error code in a typed err. -- profiler: - - Add function to check if function name is within a particular file in the - profile. - - Set parent field in create profile request. - - Return kubernetes client to start cluster, so client can be used to poll - cluster. - - Add function for checking if filename is in profile. -- pubsub: - - Fix bug where messages expired without an initial modack in - synchronous=true mode. - - Receive does not retry ResourceExhausted errors. -- spanner: - - client.Close now cancels existing requests and should be much faster for - large amounts of sessions. - - Correctly allow MinOpened sessions to be spun up. - -## v0.34.0 - -- functions/metadata: - - Switch to using JSON in context. - - Make Resource a value. -- vision: Fix ProductSearch return type. -- datastore: Add an example for how to handle MultiError. - -## v0.33.1 - -- compute: Removes an erroneously added go.mod. -- logging: Populate source location in fromLogEntry. - -## v0.33.0 - -- bttest: - - Add support for apply_label_transformer. -- expr: - - Add expr library. -- firestore: - - Support retrieval of missing documents. -- kms: - - Add IAM methods. -- pubsub: - - Clarify extension documentation. -- scheduler: - - Add v1beta1 client. -- vision: - - Add product search helper. - - Add new product search client. - -## v0.32.0 - -Note: This release is the last to support Go 1.6 and 1.8. - -- bigquery: - - Add support for removing an expiration. - - Ignore NeverExpire in Table.Create. - - Validate table expiration time. -- cbt: - - Add note about not supporting arbitrary bytes. -- datastore: - - Align key checks. -- firestore: - - Return an error when using Start/End without providing values. -- pubsub: - - Add pstest Close method. - - Clarify MaxExtension documentation. -- securitycenter: - - Add v1beta1 client. -- spanner: - - Allow nil in mutations. - - Improve doc of SessionPoolConfig.MaxOpened. - - Increase session deletion timeout from 5s to 15s. - -## v0.31.0 - -- bigtable: - - Group mutations across multiple requests. -- bigquery: - - Link to bigquery troubleshooting errors page in bigquery.Error comment. -- cbt: - - Fix go generate command. - - Document usage of both maxage + maxversions. -- datastore: - - Passing nil keys results in ErrInvalidKey. -- firestore: - - Clarify what Document.DataTo does with untouched struct fields. -- profile: - - Validate service name in agent. -- pubsub: - - Fix deadlock with pstest and ctx.Cancel. - - Fix a possible deadlock in pstest. -- trace: - - Update doc URL with new fragment. - -Special thanks to @fastest963 for going above and beyond helping us to debug -hard-to-reproduce Pub/Sub issues. - -## v0.30.0 - -- spanner: DML support added. See https://godoc.org/cloud.google.com/go/spanner#hdr-DML_and_Partitioned_DML for more information. -- bigtable: bttest supports row sample filter. -- functions: metadata package added for accessing Cloud Functions resource metadata. - -## v0.29.0 - -- bigtable: - - Add retry to all idempotent RPCs. - - cbt supports complex GC policies. - - Emulator supports arbitrary bytes in regex filters. -- firestore: Add ArrayUnion and ArrayRemove. -- logging: Add the ContextFunc option to supply the context used for - asynchronous RPCs. -- profiler: Ignore NotDefinedError when fetching the instance name -- pubsub: - - BEHAVIOR CHANGE: Receive doesn't retry if an RPC returns codes.Cancelled. - - BEHAVIOR CHANGE: Receive retries on Unavailable intead of returning. - - Fix deadlock. - - Restore Ack/Nack/Modacks metrics. - - Improve context handling in iterator. - - Implement synchronous mode for Receive. - - pstest: add Pull. -- spanner: Add a metric for the number of sessions currently opened. -- storage: - - Canceling the context releases all resources. - - Add additional RetentionPolicy attributes. -- vision/apiv1: Add LocalizeObjects method. - -## v0.28.0 - -- bigtable: - - Emulator returns Unimplemented for snapshot RPCs. -- bigquery: - - Support zero-length repeated, nested fields. -- cloud assets: - - Add v1beta client. -- datastore: - - Don't nil out transaction ID on retry. -- firestore: - - BREAKING CHANGE: When watching a query with Query.Snapshots, QuerySnapshotIterator.Next - returns a QuerySnapshot which contains read time, result size, change list and the DocumentIterator - (previously, QuerySnapshotIterator.Next returned just the DocumentIterator). See: https://godoc.org/cloud.google.com/go/firestore#Query.Snapshots. - - Add array-contains operator. -- IAM: - - Add iam/credentials/apiv1 client. -- pubsub: - - Canceling the context passed to Subscription.Receive causes Receive to return when - processing finishes on all messages currently in progress, even if new messages are arriving. -- redis: - - Add redis/apiv1 client. -- storage: - - Add Reader.Attrs. - - Deprecate several Reader getter methods: please use Reader.Attrs for these instead. - - Add ObjectHandle.Bucket and ObjectHandle.Object methods. - -## v0.27.0 - -- bigquery: - - Allow modification of encryption configuration and partitioning options to a table via the Update call. - - Add a SchemaFromJSON function that converts a JSON table schema. -- bigtable: - - Restore cbt count functionality. -- containeranalysis: - - Add v1beta client. -- spanner: - - Fix a case where an iterator might not be closed correctly. -- storage: - - Add ServiceAccount method https://godoc.org/cloud.google.com/go/storage#Client.ServiceAccount. - - Add a method to Reader that returns the parsed value of the Last-Modified header. - -## v0.26.0 - -- bigquery: - - Support filtering listed jobs by min/max creation time. - - Support data clustering (https://godoc.org/cloud.google.com/go/bigquery#Clustering). - - Include job creator email in Job struct. -- bigtable: - - Add `RowSampleFilter`. - - emulator: BREAKING BEHAVIOR CHANGE: Regexps in row, family, column and value filters - must match the entire target string to succeed. Previously, the emulator was - succeeding on partial matches. - NOTE: As of this release, this change only affects the emulator when run - from this repo (bigtable/cmd/emulator/cbtemulator.go). The version launched - from `gcloud` will be updated in a subsequent `gcloud` release. -- dataproc: Add apiv1beta2 client. -- datastore: Save non-nil pointer fields on omitempty. -- logging: populate Entry.Trace from the HTTP X-Cloud-Trace-Context header. -- logging/logadmin: Support writer_identity and include_children. -- pubsub: - - Support labels on topics and subscriptions. - - Support message storage policy for topics. - - Use the distribution of ack times to determine when to extend ack deadlines. - The only user-visible effect of this change should be that programs that - call only `Subscription.Receive` need no IAM permissions other than `Pub/Sub - Subscriber`. -- storage: - - Support predefined ACLs. - - Support additional ACL fields other than Entity and Role. - - Support bucket websites. - - Support bucket logging. - - -## v0.25.0 - -- Added [Code of Conduct](https://github.com/googleapis/google-cloud-go/blob/master/CODE_OF_CONDUCT.md) -- bigtable: - - cbt: Support a GC policy of "never". -- errorreporting: - - Support User. - - Close now calls Flush. - - Use OnError (previously ignored). - - Pass through the RPC error as-is to OnError. -- httpreplay: A tool for recording and replaying HTTP requests - (for the bigquery and storage clients in this repo). -- kms: v1 client added -- logging: add SourceLocation to Entry. -- storage: improve CRC checking on read. - -## v0.24.0 - -- bigquery: Support for the NUMERIC type. -- bigtable: - - cbt: Optionally specify columns for read/lookup - - Support instance-level administration. -- oslogin: New client for the OS Login API. -- pubsub: - - The package is now stable. There will be no further breaking changes. - - Internal changes to improve Subscription.Receive behavior. -- storage: Support updating bucket lifecycle config. -- spanner: Support struct-typed parameter bindings. -- texttospeech: New client for the Text-to-Speech API. - -## v0.23.0 - -- bigquery: Add DDL stats to query statistics. -- bigtable: - - cbt: Add cells-per-column limit for row lookup. - - cbt: Make it possible to combine read filters. -- dlp: v2beta2 client removed. Use the v2 client instead. -- firestore, spanner: Fix compilation errors due to protobuf changes. - -## v0.22.0 - -- bigtable: - - cbt: Support cells per column limit for row read. - - bttest: Correctly handle empty RowSet. - - Fix ReadModifyWrite operation in emulator. - - Fix API path in GetCluster. - -- bigquery: - - BEHAVIOR CHANGE: Retry on 503 status code. - - Add dataset.DeleteWithContents. - - Add SchemaUpdateOptions for query jobs. - - Add Timeline to QueryStatistics. - - Add more stats to ExplainQueryStage. - - Support Parquet data format. - -- datastore: - - Support omitempty for times. - -- dlp: - - **BREAKING CHANGE:** Remove v1beta1 client. Please migrate to the v2 client, - which is now out of beta. - - Add v2 client. - -- firestore: - - BEHAVIOR CHANGE: Treat set({}, MergeAll) as valid. - -- iam: - - Support JWT signing via SignJwt callopt. - -- profiler: - - BEHAVIOR CHANGE: PollForSerialOutput returns an error when context.Done. - - BEHAVIOR CHANGE: Increase the initial backoff to 1 minute. - - Avoid returning empty serial port output. - -- pubsub: - - BEHAVIOR CHANGE: Don't backoff during next retryable error once stream is healthy. - - BEHAVIOR CHANGE: Don't backoff on EOF. - - pstest: Support Acknowledge and ModifyAckDeadline RPCs. - -- redis: - - Add v1 beta Redis client. - -- spanner: - - Support SessionLabels. - -- speech: - - Add api v1 beta1 client. - -- storage: - - BEHAVIOR CHANGE: Retry reads when retryable error occurs. - - Fix delete of object in requester-pays bucket. - - Support KMS integration. - -## v0.21.0 - -- bigquery: - - Add OpenCensus tracing. - -- firestore: - - **BREAKING CHANGE:** If a document does not exist, return a DocumentSnapshot - whose Exists method returns false. DocumentRef.Get and Transaction.Get - return the non-nil DocumentSnapshot in addition to a NotFound error. - **DocumentRef.GetAll and Transaction.GetAll return a non-nil - DocumentSnapshot instead of nil.** - - Add DocumentIterator.Stop. **Call Stop whenever you are done with a - DocumentIterator.** - - Added Query.Snapshots and DocumentRef.Snapshots, which provide realtime - notification of updates. See https://cloud.google.com/firestore/docs/query-data/listen. - - Canceling an RPC now always returns a grpc.Status with codes.Canceled. - -- spanner: - - Add `CommitTimestamp`, which supports inserting the commit timestamp of a - transaction into a column. - -## v0.20.0 - -- bigquery: Support SchemaUpdateOptions for load jobs. - -- bigtable: - - Add SampleRowKeys. - - cbt: Support union, intersection GCPolicy. - - Retry admin RPCS. - - Add trace spans to retries. - -- datastore: Add OpenCensus tracing. - -- firestore: - - Fix queries involving Null and NaN. - - Allow Timestamp protobuffers for time values. - -- logging: Add a WriteTimeout option. - -- spanner: Support Batch API. - -- storage: Add OpenCensus tracing. - -## v0.19.0 - -- bigquery: - - Support customer-managed encryption keys. - -- bigtable: - - Improved emulator support. - - Support GetCluster. - -- datastore: - - Add general mutations. - - Support pointer struct fields. - - Support transaction options. - -- firestore: - - Add Transaction.GetAll. - - Support document cursors. - -- logging: - - Support concurrent RPCs to the service. - - Support per-entry resources. - -- profiler: - - Add config options to disable heap and thread profiling. - - Read the project ID from $GOOGLE_CLOUD_PROJECT when it's set. - -- pubsub: - - BEHAVIOR CHANGE: Release flow control after ack/nack (instead of after the - callback returns). - - Add SubscriptionInProject. - - Add OpenCensus instrumentation for streaming pull. - -- storage: - - Support CORS. - -## v0.18.0 - -- bigquery: - - Marked stable. - - Schema inference of nullable fields supported. - - Added TimePartitioning to QueryConfig. - -- firestore: Data provided to DocumentRef.Set with a Merge option can contain - Delete sentinels. - -- logging: Clients can accept parent resources other than projects. - -- pubsub: - - pubsub/pstest: A lighweight fake for pubsub. Experimental; feedback welcome. - - Support updating more subscription metadata: AckDeadline, - RetainAckedMessages and RetentionDuration. - -- oslogin/apiv1beta: New client for the Cloud OS Login API. - -- rpcreplay: A package for recording and replaying gRPC traffic. - -- spanner: - - Add a ReadWithOptions that supports a row limit, as well as an index. - - Support query plan and execution statistics. - - Added [OpenCensus](http://opencensus.io) support. - -- storage: Clarify checksum validation for gzipped files (it is not validated - when the file is served uncompressed). - - -## v0.17.0 - -- firestore BREAKING CHANGES: - - Remove UpdateMap and UpdateStruct; rename UpdatePaths to Update. - Change - `docref.UpdateMap(ctx, map[string]interface{}{"a.b", 1})` - to - `docref.Update(ctx, []firestore.Update{{Path: "a.b", Value: 1}})` - - Change - `docref.UpdateStruct(ctx, []string{"Field"}, aStruct)` - to - `docref.Update(ctx, []firestore.Update{{Path: "Field", Value: aStruct.Field}})` - - Rename MergePaths to Merge; require args to be FieldPaths - - A value stored as an integer can be read into a floating-point field, and vice versa. -- bigtable/cmd/cbt: - - Support deleting a column. - - Add regex option for row read. -- spanner: Mark stable. -- storage: - - Add Reader.ContentEncoding method. - - Fix handling of SignedURL headers. -- bigquery: - - If Uploader.Put is called with no rows, it returns nil without making a - call. - - Schema inference supports the "nullable" option in struct tags for - non-required fields. - - TimePartitioning supports "Field". - - -## v0.16.0 - -- Other bigquery changes: - - `JobIterator.Next` returns `*Job`; removed `JobInfo` (BREAKING CHANGE). - - UseStandardSQL is deprecated; set UseLegacySQL to true if you need - Legacy SQL. - - Uploader.Put will generate a random insert ID if you do not provide one. - - Support time partitioning for load jobs. - - Support dry-run queries. - - A `Job` remembers its last retrieved status. - - Support retrieving job configuration. - - Support labels for jobs and tables. - - Support dataset access lists. - - Improve support for external data sources, including data from Bigtable and - Google Sheets, and tables with external data. - - Support updating a table's view configuration. - - Fix uploading civil times with nanoseconds. - -- storage: - - Support PubSub notifications. - - Support Requester Pays buckets. - -- profiler: Support goroutine and mutex profile types. - -## v0.15.0 - -- firestore: beta release. See the - [announcement](https://firebase.googleblog.com/2017/10/introducing-cloud-firestore.html). - -- errorreporting: The existing package has been redesigned. - -- errors: This package has been removed. Use errorreporting. - - -## v0.14.0 - -- bigquery BREAKING CHANGES: - - Standard SQL is the default for queries and views. - - `Table.Create` takes `TableMetadata` as a second argument, instead of - options. - - `Dataset.Create` takes `DatasetMetadata` as a second argument. - - `DatasetMetadata` field `ID` renamed to `FullID` - - `TableMetadata` field `ID` renamed to `FullID` - -- Other bigquery changes: - - The client will append a random suffix to a provided job ID if you set - `AddJobIDSuffix` to true in a job config. - - Listing jobs is supported. - - Better retry logic. - -- vision, language, speech: clients are now stable - -- monitoring: client is now beta - -- profiler: - - Rename InstanceName to Instance, ZoneName to Zone - - Auto-detect service name and version on AppEngine. - -## v0.13.0 - -- bigquery: UseLegacySQL options for CreateTable and QueryConfig. Use these - options to continue using Legacy SQL after the client switches its default - to Standard SQL. - -- bigquery: Support for updating dataset labels. - -- bigquery: Set DatasetIterator.ProjectID to list datasets in a project other - than the client's. DatasetsInProject is no longer needed and is deprecated. - -- bigtable: Fail ListInstances when any zones fail. - -- spanner: support decoding of slices of basic types (e.g. []string, []int64, - etc.) - -- logging/logadmin: UpdateSink no longer creates a sink if it is missing - (actually a change to the underlying service, not the client) - -- profiler: Service and ServiceVersion replace Target in Config. - -## v0.12.0 - -- pubsub: Subscription.Receive now uses streaming pull. - -- pubsub: add Client.TopicInProject to access topics in a different project - than the client. - -- errors: renamed errorreporting. The errors package will be removed shortly. - -- datastore: improved retry behavior. - -- bigquery: support updates to dataset metadata, with etags. - -- bigquery: add etag support to Table.Update (BREAKING: etag argument added). - -- bigquery: generate all job IDs on the client. - -- storage: support bucket lifecycle configurations. - - -## v0.11.0 - -- Clients for spanner, pubsub and video are now in beta. - -- New client for DLP. - -- spanner: performance and testing improvements. - -- storage: requester-pays buckets are supported. - -- storage, profiler, bigtable, bigquery: bug fixes and other minor improvements. - -- pubsub: bug fixes and other minor improvements - -## v0.10.0 - -- pubsub: Subscription.ModifyPushConfig replaced with Subscription.Update. - -- pubsub: Subscription.Receive now runs concurrently for higher throughput. - -- vision: cloud.google.com/go/vision is deprecated. Use -cloud.google.com/go/vision/apiv1 instead. - -- translation: now stable. - -- trace: several changes to the surface. See the link below. - -### Code changes required from v0.9.0 - -- pubsub: Replace - - ``` - sub.ModifyPushConfig(ctx, pubsub.PushConfig{Endpoint: "https://example.com/push"}) - ``` - - with - - ``` - sub.Update(ctx, pubsub.SubscriptionConfigToUpdate{ - PushConfig: &pubsub.PushConfig{Endpoint: "https://example.com/push"}, - }) - ``` - -- trace: traceGRPCServerInterceptor will be provided from *trace.Client. -Given an initialized `*trace.Client` named `tc`, instead of - - ``` - s := grpc.NewServer(grpc.UnaryInterceptor(trace.GRPCServerInterceptor(tc))) - ``` - - write - - ``` - s := grpc.NewServer(grpc.UnaryInterceptor(tc.GRPCServerInterceptor())) - ``` - -- trace trace.GRPCClientInterceptor will also provided from *trace.Client. -Instead of - - ``` - conn, err := grpc.Dial(srv.Addr, grpc.WithUnaryInterceptor(trace.GRPCClientInterceptor())) - ``` - - write - - ``` - conn, err := grpc.Dial(srv.Addr, grpc.WithUnaryInterceptor(tc.GRPCClientInterceptor())) - ``` - -- trace: We removed the deprecated `trace.EnableGRPCTracing`. Use the gRPC -interceptor as a dial option as shown below when initializing Cloud package -clients: - - ``` - c, err := pubsub.NewClient(ctx, "project-id", option.WithGRPCDialOption(grpc.WithUnaryInterceptor(tc.GRPCClientInterceptor()))) - if err != nil { - ... - } - ``` - - -## v0.9.0 - -- Breaking changes to some autogenerated clients. -- rpcreplay package added. - -## v0.8.0 - -- profiler package added. -- storage: - - Retry Objects.Insert call. - - Add ProgressFunc to WRiter. -- pubsub: breaking changes: - - Publish is now asynchronous ([announcement](https://groups.google.com/d/topic/google-api-go-announce/aaqRDIQ3rvU/discussion)). - - Subscription.Pull replaced by Subscription.Receive, which takes a callback ([announcement](https://groups.google.com/d/topic/google-api-go-announce/8pt6oetAdKc/discussion)). - - Message.Done replaced with Message.Ack and Message.Nack. - -## v0.7.0 - -- Release of a client library for Spanner. See -the -[blog -post](https://cloudplatform.googleblog.com/2017/02/introducing-Cloud-Spanner-a-global-database-service-for-mission-critical-applications.html). -Note that although the Spanner service is beta, the Go client library is alpha. - -## v0.6.0 - -- Beta release of BigQuery, DataStore, Logging and Storage. See the -[blog post](https://cloudplatform.googleblog.com/2016/12/announcing-new-google-cloud-client.html). - -- bigquery: - - struct support. Read a row directly into a struct with -`RowIterator.Next`, and upload a row directly from a struct with `Uploader.Put`. -You can also use field tags. See the [package documentation][cloud-bigquery-ref] -for details. - - - The `ValueList` type was removed. It is no longer necessary. Instead of - ```go - var v ValueList - ... it.Next(&v) .. - ``` - use - - ```go - var v []Value - ... it.Next(&v) ... - ``` - - - Previously, repeatedly calling `RowIterator.Next` on the same `[]Value` or - `ValueList` would append to the slice. Now each call resets the size to zero first. - - - Schema inference will infer the SQL type BYTES for a struct field of - type []byte. Previously it inferred STRING. - - - The types `uint`, `uint64` and `uintptr` are no longer supported in schema - inference. BigQuery's integer type is INT64, and those types may hold values - that are not correctly represented in a 64-bit signed integer. - -## v0.5.0 - -- bigquery: - - The SQL types DATE, TIME and DATETIME are now supported. They correspond to - the `Date`, `Time` and `DateTime` types in the new `cloud.google.com/go/civil` - package. - - Support for query parameters. - - Support deleting a dataset. - - Values from INTEGER columns will now be returned as int64, not int. This - will avoid errors arising from large values on 32-bit systems. -- datastore: - - Nested Go structs encoded as Entity values, instead of a -flattened list of the embedded struct's fields. This means that you may now have twice-nested slices, eg. - ```go - type State struct { - Cities []struct{ - Populations []int - } - } - ``` - See [the announcement](https://groups.google.com/forum/#!topic/google-api-go-announce/79jtrdeuJAg) for -more details. - - Contexts no longer hold namespaces; instead you must set a key's namespace - explicitly. Also, key functions have been changed and renamed. - - The WithNamespace function has been removed. To specify a namespace in a Query, use the Query.Namespace method: - ```go - q := datastore.NewQuery("Kind").Namespace("ns") - ``` - - All the fields of Key are exported. That means you can construct any Key with a struct literal: - ```go - k := &Key{Kind: "Kind", ID: 37, Namespace: "ns"} - ``` - - As a result of the above, the Key methods Kind, ID, d.Name, Parent, SetParent and Namespace have been removed. - - `NewIncompleteKey` has been removed, replaced by `IncompleteKey`. Replace - ```go - NewIncompleteKey(ctx, kind, parent) - ``` - with - ```go - IncompleteKey(kind, parent) - ``` - and if you do use namespaces, make sure you set the namespace on the returned key. - - `NewKey` has been removed, replaced by `NameKey` and `IDKey`. Replace - ```go - NewKey(ctx, kind, name, 0, parent) - NewKey(ctx, kind, "", id, parent) - ``` - with - ```go - NameKey(kind, name, parent) - IDKey(kind, id, parent) - ``` - and if you do use namespaces, make sure you set the namespace on the returned key. - - The `Done` variable has been removed. Replace `datastore.Done` with `iterator.Done`, from the package `google.golang.org/api/iterator`. - - The `Client.Close` method will have a return type of error. It will return the result of closing the underlying gRPC connection. - - See [the announcement](https://groups.google.com/forum/#!topic/google-api-go-announce/hqXtM_4Ix-0) for -more details. - -## v0.4.0 - -- bigquery: - -`NewGCSReference` is now a function, not a method on `Client`. - - `Table.LoaderFrom` now accepts a `ReaderSource`, enabling - loading data into a table from a file or any `io.Reader`. - * Client.Table and Client.OpenTable have been removed. - Replace - ```go - client.OpenTable("project", "dataset", "table") - ``` - with - ```go - client.DatasetInProject("project", "dataset").Table("table") - ``` - - * Client.CreateTable has been removed. - Replace - ```go - client.CreateTable(ctx, "project", "dataset", "table") - ``` - with - ```go - client.DatasetInProject("project", "dataset").Table("table").Create(ctx) - ``` - - * Dataset.ListTables have been replaced with Dataset.Tables. - Replace - ```go - tables, err := ds.ListTables(ctx) - ``` - with - ```go - it := ds.Tables(ctx) - for { - table, err := it.Next() - if err == iterator.Done { - break - } - if err != nil { - // TODO: Handle error. - } - // TODO: use table. - } - ``` - - * Client.Read has been replaced with Job.Read, Table.Read and Query.Read. - Replace - ```go - it, err := client.Read(ctx, job) - ``` - with - ```go - it, err := job.Read(ctx) - ``` - and similarly for reading from tables or queries. - - * The iterator returned from the Read methods is now named RowIterator. Its - behavior is closer to the other iterators in these libraries. It no longer - supports the Schema method; see the next item. - Replace - ```go - for it.Next(ctx) { - var vals ValueList - if err := it.Get(&vals); err != nil { - // TODO: Handle error. - } - // TODO: use vals. - } - if err := it.Err(); err != nil { - // TODO: Handle error. - } - ``` - with - ``` - for { - var vals ValueList - err := it.Next(&vals) - if err == iterator.Done { - break - } - if err != nil { - // TODO: Handle error. - } - // TODO: use vals. - } - ``` - Instead of the `RecordsPerRequest(n)` option, write - ```go - it.PageInfo().MaxSize = n - ``` - Instead of the `StartIndex(i)` option, write - ```go - it.StartIndex = i - ``` - - * ValueLoader.Load now takes a Schema in addition to a slice of Values. - Replace - ```go - func (vl *myValueLoader) Load(v []bigquery.Value) - ``` - with - ```go - func (vl *myValueLoader) Load(v []bigquery.Value, s bigquery.Schema) - ``` - - - * Table.Patch is replace by Table.Update. - Replace - ```go - p := table.Patch() - p.Description("new description") - metadata, err := p.Apply(ctx) - ``` - with - ```go - metadata, err := table.Update(ctx, bigquery.TableMetadataToUpdate{ - Description: "new description", - }) - ``` - - * Client.Copy is replaced by separate methods for each of its four functions. - All options have been replaced by struct fields. - - * To load data from Google Cloud Storage into a table, use Table.LoaderFrom. - - Replace - ```go - client.Copy(ctx, table, gcsRef) - ``` - with - ```go - table.LoaderFrom(gcsRef).Run(ctx) - ``` - Instead of passing options to Copy, set fields on the Loader: - ```go - loader := table.LoaderFrom(gcsRef) - loader.WriteDisposition = bigquery.WriteTruncate - ``` - - * To extract data from a table into Google Cloud Storage, use - Table.ExtractorTo. Set fields on the returned Extractor instead of - passing options. - - Replace - ```go - client.Copy(ctx, gcsRef, table) - ``` - with - ```go - table.ExtractorTo(gcsRef).Run(ctx) - ``` - - * To copy data into a table from one or more other tables, use - Table.CopierFrom. Set fields on the returned Copier instead of passing options. - - Replace - ```go - client.Copy(ctx, dstTable, srcTable) - ``` - with - ```go - dst.Table.CopierFrom(srcTable).Run(ctx) - ``` - - * To start a query job, create a Query and call its Run method. Set fields - on the query instead of passing options. - - Replace - ```go - client.Copy(ctx, table, query) - ``` - with - ```go - query.Run(ctx) - ``` - - * Table.NewUploader has been renamed to Table.Uploader. Instead of options, - configure an Uploader by setting its fields. - Replace - ```go - u := table.NewUploader(bigquery.UploadIgnoreUnknownValues()) - ``` - with - ```go - u := table.NewUploader(bigquery.UploadIgnoreUnknownValues()) - u.IgnoreUnknownValues = true - ``` - -- pubsub: remove `pubsub.Done`. Use `iterator.Done` instead, where `iterator` is the package -`google.golang.org/api/iterator`. - -## v0.3.0 - -- storage: - * AdminClient replaced by methods on Client. - Replace - ```go - adminClient.CreateBucket(ctx, bucketName, attrs) - ``` - with - ```go - client.Bucket(bucketName).Create(ctx, projectID, attrs) - ``` - - * BucketHandle.List replaced by BucketHandle.Objects. - Replace - ```go - for query != nil { - objs, err := bucket.List(d.ctx, query) - if err != nil { ... } - query = objs.Next - for _, obj := range objs.Results { - fmt.Println(obj) - } - } - ``` - with - ```go - iter := bucket.Objects(d.ctx, query) - for { - obj, err := iter.Next() - if err == iterator.Done { - break - } - if err != nil { ... } - fmt.Println(obj) - } - ``` - (The `iterator` package is at `google.golang.org/api/iterator`.) - - Replace `Query.Cursor` with `ObjectIterator.PageInfo().Token`. - - Replace `Query.MaxResults` with `ObjectIterator.PageInfo().MaxSize`. - - - * ObjectHandle.CopyTo replaced by ObjectHandle.CopierFrom. - Replace - ```go - attrs, err := src.CopyTo(ctx, dst, nil) - ``` - with - ```go - attrs, err := dst.CopierFrom(src).Run(ctx) - ``` - - Replace - ```go - attrs, err := src.CopyTo(ctx, dst, &storage.ObjectAttrs{ContextType: "text/html"}) - ``` - with - ```go - c := dst.CopierFrom(src) - c.ContextType = "text/html" - attrs, err := c.Run(ctx) - ``` - - * ObjectHandle.ComposeFrom replaced by ObjectHandle.ComposerFrom. - Replace - ```go - attrs, err := dst.ComposeFrom(ctx, []*storage.ObjectHandle{src1, src2}, nil) - ``` - with - ```go - attrs, err := dst.ComposerFrom(src1, src2).Run(ctx) - ``` - - * ObjectHandle.Update's ObjectAttrs argument replaced by ObjectAttrsToUpdate. - Replace - ```go - attrs, err := obj.Update(ctx, &storage.ObjectAttrs{ContextType: "text/html"}) - ``` - with - ```go - attrs, err := obj.Update(ctx, storage.ObjectAttrsToUpdate{ContextType: "text/html"}) - ``` - - * ObjectHandle.WithConditions replaced by ObjectHandle.If. - Replace - ```go - obj.WithConditions(storage.Generation(gen), storage.IfMetaGenerationMatch(mgen)) - ``` - with - ```go - obj.Generation(gen).If(storage.Conditions{MetagenerationMatch: mgen}) - ``` - - Replace - ```go - obj.WithConditions(storage.IfGenerationMatch(0)) - ``` - with - ```go - obj.If(storage.Conditions{DoesNotExist: true}) - ``` - - * `storage.Done` replaced by `iterator.Done` (from package `google.golang.org/api/iterator`). - -- Package preview/logging deleted. Use logging instead. - -## v0.2.0 - -- Logging client replaced with preview version (see below). - -- New clients for some of Google's Machine Learning APIs: Vision, Speech, and -Natural Language. - -- Preview version of a new [Stackdriver Logging][cloud-logging] client in -[`cloud.google.com/go/preview/logging`](https://godoc.org/cloud.google.com/go/preview/logging). -This client uses gRPC as its transport layer, and supports log reading, sinks -and metrics. It will replace the current client at `cloud.google.com/go/logging` shortly. diff --git a/vendor/cloud.google.com/go/CODE_OF_CONDUCT.md b/vendor/cloud.google.com/go/CODE_OF_CONDUCT.md deleted file mode 100644 index 8fd1bc9c22b..00000000000 --- a/vendor/cloud.google.com/go/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,44 +0,0 @@ -# Contributor Code of Conduct - -As contributors and maintainers of this project, -and in the interest of fostering an open and welcoming community, -we pledge to respect all people who contribute through reporting issues, -posting feature requests, updating documentation, -submitting pull requests or patches, and other activities. - -We are committed to making participation in this project -a harassment-free experience for everyone, -regardless of level of experience, gender, gender identity and expression, -sexual orientation, disability, personal appearance, -body size, race, ethnicity, age, religion, or nationality. - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery -* Personal attacks -* Trolling or insulting/derogatory comments -* Public or private harassment -* Publishing other's private information, -such as physical or electronic -addresses, without explicit permission -* Other unethical or unprofessional conduct. - -Project maintainers have the right and responsibility to remove, edit, or reject -comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct. -By adopting this Code of Conduct, -project maintainers commit themselves to fairly and consistently -applying these principles to every aspect of managing this project. -Project maintainers who do not follow or enforce the Code of Conduct -may be permanently removed from the project team. - -This code of conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. - -Instances of abusive, harassing, or otherwise unacceptable behavior -may be reported by opening an issue -or contacting one or more of the project maintainers. - -This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, -available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/) - diff --git a/vendor/cloud.google.com/go/CONTRIBUTING.md b/vendor/cloud.google.com/go/CONTRIBUTING.md deleted file mode 100644 index e1398722c3e..00000000000 --- a/vendor/cloud.google.com/go/CONTRIBUTING.md +++ /dev/null @@ -1,261 +0,0 @@ -# Contributing - -1. [File an issue](https://github.com/googleapis/google-cloud-go/issues/new/choose). - The issue will be used to discuss the bug or feature and should be created - before sending a CL. - -1. [Install Go](https://golang.org/dl/). - 1. Ensure that your `GOBIN` directory (by default `$(go env GOPATH)/bin`) - is in your `PATH`. - 1. Check it's working by running `go version`. - * If it doesn't work, check the install location, usually - `/usr/local/go`, is on your `PATH`. - -1. Sign one of the -[contributor license agreements](#contributor-license-agreements) below. - -1. Clone the repo: - `git clone https://github.com/googleapis/google-cloud-go` - -1. Change into the checked out source: - `cd google-cloud-go` - -1. Fork the repo. - -1. Set your fork as a remote: - `git remote add fork git@github.com:GITHUB_USERNAME/google-cloud-go.git` - -1. Make changes, commit to your fork. - - Commit messages should follow the - [Conventional Commits Style](https://www.conventionalcommits.org). The scope - portion should always be filled with the name of the package affected by the - changes being made. For example: - ``` - feat(functions): add gophers codelab - ``` - -1. Send a pull request with your changes. - - To minimize friction, consider setting `Allow edits from maintainers` on the - PR, which will enable project committers and automation to update your PR. - -1. A maintainer will review the pull request and make comments. - - Prefer adding additional commits over amending and force-pushing since it can - be difficult to follow code reviews when the commit history changes. - - Commits will be squashed when they're merged. - -## Testing - -We test code against two versions of Go, the minimum and maximum versions -supported by our clients. To see which versions these are checkout our -[README](README.md#supported-versions). - -### Integration Tests - -In addition to the unit tests, you may run the integration test suite. These -directions describe setting up your environment to run integration tests for -_all_ packages: note that many of these instructions may be redundant if you -intend only to run integration tests on a single package. - -#### GCP Setup - -To run the integrations tests, creation and configuration of two projects in -the Google Developers Console is required: one specifically for Firestore -integration tests, and another for all other integration tests. We'll refer to -these projects as "general project" and "Firestore project". - -After creating each project, you must [create a service account](https://developers.google.com/identity/protocols/OAuth2ServiceAccount#creatinganaccount) -for each project. Ensure the project-level **Owner** -[IAM role](console.cloud.google.com/iam-admin/iam/project) role is added to -each service account. During the creation of the service account, you should -download the JSON credential file for use later. - -Next, ensure the following APIs are enabled in the general project: - -- BigQuery API -- BigQuery Data Transfer API -- Cloud Dataproc API -- Cloud Dataproc Control API Private -- Cloud Datastore API -- Cloud Firestore API -- Cloud Key Management Service (KMS) API -- Cloud Natural Language API -- Cloud OS Login API -- Cloud Pub/Sub API -- Cloud Resource Manager API -- Cloud Spanner API -- Cloud Speech API -- Cloud Translation API -- Cloud Video Intelligence API -- Cloud Vision API -- Compute Engine API -- Compute Engine Instance Group Manager API -- Container Registry API -- Firebase Rules API -- Google Cloud APIs -- Google Cloud Deployment Manager V2 API -- Google Cloud SQL -- Google Cloud Storage -- Google Cloud Storage JSON API -- Google Compute Engine Instance Group Updater API -- Google Compute Engine Instance Groups API -- Kubernetes Engine API -- Cloud Error Reporting API -- Pub/Sub Lite API - -Next, create a Datastore database in the general project, and a Firestore -database in the Firestore project. - -Finally, in the general project, create an API key for the translate API: - -- Go to GCP Developer Console. -- Navigate to APIs & Services > Credentials. -- Click Create Credentials > API Key. -- Save this key for use in `GCLOUD_TESTS_API_KEY` as described below. - -#### Local Setup - -Once the two projects are created and configured, set the following environment -variables: - -- `GCLOUD_TESTS_GOLANG_PROJECT_ID`: Developers Console project's ID (e.g. -bamboo-shift-455) for the general project. -- `GCLOUD_TESTS_GOLANG_KEY`: The path to the JSON key file of the general -project's service account. -- `GCLOUD_TESTS_GOLANG_FIRESTORE_PROJECT_ID`: Developers Console project's ID -(e.g. doorway-cliff-677) for the Firestore project. -- `GCLOUD_TESTS_GOLANG_FIRESTORE_KEY`: The path to the JSON key file of the -Firestore project's service account. -- `GCLOUD_TESTS_GOLANG_KEYRING`: The full name of the keyring for the tests, -in the form -"projects/P/locations/L/keyRings/R". The creation of this is described below. -- `GCLOUD_TESTS_API_KEY`: API key for using the Translate API. -- `GCLOUD_TESTS_GOLANG_ZONE`: Compute Engine zone. - -Install the [gcloud command-line tool][gcloudcli] to your machine and use it to -create some resources used in integration tests. - -From the project's root directory: - -``` sh -# Sets the default project in your env. -$ gcloud config set project $GCLOUD_TESTS_GOLANG_PROJECT_ID - -# Authenticates the gcloud tool with your account. -$ gcloud auth login - -# Create the indexes used in the datastore integration tests. -$ gcloud datastore indexes create datastore/testdata/index.yaml - -# Creates a Google Cloud storage bucket with the same name as your test project, -# and with the Cloud Logging service account as owner, for the sink -# integration tests in logging. -$ gsutil mb gs://$GCLOUD_TESTS_GOLANG_PROJECT_ID -$ gsutil acl ch -g cloud-logs@google.com:O gs://$GCLOUD_TESTS_GOLANG_PROJECT_ID - -# Creates a PubSub topic for integration tests of storage notifications. -$ gcloud beta pubsub topics create go-storage-notification-test -# Next, go to the Pub/Sub dashboard in GCP console. Authorize the user -# "service-@gs-project-accounts.iam.gserviceaccount.com" -# as a publisher to that topic. - -# Creates a Spanner instance for the spanner integration tests. -$ gcloud beta spanner instances create go-integration-test --config regional-us-central1 --nodes 10 --description 'Instance for go client test' -# NOTE: Spanner instances are priced by the node-hour, so you may want to -# delete the instance after testing with 'gcloud beta spanner instances delete'. - -$ export MY_KEYRING=some-keyring-name -$ export MY_LOCATION=global -# Creates a KMS keyring, in the same location as the default location for your -# project's buckets. -$ gcloud kms keyrings create $MY_KEYRING --location $MY_LOCATION -# Creates two keys in the keyring, named key1 and key2. -$ gcloud kms keys create key1 --keyring $MY_KEYRING --location $MY_LOCATION --purpose encryption -$ gcloud kms keys create key2 --keyring $MY_KEYRING --location $MY_LOCATION --purpose encryption -# Sets the GCLOUD_TESTS_GOLANG_KEYRING environment variable. -$ export GCLOUD_TESTS_GOLANG_KEYRING=projects/$GCLOUD_TESTS_GOLANG_PROJECT_ID/locations/$MY_LOCATION/keyRings/$MY_KEYRING -# Authorizes Google Cloud Storage to encrypt and decrypt using key1. -gsutil kms authorize -p $GCLOUD_TESTS_GOLANG_PROJECT_ID -k $GCLOUD_TESTS_GOLANG_KEYRING/cryptoKeys/key1 -``` - -#### Running - -Once you've done the necessary setup, you can run the integration tests by -running: - -``` sh -$ go test -v cloud.google.com/go/... -``` - -#### Replay - -Some packages can record the RPCs during integration tests to a file for -subsequent replay. To record, pass the `-record` flag to `go test`. The -recording will be saved to the _package_`.replay` file. To replay integration -tests from a saved recording, the replay file must be present, the `-short` -flag must be passed to `go test`, and the `GCLOUD_TESTS_GOLANG_ENABLE_REPLAY` -environment variable must have a non-empty value. - -## Contributor License Agreements - -Before we can accept your pull requests you'll need to sign a Contributor -License Agreement (CLA): - -- **If you are an individual writing original source code** and **you own the -intellectual property**, then you'll need to sign an [individual CLA][indvcla]. -- **If you work for a company that wants to allow you to contribute your -work**, then you'll need to sign a [corporate CLA][corpcla]. - -You can sign these electronically (just scroll to the bottom). After that, -we'll be able to accept your pull requests. - -## Contributor Code of Conduct - -As contributors and maintainers of this project, -and in the interest of fostering an open and welcoming community, -we pledge to respect all people who contribute through reporting issues, -posting feature requests, updating documentation, -submitting pull requests or patches, and other activities. - -We are committed to making participation in this project -a harassment-free experience for everyone, -regardless of level of experience, gender, gender identity and expression, -sexual orientation, disability, personal appearance, -body size, race, ethnicity, age, religion, or nationality. - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery -* Personal attacks -* Trolling or insulting/derogatory comments -* Public or private harassment -* Publishing other's private information, -such as physical or electronic -addresses, without explicit permission -* Other unethical or unprofessional conduct. - -Project maintainers have the right and responsibility to remove, edit, or reject -comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct. -By adopting this Code of Conduct, -project maintainers commit themselves to fairly and consistently -applying these principles to every aspect of managing this project. -Project maintainers who do not follow or enforce the Code of Conduct -may be permanently removed from the project team. - -This code of conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. - -Instances of abusive, harassing, or otherwise unacceptable behavior -may be reported by opening an issue -or contacting one or more of the project maintainers. - -This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, -available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/) - -[gcloudcli]: https://developers.google.com/cloud/sdk/gcloud/ -[indvcla]: https://developers.google.com/open-source/cla/individual -[corpcla]: https://developers.google.com/open-source/cla/corporate diff --git a/vendor/cloud.google.com/go/README.md b/vendor/cloud.google.com/go/README.md deleted file mode 100644 index fdf6f73c1c3..00000000000 --- a/vendor/cloud.google.com/go/README.md +++ /dev/null @@ -1,177 +0,0 @@ -# Google Cloud Client Libraries for Go - -[![GoDoc](https://godoc.org/cloud.google.com/go?status.svg)](https://pkg.go.dev/cloud.google.com/go) - -Go packages for [Google Cloud Platform](https://cloud.google.com) services. - -``` go -import "cloud.google.com/go" -``` - -To install the packages on your system, *do not clone the repo*. Instead: - -1. Change to your project directory: - - ``` - cd /my/cloud/project - ``` -1. Get the package you want to use. Some products have their own module, so it's - best to `go get` the package(s) you want to use: - - ``` - $ go get cloud.google.com/go/firestore # Replace with the package you want to use. - ``` - -**NOTE:** Some of these packages are under development, and may occasionally -make backwards-incompatible changes. - -**NOTE:** Github repo is a mirror of [https://code.googlesource.com/gocloud](https://code.googlesource.com/gocloud). - -## Supported APIs - -| Google API | Status | Package | -| ----------------------------------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------- | -| [Asset][cloud-asset] | stable | [`cloud.google.com/go/asset/apiv1`](https://pkg.go.dev/cloud.google.com/go/asset/v1beta) | -| [Automl][cloud-automl] | stable | [`cloud.google.com/go/automl/apiv1`](https://pkg.go.dev/cloud.google.com/go/automl/apiv1) | -| [BigQuery][cloud-bigquery] | stable | [`cloud.google.com/go/bigquery`](https://pkg.go.dev/cloud.google.com/go/bigquery) | -| [Bigtable][cloud-bigtable] | stable | [`cloud.google.com/go/bigtable`](https://pkg.go.dev/cloud.google.com/go/bigtable) | -| [Cloudbuild][cloud-build] | stable | [`cloud.google.com/go/cloudbuild/apiv1`](https://pkg.go.dev/cloud.google.com/go/cloudbuild/apiv1) | -| [Cloudtasks][cloud-tasks] | stable | [`cloud.google.com/go/cloudtasks/apiv2`](https://pkg.go.dev/cloud.google.com/go/cloudtasks/apiv2) | -| [Container][cloud-container] | stable | [`cloud.google.com/go/container/apiv1`](https://pkg.go.dev/cloud.google.com/go/container/apiv1) | -| [ContainerAnalysis][cloud-containeranalysis] | beta | [`cloud.google.com/go/containeranalysis/apiv1`](https://pkg.go.dev/cloud.google.com/go/containeranalysis/apiv1) | -| [Dataproc][cloud-dataproc] | stable | [`cloud.google.com/go/dataproc/apiv1`](https://pkg.go.dev/cloud.google.com/go/dataproc/apiv1) | -| [Datastore][cloud-datastore] | stable | [`cloud.google.com/go/datastore`](https://pkg.go.dev/cloud.google.com/go/datastore) | -| [Debugger][cloud-debugger] | stable | [`cloud.google.com/go/debugger/apiv2`](https://pkg.go.dev/cloud.google.com/go/debugger/apiv2) | -| [Dialogflow][cloud-dialogflow] | stable | [`cloud.google.com/go/dialogflow/apiv2`](https://pkg.go.dev/cloud.google.com/go/dialogflow/apiv2) | -| [Data Loss Prevention][cloud-dlp] | stable | [`cloud.google.com/go/dlp/apiv2`](https://pkg.go.dev/cloud.google.com/go/dlp/apiv2) | -| [ErrorReporting][cloud-errors] | alpha | [`cloud.google.com/go/errorreporting`](https://pkg.go.dev/cloud.google.com/go/errorreporting) | -| [Firestore][cloud-firestore] | stable | [`cloud.google.com/go/firestore`](https://pkg.go.dev/cloud.google.com/go/firestore) | -| [IAM][cloud-iam] | stable | [`cloud.google.com/go/iam`](https://pkg.go.dev/cloud.google.com/go/iam) | -| [IoT][cloud-iot] | stable | [`cloud.google.com/go/iot/apiv1`](https://pkg.go.dev/cloud.google.com/go/iot/apiv1) | -| [IRM][cloud-irm] | alpha | [`cloud.google.com/go/irm/apiv1alpha2`](https://pkg.go.dev/cloud.google.com/go/irm/apiv1alpha2) | -| [KMS][cloud-kms] | stable | [`cloud.google.com/go/kms/apiv1`](https://pkg.go.dev/cloud.google.com/go/kms/apiv1) | -| [Natural Language][cloud-natural-language] | stable | [`cloud.google.com/go/language/apiv1`](https://pkg.go.dev/cloud.google.com/go/language/apiv1) | -| [Logging][cloud-logging] | stable | [`cloud.google.com/go/logging`](https://pkg.go.dev/cloud.google.com/go/logging) | -| [Memorystore][cloud-memorystore] | alpha | [`cloud.google.com/go/redis/apiv1`](https://pkg.go.dev/cloud.google.com/go/redis/apiv1) | -| [Monitoring][cloud-monitoring] | stable | [`cloud.google.com/go/monitoring/apiv3`](https://pkg.go.dev/cloud.google.com/go/monitoring/apiv3) | -| [OS Login][cloud-oslogin] | stable | [`cloud.google.com/go/oslogin/apiv1`](https://pkg.go.dev/cloud.google.com/go/oslogin/apiv1) | -| [Pub/Sub][cloud-pubsub] | stable | [`cloud.google.com/go/pubsub`](https://pkg.go.dev/cloud.google.com/go/pubsub) | -| [Phishing Protection][cloud-phishingprotection] | alpha | [`cloud.google.com/go/phishingprotection/apiv1beta1`](https://pkg.go.dev/cloud.google.com/go/phishingprotection/apiv1beta1) | -| [reCAPTCHA Enterprise][cloud-recaptcha] | alpha | [`cloud.google.com/go/recaptchaenterprise/apiv1beta1`](https://pkg.go.dev/cloud.google.com/go/recaptchaenterprise/apiv1beta1) | -| [Recommender][cloud-recommender] | beta | [`cloud.google.com/go/recommender/apiv1beta1`](https://pkg.go.dev/cloud.google.com/go/recommender/apiv1beta1) | -| [Scheduler][cloud-scheduler] | stable | [`cloud.google.com/go/scheduler/apiv1`](https://pkg.go.dev/cloud.google.com/go/scheduler/apiv1) | -| [Securitycenter][cloud-securitycenter] | stable | [`cloud.google.com/go/securitycenter/apiv1`](https://pkg.go.dev/cloud.google.com/go/securitycenter/apiv1) | -| [Spanner][cloud-spanner] | stable | [`cloud.google.com/go/spanner`](https://pkg.go.dev/cloud.google.com/go/spanner) | -| [Speech][cloud-speech] | stable | [`cloud.google.com/go/speech/apiv1`](https://pkg.go.dev/cloud.google.com/go/speech/apiv1) | -| [Storage][cloud-storage] | stable | [`cloud.google.com/go/storage`](https://pkg.go.dev/cloud.google.com/go/storage) | -| [Talent][cloud-talent] | alpha | [`cloud.google.com/go/talent/apiv4beta1`](https://pkg.go.dev/cloud.google.com/go/talent/apiv4beta1) | -| [Text To Speech][cloud-texttospeech] | stable | [`cloud.google.com/go/texttospeech/apiv1`](https://pkg.go.dev/cloud.google.com/go/texttospeech/apiv1) | -| [Trace][cloud-trace] | stable | [`cloud.google.com/go/trace/apiv2`](https://pkg.go.dev/cloud.google.com/go/trace/apiv2) | -| [Translate][cloud-translate] | stable | [`cloud.google.com/go/translate`](https://pkg.go.dev/cloud.google.com/go/translate) | -| [Video Intelligence][cloud-video] | beta | [`cloud.google.com/go/videointelligence/apiv1beta2`](https://pkg.go.dev/cloud.google.com/go/videointelligence/apiv1beta2) | -| [Vision][cloud-vision] | stable | [`cloud.google.com/go/vision/apiv1`](https://pkg.go.dev/cloud.google.com/go/vision/apiv1) | -| [Webrisk][cloud-webrisk] | alpha | [`cloud.google.com/go/webrisk/apiv1beta1`](https://pkg.go.dev/cloud.google.com/go/webrisk/apiv1beta1) | - -> **Alpha status**: the API is still being actively developed. As a -> result, it might change in backward-incompatible ways and is not recommended -> for production use. -> -> **Beta status**: the API is largely complete, but still has outstanding -> features and bugs to be addressed. There may be minor backwards-incompatible -> changes where necessary. -> -> **Stable status**: the API is mature and ready for production use. We will -> continue addressing bugs and feature requests. - -Documentation and examples are available at [pkg.go.dev/cloud.google.com/go](https://pkg.go.dev/cloud.google.com/go) - -## [Go Versions Supported](#supported-versions) - -We currently support Go versions 1.11 and newer. - -## Authorization - -By default, each API will use [Google Application Default Credentials](https://developers.google.com/identity/protocols/application-default-credentials) -for authorization credentials used in calling the API endpoints. This will allow your -application to run in many environments without requiring explicit configuration. - -[snip]:# (auth) -```go -client, err := storage.NewClient(ctx) -``` - -To authorize using a -[JSON key file](https://cloud.google.com/iam/docs/managing-service-account-keys), -pass -[`option.WithCredentialsFile`](https://pkg.go.dev/google.golang.org/api/option#WithCredentialsFile) -to the `NewClient` function of the desired package. For example: - -[snip]:# (auth-JSON) -```go -client, err := storage.NewClient(ctx, option.WithCredentialsFile("path/to/keyfile.json")) -``` - -You can exert more control over authorization by using the -[`golang.org/x/oauth2`](https://pkg.go.dev/golang.org/x/oauth2) package to -create an `oauth2.TokenSource`. Then pass -[`option.WithTokenSource`](https://pkg.go.dev/google.golang.org/api/option#WithTokenSource) -to the `NewClient` function: -[snip]:# (auth-ts) -```go -tokenSource := ... -client, err := storage.NewClient(ctx, option.WithTokenSource(tokenSource)) -``` - -## Contributing - -Contributions are welcome. Please, see the -[CONTRIBUTING](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/master/CONTRIBUTING.md) -document for details. - -Please note that this project is released with a Contributor Code of Conduct. -By participating in this project you agree to abide by its terms. -See [Contributor Code of Conduct](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/master/CONTRIBUTING.md#contributor-code-of-conduct) -for more information. - -[cloud-asset]: https://cloud.google.com/security-command-center/docs/how-to-asset-inventory -[cloud-automl]: https://cloud.google.com/automl -[cloud-build]: https://cloud.google.com/cloud-build/ -[cloud-bigquery]: https://cloud.google.com/bigquery/ -[cloud-bigtable]: https://cloud.google.com/bigtable/ -[cloud-container]: https://cloud.google.com/containers/ -[cloud-containeranalysis]: https://cloud.google.com/container-registry/docs/container-analysis -[cloud-dataproc]: https://cloud.google.com/dataproc/ -[cloud-datastore]: https://cloud.google.com/datastore/ -[cloud-dialogflow]: https://cloud.google.com/dialogflow-enterprise/ -[cloud-debugger]: https://cloud.google.com/debugger/ -[cloud-dlp]: https://cloud.google.com/dlp/ -[cloud-errors]: https://cloud.google.com/error-reporting/ -[cloud-firestore]: https://cloud.google.com/firestore/ -[cloud-iam]: https://cloud.google.com/iam/ -[cloud-iot]: https://cloud.google.com/iot-core/ -[cloud-irm]: https://cloud.google.com/incident-response/docs/concepts -[cloud-kms]: https://cloud.google.com/kms/ -[cloud-pubsub]: https://cloud.google.com/pubsub/ -[cloud-storage]: https://cloud.google.com/storage/ -[cloud-language]: https://cloud.google.com/natural-language -[cloud-logging]: https://cloud.google.com/logging/ -[cloud-natural-language]: https://cloud.google.com/natural-language/ -[cloud-memorystore]: https://cloud.google.com/memorystore/ -[cloud-monitoring]: https://cloud.google.com/monitoring/ -[cloud-oslogin]: https://cloud.google.com/compute/docs/oslogin/rest -[cloud-phishingprotection]: https://cloud.google.com/phishing-protection/ -[cloud-securitycenter]: https://cloud.google.com/security-command-center/ -[cloud-scheduler]: https://cloud.google.com/scheduler -[cloud-spanner]: https://cloud.google.com/spanner/ -[cloud-speech]: https://cloud.google.com/speech -[cloud-talent]: https://cloud.google.com/solutions/talent-solution/ -[cloud-tasks]: https://cloud.google.com/tasks/ -[cloud-texttospeech]: https://cloud.google.com/texttospeech/ -[cloud-talent]: https://cloud.google.com/solutions/talent-solution/ -[cloud-trace]: https://cloud.google.com/trace/ -[cloud-translate]: https://cloud.google.com/translate -[cloud-recaptcha]: https://cloud.google.com/recaptcha-enterprise/ -[cloud-recommender]: https://cloud.google.com/recommendations/ -[cloud-video]: https://cloud.google.com/video-intelligence/ -[cloud-vision]: https://cloud.google.com/vision -[cloud-webrisk]: https://cloud.google.com/web-risk/ diff --git a/vendor/cloud.google.com/go/RELEASING.md b/vendor/cloud.google.com/go/RELEASING.md deleted file mode 100644 index 12e0c6104b9..00000000000 --- a/vendor/cloud.google.com/go/RELEASING.md +++ /dev/null @@ -1,149 +0,0 @@ -# Releasing - -## Setup environment from scratch - -1. [Install Go](https://golang.org/dl/). - 1. Ensure that your `GOBIN` directory (by default `$(go env GOPATH)/bin`) - is in your `PATH`. - 1. Check it's working by running `go version`. - * If it doesn't work, check the install location, usually - `/usr/local/go`, is on your `PATH`. - -1. Sign one of the -[contributor license agreements](#contributor-license-agreements) below. - -1. Clone the repo: - `git clone https://github.com/googleapis/google-cloud-go` - -1. Change into the checked out source: - `cd google-cloud-go` - -1. Fork the repo and add your fork as a secondary remote (this is necessary in - order to create PRs). - -## Determine which module to release - -The Go client libraries have several modules. Each module does not strictly -correspond to a single library - they correspond to trees of directories. If a -file needs to be released, you must release the closest ancestor module. - -To see all modules: - -```bash -$ cat `find . -name go.mod` | grep module -module cloud.google.com/go -module cloud.google.com/go/bigtable -module cloud.google.com/go/firestore -module cloud.google.com/go/bigquery -module cloud.google.com/go/storage -module cloud.google.com/go/datastore -module cloud.google.com/go/pubsub -module cloud.google.com/go/spanner -module cloud.google.com/go/logging -``` - -The `cloud.google.com/go` is the repository root module. Each other module is -a submodule. - -So, if you need to release a change in `bigtable/bttest/inmem.go`, the closest -ancestor module is `cloud.google.com/go/bigtable` - so you should release a new -version of the `cloud.google.com/go/bigtable` submodule. - -If you need to release a change in `asset/apiv1/asset_client.go`, the closest -ancestor module is `cloud.google.com/go` - so you should release a new version -of the `cloud.google.com/go` repository root module. Note: releasing -`cloud.google.com/go` has no impact on any of the submodules, and vice-versa. -They are released entirely independently. - -## Test failures - -If there are any test failures in the Kokoro build, releases are blocked until -the failures have been resolved. - -## How to release `cloud.google.com/go` - -Check for failures in the [continuous Kokoro build](http://go/google-cloud-go-continuous). -If there are any failures in the most recent build, address them before -proceeding with the release. - -### Automated Release - -If there are changes that have not yet been released a -[pull request](https://github.com/googleapis/google-cloud-go/pull/2971) should -be automatically opened by [release-please](https://github.com/googleapis/release-please) -with a title like "chore: release 0.XX.0", where XX is the next version to be -released. To cut a release, approve and merge this pull request. Doing so will -update the `CHANGES.md`, tag the merged commit with the appropriate version, -and draft a GitHub release. - -### Manual Release - -If for whatever reason the automated release process is not working as expected, -here is how to manually cut a release. - -1. Navigate to `google-cloud-go/` and switch to master. -1. `git pull` -1. Run `git tag -l | grep -v beta | grep -v alpha` to see all existing releases. - The current latest tag `$CV` is the largest tag. It should look something - like `vX.Y.Z` (note: ignore all `LIB/vX.Y.Z` tags - these are tags for a - specific library, not the module root). We'll call the current version `$CV` - and the new version `$NV`. -1. On master, run `git log $CV...` to list all the changes since the last - release. NOTE: You must manually visually parse out changes to submodules [1] - (the `git log` is going to show you things in submodules, which are not going - to be part of your release). -1. Edit `CHANGES.md` to include a summary of the changes. -1. In `internal/version/version.go`, update `const Repo` to today's date with - the format `YYYYMMDD`. -1. In `internal/version` run `go generate`. -1. Commit the changes, ignoring the generated `.go-r` file. Push to your fork, - and create a PR titled `chore: release $NV`. -1. Wait for the PR to be reviewed and merged. Once it's merged, and without - merging any other PRs in the meantime: - a. Switch to master. - b. `git pull` - c. Tag the repo with the next version: `git tag $NV`. - d. Push the tag to origin: - `git push origin $NV` -1. Update [the releases page](https://github.com/googleapis/google-cloud-go/releases) - with the new release, copying the contents of `CHANGES.md`. - -## How to release a submodule - -We have several submodules, including `cloud.google.com/go/logging`, -`cloud.google.com/go/datastore`, and so on. - -To release a submodule: - -(these instructions assume we're releasing `cloud.google.com/go/datastore` - adjust accordingly) - -1. Check for failures in the - [continuous Kokoro build](http://go/google-cloud-go-continuous). If there are - any failures in the most recent build, address them before proceeding with - the release. (This applies even if the failures are in a different submodule - from the one being released.) -1. Navigate to `google-cloud-go/` and switch to master. -1. `git pull` -1. Run `git tag -l | grep datastore | grep -v beta | grep -v alpha` to see all - existing releases. The current latest tag `$CV` is the largest tag. It - should look something like `datastore/vX.Y.Z`. We'll call the current version - `$CV` and the new version `$NV`. -1. On master, run `git log $CV.. -- datastore/` to list all the changes to the - submodule directory since the last release. -1. Edit `datastore/CHANGES.md` to include a summary of the changes. -1. In `internal/version` run `go generate`. -1. Commit the changes, ignoring the generated `.go-r` file. Push to your fork, - and create a PR titled `chore(datastore): release $NV`. -1. Wait for the PR to be reviewed and merged. Once it's merged, and without - merging any other PRs in the meantime: - a. Switch to master. - b. `git pull` - c. Tag the repo with the next version: `git tag $NV`. - d. Push the tag to origin: - `git push origin $NV` -1. Update [the releases page](https://github.com/googleapis/google-cloud-go/releases) - with the new release, copying the contents of `datastore/CHANGES.md`. - -## Appendix - -1: This should get better as submodule tooling matures. diff --git a/vendor/cloud.google.com/go/compute/LICENSE b/vendor/cloud.google.com/go/compute/LICENSE new file mode 100644 index 00000000000..d6456956733 --- /dev/null +++ b/vendor/cloud.google.com/go/compute/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/cloud.google.com/go/compute/internal/version.go b/vendor/cloud.google.com/go/compute/internal/version.go new file mode 100644 index 00000000000..a5b020992b8 --- /dev/null +++ b/vendor/cloud.google.com/go/compute/internal/version.go @@ -0,0 +1,18 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package internal + +// Version is the current tagged release of the library. +const Version = "1.19.1" diff --git a/vendor/cloud.google.com/go/compute/metadata/CHANGES.md b/vendor/cloud.google.com/go/compute/metadata/CHANGES.md new file mode 100644 index 00000000000..06b957349af --- /dev/null +++ b/vendor/cloud.google.com/go/compute/metadata/CHANGES.md @@ -0,0 +1,19 @@ +# Changes + +## [0.2.3](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.2.2...compute/metadata/v0.2.3) (2022-12-15) + + +### Bug Fixes + +* **compute/metadata:** Switch DNS lookup to an absolute lookup ([119b410](https://github.com/googleapis/google-cloud-go/commit/119b41060c7895e45e48aee5621ad35607c4d021)), refs [#7165](https://github.com/googleapis/google-cloud-go/issues/7165) + +## [0.2.2](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.2.1...compute/metadata/v0.2.2) (2022-12-01) + + +### Bug Fixes + +* **compute/metadata:** Set IdleConnTimeout for http.Client ([#7084](https://github.com/googleapis/google-cloud-go/issues/7084)) ([766516a](https://github.com/googleapis/google-cloud-go/commit/766516aaf3816bfb3159efeea65aa3d1d205a3e2)), refs [#5430](https://github.com/googleapis/google-cloud-go/issues/5430) + +## [0.1.0] (2022-10-26) + +Initial release of metadata being it's own module. diff --git a/vendor/cloud.google.com/go/compute/metadata/LICENSE b/vendor/cloud.google.com/go/compute/metadata/LICENSE new file mode 100644 index 00000000000..d6456956733 --- /dev/null +++ b/vendor/cloud.google.com/go/compute/metadata/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/cloud.google.com/go/compute/metadata/README.md b/vendor/cloud.google.com/go/compute/metadata/README.md new file mode 100644 index 00000000000..f940fb2c85b --- /dev/null +++ b/vendor/cloud.google.com/go/compute/metadata/README.md @@ -0,0 +1,27 @@ +# Compute API + +[![Go Reference](https://pkg.go.dev/badge/cloud.google.com/go/compute.svg)](https://pkg.go.dev/cloud.google.com/go/compute/metadata) + +This is a utility library for communicating with Google Cloud metadata service +on Google Cloud. + +## Install + +```bash +go get cloud.google.com/go/compute/metadata +``` + +## Go Version Support + +See the [Go Versions Supported](https://github.com/googleapis/google-cloud-go#go-versions-supported) +section in the root directory's README. + +## Contributing + +Contributions are welcome. Please, see the [CONTRIBUTING](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/main/CONTRIBUTING.md) +document for details. + +Please note that this project is released with a Contributor Code of Conduct. +By participating in this project you agree to abide by its terms. See +[Contributor Code of Conduct](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/main/CONTRIBUTING.md#contributor-code-of-conduct) +for more information. diff --git a/vendor/cloud.google.com/go/compute/metadata/metadata.go b/vendor/cloud.google.com/go/compute/metadata/metadata.go index 545bd9d379c..c17faa142a4 100644 --- a/vendor/cloud.google.com/go/compute/metadata/metadata.go +++ b/vendor/cloud.google.com/go/compute/metadata/metadata.go @@ -16,7 +16,7 @@ // metadata and API service accounts. // // This package is a wrapper around the GCE metadata service, -// as documented at https://developers.google.com/compute/docs/metadata. +// as documented at https://cloud.google.com/compute/docs/metadata/overview. package metadata // import "cloud.google.com/go/compute/metadata" import ( @@ -61,14 +61,20 @@ var ( instID = &cachedValue{k: "instance/id", trim: true} ) -var defaultClient = &Client{hc: &http.Client{ - Transport: &http.Transport{ - Dial: (&net.Dialer{ - Timeout: 2 * time.Second, - KeepAlive: 30 * time.Second, - }).Dial, - }, -}} +var defaultClient = &Client{hc: newDefaultHTTPClient()} + +func newDefaultHTTPClient() *http.Client { + return &http.Client{ + Transport: &http.Transport{ + Dial: (&net.Dialer{ + Timeout: 2 * time.Second, + KeepAlive: 30 * time.Second, + }).Dial, + IdleConnTimeout: 60 * time.Second, + }, + Timeout: 5 * time.Second, + } +} // NotDefinedError is returned when requested metadata is not defined. // @@ -130,7 +136,7 @@ func testOnGCE() bool { go func() { req, _ := http.NewRequest("GET", "http://"+metadataIP, nil) req.Header.Set("User-Agent", userAgent) - res, err := defaultClient.hc.Do(req.WithContext(ctx)) + res, err := newDefaultHTTPClient().Do(req.WithContext(ctx)) if err != nil { resc <- false return @@ -140,7 +146,8 @@ func testOnGCE() bool { }() go func() { - addrs, err := net.DefaultResolver.LookupHost(ctx, "metadata.google.internal") + resolver := &net.Resolver{} + addrs, err := resolver.LookupHost(ctx, "metadata.google.internal.") if err != nil || len(addrs) == 0 { resc <- false return @@ -282,6 +289,7 @@ func NewClient(c *http.Client) *Client { // getETag returns a value from the metadata service as well as the associated ETag. // This func is otherwise equivalent to Get. func (c *Client) getETag(suffix string) (value, etag string, err error) { + ctx := context.TODO() // Using a fixed IP makes it very difficult to spoof the metadata service in // a container, which is an important use-case for local testing of cloud // deployments. To enable spoofing of the metadata service, the environment @@ -304,9 +312,25 @@ func (c *Client) getETag(suffix string) (value, etag string, err error) { } req.Header.Set("Metadata-Flavor", "Google") req.Header.Set("User-Agent", userAgent) - res, err := c.hc.Do(req) - if err != nil { - return "", "", err + var res *http.Response + var reqErr error + retryer := newRetryer() + for { + res, reqErr = c.hc.Do(req) + var code int + if res != nil { + code = res.StatusCode + } + if delay, shouldRetry := retryer.Retry(code, reqErr); shouldRetry { + if err := sleep(ctx, delay); err != nil { + return "", "", err + } + continue + } + break + } + if reqErr != nil { + return "", "", reqErr } defer res.Body.Close() if res.StatusCode == http.StatusNotFound { diff --git a/vendor/cloud.google.com/go/compute/metadata/retry.go b/vendor/cloud.google.com/go/compute/metadata/retry.go new file mode 100644 index 00000000000..0f18f3cda1e --- /dev/null +++ b/vendor/cloud.google.com/go/compute/metadata/retry.go @@ -0,0 +1,114 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package metadata + +import ( + "context" + "io" + "math/rand" + "net/http" + "time" +) + +const ( + maxRetryAttempts = 5 +) + +var ( + syscallRetryable = func(err error) bool { return false } +) + +// defaultBackoff is basically equivalent to gax.Backoff without the need for +// the dependency. +type defaultBackoff struct { + max time.Duration + mul float64 + cur time.Duration +} + +func (b *defaultBackoff) Pause() time.Duration { + d := time.Duration(1 + rand.Int63n(int64(b.cur))) + b.cur = time.Duration(float64(b.cur) * b.mul) + if b.cur > b.max { + b.cur = b.max + } + return d +} + +// sleep is the equivalent of gax.Sleep without the need for the dependency. +func sleep(ctx context.Context, d time.Duration) error { + t := time.NewTimer(d) + select { + case <-ctx.Done(): + t.Stop() + return ctx.Err() + case <-t.C: + return nil + } +} + +func newRetryer() *metadataRetryer { + return &metadataRetryer{bo: &defaultBackoff{ + cur: 100 * time.Millisecond, + max: 30 * time.Second, + mul: 2, + }} +} + +type backoff interface { + Pause() time.Duration +} + +type metadataRetryer struct { + bo backoff + attempts int +} + +func (r *metadataRetryer) Retry(status int, err error) (time.Duration, bool) { + if status == http.StatusOK { + return 0, false + } + retryOk := shouldRetry(status, err) + if !retryOk { + return 0, false + } + if r.attempts == maxRetryAttempts { + return 0, false + } + r.attempts++ + return r.bo.Pause(), true +} + +func shouldRetry(status int, err error) bool { + if 500 <= status && status <= 599 { + return true + } + if err == io.ErrUnexpectedEOF { + return true + } + // Transient network errors should be retried. + if syscallRetryable(err) { + return true + } + if err, ok := err.(interface{ Temporary() bool }); ok { + if err.Temporary() { + return true + } + } + if err, ok := err.(interface{ Unwrap() error }); ok { + return shouldRetry(status, err.Unwrap()) + } + return false +} diff --git a/vendor/cloud.google.com/go/compute/metadata/retry_linux.go b/vendor/cloud.google.com/go/compute/metadata/retry_linux.go new file mode 100644 index 00000000000..bb412f8917e --- /dev/null +++ b/vendor/cloud.google.com/go/compute/metadata/retry_linux.go @@ -0,0 +1,26 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:build linux +// +build linux + +package metadata + +import "syscall" + +func init() { + // Initialize syscallRetryable to return true on transient socket-level + // errors. These errors are specific to Linux. + syscallRetryable = func(err error) bool { return err == syscall.ECONNRESET || err == syscall.ECONNREFUSED } +} diff --git a/vendor/cloud.google.com/go/storage/go_mod_tidy_hack.go b/vendor/cloud.google.com/go/compute/metadata/tidyfix.go similarity index 80% rename from vendor/cloud.google.com/go/storage/go_mod_tidy_hack.go rename to vendor/cloud.google.com/go/compute/metadata/tidyfix.go index 7df7a1d7155..4cef4850081 100644 --- a/vendor/cloud.google.com/go/storage/go_mod_tidy_hack.go +++ b/vendor/cloud.google.com/go/compute/metadata/tidyfix.go @@ -1,4 +1,4 @@ -// Copyright 2019 Google LLC +// Copyright 2022 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,11 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -// This file, and the cloud.google.com/go import, won't actually become part of +// This file, and the {{.RootMod}} import, won't actually become part of // the resultant binary. +//go:build modhack // +build modhack -package storage +package metadata // Necessary for safely adding multi-module repo. See: https://github.com/golang/go/wiki/Modules#is-it-possible-to-add-a-module-to-a-multi-module-repository -import _ "cloud.google.com/go" +import _ "cloud.google.com/go/compute/internal" diff --git a/vendor/cloud.google.com/go/doc.go b/vendor/cloud.google.com/go/doc.go deleted file mode 100644 index 0130d7422d4..00000000000 --- a/vendor/cloud.google.com/go/doc.go +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2014 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/* -Package cloud is the root of the packages used to access Google Cloud -Services. See https://godoc.org/cloud.google.com/go for a full list -of sub-packages. - - -Client Options - -All clients in sub-packages are configurable via client options. These options are -described here: https://godoc.org/google.golang.org/api/option. - - -Authentication and Authorization - -All the clients in sub-packages support authentication via Google Application Default -Credentials (see https://cloud.google.com/docs/authentication/production), or -by providing a JSON key file for a Service Account. See the authentication examples -in this package for details. - - -Timeouts and Cancellation - -By default, non-streaming methods, like Create or Get, will have a default deadline applied to the -context provided at call time, unless a context deadline is already set. Streaming -methods have no default deadline and will run indefinitely. To set timeouts or -arrange for cancellation, use contexts. See the examples for details. Transient -errors will be retried when correctness allows. - -To opt out of default deadlines, set the temporary environment variable -GOOGLE_API_GO_EXPERIMENTAL_DISABLE_DEFAULT_DEADLINE to "true" prior to client -creation. This affects all Google Cloud Go client libraries. This opt-out -mechanism will be removed in a future release. File an issue at -https://github.com/googleapis/google-cloud-go if the default deadlines -cannot work for you. - -Do not attempt to control the initial connection (dialing) of a service by setting a -timeout on the context passed to NewClient. Dialing is non-blocking, so timeouts -would be ineffective and would only interfere with credential refreshing, which uses -the same context. - - -Connection Pooling - -Connection pooling differs in clients based on their transport. Cloud -clients either rely on HTTP or gRPC transports to communicate -with Google Cloud. - -Cloud clients that use HTTP (bigquery, compute, storage, and translate) rely on the -underlying HTTP transport to cache connections for later re-use. These are cached to -the default http.MaxIdleConns and http.MaxIdleConnsPerHost settings in -http.DefaultTransport. - -For gRPC clients (all others in this repo), connection pooling is configurable. Users -of cloud client libraries may specify option.WithGRPCConnectionPool(n) as a client -option to NewClient calls. This configures the underlying gRPC connections to be -pooled and addressed in a round robin fashion. - - -Using the Libraries with Docker - -Minimal docker images like Alpine lack CA certificates. This causes RPCs to appear to -hang, because gRPC retries indefinitely. See https://github.com/googleapis/google-cloud-go/issues/928 -for more information. - - -Debugging - -To see gRPC logs, set the environment variable GRPC_GO_LOG_SEVERITY_LEVEL. See -https://godoc.org/google.golang.org/grpc/grpclog for more information. - -For HTTP logging, set the GODEBUG environment variable to "http2debug=1" or "http2debug=2". - - -Client Stability - -Clients in this repository are considered alpha or beta unless otherwise -marked as stable in the README.md. Semver is not used to communicate stability -of clients. - -Alpha and beta clients may change or go away without notice. - -Clients marked stable will maintain compatibility with future versions for as -long as we can reasonably sustain. Incompatible changes might be made in some -situations, including: - -- Security bugs may prompt backwards-incompatible changes. - -- Situations in which components are no longer feasible to maintain without -making breaking changes, including removal. - -- Parts of the client surface may be outright unstable and subject to change. -These parts of the surface will be labeled with the note, "It is EXPERIMENTAL -and subject to change or removal without notice." -*/ -package cloud // import "cloud.google.com/go" diff --git a/vendor/cloud.google.com/go/iam/CHANGES.md b/vendor/cloud.google.com/go/iam/CHANGES.md new file mode 100644 index 00000000000..40ae15de52e --- /dev/null +++ b/vendor/cloud.google.com/go/iam/CHANGES.md @@ -0,0 +1,97 @@ +# Changes + +## [0.13.0](https://github.com/googleapis/google-cloud-go/compare/iam/v0.12.0...iam/v0.13.0) (2023-03-15) + + +### Features + +* **iam:** Update iam and longrunning deps ([91a1f78](https://github.com/googleapis/google-cloud-go/commit/91a1f784a109da70f63b96414bba8a9b4254cddd)) + +## [0.12.0](https://github.com/googleapis/google-cloud-go/compare/iam/v0.11.0...iam/v0.12.0) (2023-02-17) + + +### Features + +* **iam:** Migrate to new stubs ([a61ddcd](https://github.com/googleapis/google-cloud-go/commit/a61ddcd3041c7af4a15109dc4431f9b327c497fb)) + +## [0.11.0](https://github.com/googleapis/google-cloud-go/compare/iam/v0.10.0...iam/v0.11.0) (2023-02-16) + + +### Features + +* **iam:** Start generating proto stubs ([970d763](https://github.com/googleapis/google-cloud-go/commit/970d763531b54b2bc75d7ff26a20b6e05150cab8)) + +## [0.10.0](https://github.com/googleapis/google-cloud-go/compare/iam/v0.9.0...iam/v0.10.0) (2023-01-04) + + +### Features + +* **iam:** Add REST client ([06a54a1](https://github.com/googleapis/google-cloud-go/commit/06a54a16a5866cce966547c51e203b9e09a25bc0)) + +## [0.9.0](https://github.com/googleapis/google-cloud-go/compare/iam/v0.8.0...iam/v0.9.0) (2022-12-15) + + +### Features + +* **iam:** Rewrite iam sigs and update proto import ([#7137](https://github.com/googleapis/google-cloud-go/issues/7137)) ([ad67fa3](https://github.com/googleapis/google-cloud-go/commit/ad67fa36c263c161226f7fecbab5221592374dca)) + +## [0.8.0](https://github.com/googleapis/google-cloud-go/compare/iam/v0.7.0...iam/v0.8.0) (2022-12-05) + + +### Features + +* **iam:** Start generating and refresh some libraries ([#7089](https://github.com/googleapis/google-cloud-go/issues/7089)) ([a9045ff](https://github.com/googleapis/google-cloud-go/commit/a9045ff191a711089c37f1d94a63522d9939ce38)) + +## [0.7.0](https://github.com/googleapis/google-cloud-go/compare/iam/v0.6.0...iam/v0.7.0) (2022-11-03) + + +### Features + +* **iam:** rewrite signatures in terms of new location ([3c4b2b3](https://github.com/googleapis/google-cloud-go/commit/3c4b2b34565795537aac1661e6af2442437e34ad)) + +## [0.6.0](https://github.com/googleapis/google-cloud-go/compare/iam/v0.5.0...iam/v0.6.0) (2022-10-25) + + +### Features + +* **iam:** start generating stubs dir ([de2d180](https://github.com/googleapis/google-cloud-go/commit/de2d18066dc613b72f6f8db93ca60146dabcfdcc)) + +## [0.5.0](https://github.com/googleapis/google-cloud-go/compare/iam/v0.4.0...iam/v0.5.0) (2022-09-28) + + +### Features + +* **iam:** remove ListApplicablePolicies ([52dddd1](https://github.com/googleapis/google-cloud-go/commit/52dddd1ed89fbe77e1859311c3b993a77a82bfc7)) + +## [0.4.0](https://github.com/googleapis/google-cloud-go/compare/iam/v0.3.0...iam/v0.4.0) (2022-09-06) + + +### Features + +* **iam:** start generating apiv2 ([#6605](https://github.com/googleapis/google-cloud-go/issues/6605)) ([a6004e7](https://github.com/googleapis/google-cloud-go/commit/a6004e762f782869cd85688937475744f7b17e50)) + +## [0.3.0](https://github.com/googleapis/google-cloud-go/compare/iam/v0.2.0...iam/v0.3.0) (2022-02-23) + + +### Features + +* **iam:** set versionClient to module version ([55f0d92](https://github.com/googleapis/google-cloud-go/commit/55f0d92bf112f14b024b4ab0076c9875a17423c9)) + +## [0.2.0](https://github.com/googleapis/google-cloud-go/compare/iam/v0.1.1...iam/v0.2.0) (2022-02-14) + + +### Features + +* **iam:** add file for tracking version ([17b36ea](https://github.com/googleapis/google-cloud-go/commit/17b36ead42a96b1a01105122074e65164357519e)) + +### [0.1.1](https://www.github.com/googleapis/google-cloud-go/compare/iam/v0.1.0...iam/v0.1.1) (2022-01-14) + + +### Bug Fixes + +* **iam:** run formatter ([#5277](https://www.github.com/googleapis/google-cloud-go/issues/5277)) ([8682e4e](https://www.github.com/googleapis/google-cloud-go/commit/8682e4ed57a4428a659fbc225f56c91767e2a4a9)) + +## v0.1.0 + +This is the first tag to carve out iam as its own module. See +[Add a module to a multi-module repository](https://github.com/golang/go/wiki/Modules#is-it-possible-to-add-a-module-to-a-multi-module-repository). diff --git a/vendor/cloud.google.com/go/iam/LICENSE b/vendor/cloud.google.com/go/iam/LICENSE new file mode 100644 index 00000000000..d6456956733 --- /dev/null +++ b/vendor/cloud.google.com/go/iam/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/cloud.google.com/go/iam/README.md b/vendor/cloud.google.com/go/iam/README.md new file mode 100644 index 00000000000..0072cc9e294 --- /dev/null +++ b/vendor/cloud.google.com/go/iam/README.md @@ -0,0 +1,40 @@ +# IAM API + +[![Go Reference](https://pkg.go.dev/badge/cloud.google.com/go/iam.svg)](https://pkg.go.dev/cloud.google.com/go/iam) + +Go Client Library for IAM API. + +## Install + +```bash +go get cloud.google.com/go/iam +``` + +## Stability + +The stability of this module is indicated by SemVer. + +However, a `v1+` module may have breaking changes in two scenarios: + +* Packages with `alpha` or `beta` in the import path +* The GoDoc has an explicit stability disclaimer (for example, for an experimental feature). + +## Go Version Support + +See the [Go Versions Supported](https://github.com/googleapis/google-cloud-go#go-versions-supported) +section in the root directory's README. + +## Authorization + +See the [Authorization](https://github.com/googleapis/google-cloud-go#authorization) +section in the root directory's README. + +## Contributing + +Contributions are welcome. Please, see the [CONTRIBUTING](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/main/CONTRIBUTING.md) +document for details. + +Please note that this project is released with a Contributor Code of Conduct. +By participating in this project you agree to abide by its terms. See +[Contributor Code of Conduct](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/main/CONTRIBUTING.md#contributor-code-of-conduct) +for more information. diff --git a/vendor/google.golang.org/genproto/googleapis/iam/v1/iam_policy.pb.go b/vendor/cloud.google.com/go/iam/apiv1/iampb/iam_policy.pb.go similarity index 85% rename from vendor/google.golang.org/genproto/googleapis/iam/v1/iam_policy.pb.go rename to vendor/cloud.google.com/go/iam/apiv1/iampb/iam_policy.pb.go index 8a0cca603e4..21079f65c3b 100644 --- a/vendor/google.golang.org/genproto/googleapis/iam/v1/iam_policy.pb.go +++ b/vendor/cloud.google.com/go/iam/apiv1/iampb/iam_policy.pb.go @@ -1,4 +1,4 @@ -// Copyright 2019 Google LLC. +// Copyright 2022 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -11,28 +11,27 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -// // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.25.0 -// protoc v3.13.0 +// protoc-gen-go v1.26.0 +// protoc v3.21.9 // source: google/iam/v1/iam_policy.proto -package iam +package iampb import ( context "context" reflect "reflect" sync "sync" - proto "github.com/golang/protobuf/proto" _ "google.golang.org/genproto/googleapis/api/annotations" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + fieldmaskpb "google.golang.org/protobuf/types/known/fieldmaskpb" ) const ( @@ -42,10 +41,6 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - // Request message for `SetIamPolicy` method. type SetIamPolicyRequest struct { state protoimpl.MessageState @@ -60,6 +55,12 @@ type SetIamPolicyRequest struct { // valid policy but certain Cloud Platform services (such as Projects) // might reject them. Policy *Policy `protobuf:"bytes,2,opt,name=policy,proto3" json:"policy,omitempty"` + // OPTIONAL: A FieldMask specifying which fields of the policy to modify. Only + // the fields in the mask will be modified. If no mask is provided, the + // following default mask is used: + // + // `paths: "bindings, etag"` + UpdateMask *fieldmaskpb.FieldMask `protobuf:"bytes,3,opt,name=update_mask,json=updateMask,proto3" json:"update_mask,omitempty"` } func (x *SetIamPolicyRequest) Reset() { @@ -108,6 +109,13 @@ func (x *SetIamPolicyRequest) GetPolicy() *Policy { return nil } +func (x *SetIamPolicyRequest) GetUpdateMask() *fieldmaskpb.FieldMask { + if x != nil { + return x.UpdateMask + } + return nil +} + // Request message for `GetIamPolicy` method. type GetIamPolicyRequest struct { state protoimpl.MessageState @@ -118,7 +126,7 @@ type GetIamPolicyRequest struct { // See the operation documentation for the appropriate value for this field. Resource string `protobuf:"bytes,1,opt,name=resource,proto3" json:"resource,omitempty"` // OPTIONAL: A `GetPolicyOptions` object for specifying options to - // `GetIamPolicy`. This field is only used by Cloud IAM. + // `GetIamPolicy`. Options *GetPolicyOptions `protobuf:"bytes,2,opt,name=options,proto3" json:"options,omitempty"` } @@ -286,24 +294,30 @@ var file_google_iam_v1_iam_policy_proto_rawDesc = []byte{ 0x0a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x69, 0x61, 0x6d, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x61, 0x6d, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0d, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x1a, - 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x69, 0x61, 0x6d, 0x2f, 0x76, 0x31, 0x2f, 0x6f, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1a, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x69, 0x61, 0x6d, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x6f, 0x6c, 0x69, - 0x63, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, - 0x70, 0x69, 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, - 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x66, 0x69, 0x65, 0x6c, - 0x64, 0x5f, 0x62, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x70, 0x0a, 0x13, 0x53, - 0x65, 0x74, 0x49, 0x61, 0x6d, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x25, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x42, 0x09, 0xe0, 0x41, 0x02, 0xfa, 0x41, 0x03, 0x0a, 0x01, 0x2a, 0x52, - 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x32, 0x0a, 0x06, 0x70, 0x6f, 0x6c, - 0x69, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x06, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x22, 0x77, 0x0a, + 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, + 0x70, 0x69, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x62, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, + 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, + 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x69, 0x61, 0x6d, 0x2f, 0x76, + 0x31, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, + 0x1a, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x69, 0x61, 0x6d, 0x2f, 0x76, 0x31, 0x2f, 0x70, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x20, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x66, 0x69, 0x65, + 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xad, 0x01, + 0x0a, 0x13, 0x53, 0x65, 0x74, 0x49, 0x61, 0x6d, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x09, 0xe0, 0x41, 0x02, 0xfa, 0x41, 0x03, 0x0a, + 0x01, 0x2a, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x32, 0x0a, 0x06, + 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, 0x6c, + 0x69, 0x63, 0x79, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x06, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, + 0x12, 0x3b, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, + 0x6b, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x61, 0x73, 0x6b, 0x22, 0x77, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x49, 0x61, 0x6d, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x09, 0xe0, 0x41, 0x02, 0xfa, 0x41, 0x03, 0x0a, 0x01, @@ -380,22 +394,24 @@ var file_google_iam_v1_iam_policy_proto_goTypes = []interface{}{ (*TestIamPermissionsRequest)(nil), // 2: google.iam.v1.TestIamPermissionsRequest (*TestIamPermissionsResponse)(nil), // 3: google.iam.v1.TestIamPermissionsResponse (*Policy)(nil), // 4: google.iam.v1.Policy - (*GetPolicyOptions)(nil), // 5: google.iam.v1.GetPolicyOptions + (*fieldmaskpb.FieldMask)(nil), // 5: google.protobuf.FieldMask + (*GetPolicyOptions)(nil), // 6: google.iam.v1.GetPolicyOptions } var file_google_iam_v1_iam_policy_proto_depIdxs = []int32{ 4, // 0: google.iam.v1.SetIamPolicyRequest.policy:type_name -> google.iam.v1.Policy - 5, // 1: google.iam.v1.GetIamPolicyRequest.options:type_name -> google.iam.v1.GetPolicyOptions - 0, // 2: google.iam.v1.IAMPolicy.SetIamPolicy:input_type -> google.iam.v1.SetIamPolicyRequest - 1, // 3: google.iam.v1.IAMPolicy.GetIamPolicy:input_type -> google.iam.v1.GetIamPolicyRequest - 2, // 4: google.iam.v1.IAMPolicy.TestIamPermissions:input_type -> google.iam.v1.TestIamPermissionsRequest - 4, // 5: google.iam.v1.IAMPolicy.SetIamPolicy:output_type -> google.iam.v1.Policy - 4, // 6: google.iam.v1.IAMPolicy.GetIamPolicy:output_type -> google.iam.v1.Policy - 3, // 7: google.iam.v1.IAMPolicy.TestIamPermissions:output_type -> google.iam.v1.TestIamPermissionsResponse - 5, // [5:8] is the sub-list for method output_type - 2, // [2:5] is the sub-list for method input_type - 2, // [2:2] is the sub-list for extension type_name - 2, // [2:2] is the sub-list for extension extendee - 0, // [0:2] is the sub-list for field type_name + 5, // 1: google.iam.v1.SetIamPolicyRequest.update_mask:type_name -> google.protobuf.FieldMask + 6, // 2: google.iam.v1.GetIamPolicyRequest.options:type_name -> google.iam.v1.GetPolicyOptions + 0, // 3: google.iam.v1.IAMPolicy.SetIamPolicy:input_type -> google.iam.v1.SetIamPolicyRequest + 1, // 4: google.iam.v1.IAMPolicy.GetIamPolicy:input_type -> google.iam.v1.GetIamPolicyRequest + 2, // 5: google.iam.v1.IAMPolicy.TestIamPermissions:input_type -> google.iam.v1.TestIamPermissionsRequest + 4, // 6: google.iam.v1.IAMPolicy.SetIamPolicy:output_type -> google.iam.v1.Policy + 4, // 7: google.iam.v1.IAMPolicy.GetIamPolicy:output_type -> google.iam.v1.Policy + 3, // 8: google.iam.v1.IAMPolicy.TestIamPermissions:output_type -> google.iam.v1.TestIamPermissionsResponse + 6, // [6:9] is the sub-list for method output_type + 3, // [3:6] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name } func init() { file_google_iam_v1_iam_policy_proto_init() } @@ -489,6 +505,8 @@ const _ = grpc.SupportPackageIsVersion6 type IAMPolicyClient interface { // Sets the access control policy on the specified resource. Replaces any // existing policy. + // + // Can return `NOT_FOUND`, `INVALID_ARGUMENT`, and `PERMISSION_DENIED` errors. SetIamPolicy(ctx context.Context, in *SetIamPolicyRequest, opts ...grpc.CallOption) (*Policy, error) // Gets the access control policy for a resource. // Returns an empty policy if the resource exists and does not have a policy @@ -496,7 +514,7 @@ type IAMPolicyClient interface { GetIamPolicy(ctx context.Context, in *GetIamPolicyRequest, opts ...grpc.CallOption) (*Policy, error) // Returns permissions that a caller has on the specified resource. // If the resource does not exist, this will return an empty set of - // permissions, not a NOT_FOUND error. + // permissions, not a `NOT_FOUND` error. // // Note: This operation is designed to be used for building permission-aware // UIs and command-line tools, not for authorization checking. This operation @@ -543,6 +561,8 @@ func (c *iAMPolicyClient) TestIamPermissions(ctx context.Context, in *TestIamPer type IAMPolicyServer interface { // Sets the access control policy on the specified resource. Replaces any // existing policy. + // + // Can return `NOT_FOUND`, `INVALID_ARGUMENT`, and `PERMISSION_DENIED` errors. SetIamPolicy(context.Context, *SetIamPolicyRequest) (*Policy, error) // Gets the access control policy for a resource. // Returns an empty policy if the resource exists and does not have a policy @@ -550,7 +570,7 @@ type IAMPolicyServer interface { GetIamPolicy(context.Context, *GetIamPolicyRequest) (*Policy, error) // Returns permissions that a caller has on the specified resource. // If the resource does not exist, this will return an empty set of - // permissions, not a NOT_FOUND error. + // permissions, not a `NOT_FOUND` error. // // Note: This operation is designed to be used for building permission-aware // UIs and command-line tools, not for authorization checking. This operation diff --git a/vendor/google.golang.org/genproto/googleapis/iam/v1/options.pb.go b/vendor/cloud.google.com/go/iam/apiv1/iampb/options.pb.go similarity index 70% rename from vendor/google.golang.org/genproto/googleapis/iam/v1/options.pb.go rename to vendor/cloud.google.com/go/iam/apiv1/iampb/options.pb.go index f8f9fb0e92f..e8a2aca9c7d 100644 --- a/vendor/google.golang.org/genproto/googleapis/iam/v1/options.pb.go +++ b/vendor/cloud.google.com/go/iam/apiv1/iampb/options.pb.go @@ -1,4 +1,4 @@ -// Copyright 2019 Google LLC. +// Copyright 2022 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -11,22 +11,19 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -// // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.25.0 -// protoc v3.13.0 +// protoc-gen-go v1.26.0 +// protoc v3.21.9 // source: google/iam/v1/options.proto -package iam +package iampb import ( reflect "reflect" sync "sync" - proto "github.com/golang/protobuf/proto" - _ "google.golang.org/genproto/googleapis/api/annotations" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" ) @@ -38,24 +35,30 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - // Encapsulates settings provided to GetIamPolicy. type GetPolicyOptions struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // Optional. The policy format version to be returned. + // Optional. The maximum policy version that will be used to format the + // policy. // // Valid values are 0, 1, and 3. Requests specifying an invalid value will be // rejected. // - // Requests for policies with any conditional bindings must specify version 3. - // Policies without any conditional bindings may specify any valid value or - // leave the field unset. + // Requests for policies with any conditional role bindings must specify + // version 3. Policies with no conditional role bindings may specify any valid + // value or leave the field unset. + // + // The policy in the response might use the policy version that you specified, + // or it might use a lower policy version. For example, if you specify version + // 3, but the policy has no conditional role bindings, the response uses + // version 1. + // + // To learn which resources support conditions in their IAM policies, see the + // [IAM + // documentation](https://cloud.google.com/iam/help/conditions/resource-policies). RequestedPolicyVersion int32 `protobuf:"varint,1,opt,name=requested_policy_version,json=requestedPolicyVersion,proto3" json:"requested_policy_version,omitempty"` } @@ -103,23 +106,21 @@ var File_google_iam_v1_options_proto protoreflect.FileDescriptor var file_google_iam_v1_options_proto_rawDesc = []byte{ 0x0a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x69, 0x61, 0x6d, 0x2f, 0x76, 0x31, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0d, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x1a, 0x1c, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x4c, 0x0a, 0x10, 0x47, 0x65, - 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x38, - 0x0a, 0x18, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x70, 0x6f, 0x6c, 0x69, - 0x63, 0x79, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x16, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x65, 0x64, 0x50, 0x6f, 0x6c, 0x69, 0x63, - 0x79, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x84, 0x01, 0x0a, 0x11, 0x63, 0x6f, 0x6d, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x42, 0x0c, - 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, - 0x67, 0x2f, 0x67, 0x65, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x69, 0x61, 0x6d, 0x2f, 0x76, 0x31, 0x3b, 0x69, 0x61, 0x6d, - 0xf8, 0x01, 0x01, 0xaa, 0x02, 0x13, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x43, 0x6c, 0x6f, - 0x75, 0x64, 0x2e, 0x49, 0x61, 0x6d, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x13, 0x47, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x5c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x5c, 0x49, 0x61, 0x6d, 0x5c, 0x56, 0x31, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x22, 0x4c, 0x0a, 0x10, + 0x47, 0x65, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x12, 0x38, 0x0a, 0x18, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x70, 0x6f, + 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x16, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x65, 0x64, 0x50, 0x6f, 0x6c, + 0x69, 0x63, 0x79, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x84, 0x01, 0x0a, 0x11, 0x63, + 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x76, 0x31, + 0x42, 0x0c, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, + 0x5a, 0x30, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, + 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x65, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x69, 0x61, 0x6d, 0x2f, 0x76, 0x31, 0x3b, 0x69, + 0x61, 0x6d, 0xf8, 0x01, 0x01, 0xaa, 0x02, 0x13, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x43, + 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x49, 0x61, 0x6d, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x13, 0x47, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x5c, 0x49, 0x61, 0x6d, 0x5c, 0x56, + 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/vendor/cloud.google.com/go/iam/apiv1/iampb/policy.pb.go b/vendor/cloud.google.com/go/iam/apiv1/iampb/policy.pb.go new file mode 100644 index 00000000000..e521db60fa5 --- /dev/null +++ b/vendor/cloud.google.com/go/iam/apiv1/iampb/policy.pb.go @@ -0,0 +1,1169 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.26.0 +// protoc v3.21.9 +// source: google/iam/v1/policy.proto + +package iampb + +import ( + reflect "reflect" + sync "sync" + + expr "google.golang.org/genproto/googleapis/type/expr" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// The list of valid permission types for which logging can be configured. +// Admin writes are always logged, and are not configurable. +type AuditLogConfig_LogType int32 + +const ( + // Default case. Should never be this. + AuditLogConfig_LOG_TYPE_UNSPECIFIED AuditLogConfig_LogType = 0 + // Admin reads. Example: CloudIAM getIamPolicy + AuditLogConfig_ADMIN_READ AuditLogConfig_LogType = 1 + // Data writes. Example: CloudSQL Users create + AuditLogConfig_DATA_WRITE AuditLogConfig_LogType = 2 + // Data reads. Example: CloudSQL Users list + AuditLogConfig_DATA_READ AuditLogConfig_LogType = 3 +) + +// Enum value maps for AuditLogConfig_LogType. +var ( + AuditLogConfig_LogType_name = map[int32]string{ + 0: "LOG_TYPE_UNSPECIFIED", + 1: "ADMIN_READ", + 2: "DATA_WRITE", + 3: "DATA_READ", + } + AuditLogConfig_LogType_value = map[string]int32{ + "LOG_TYPE_UNSPECIFIED": 0, + "ADMIN_READ": 1, + "DATA_WRITE": 2, + "DATA_READ": 3, + } +) + +func (x AuditLogConfig_LogType) Enum() *AuditLogConfig_LogType { + p := new(AuditLogConfig_LogType) + *p = x + return p +} + +func (x AuditLogConfig_LogType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (AuditLogConfig_LogType) Descriptor() protoreflect.EnumDescriptor { + return file_google_iam_v1_policy_proto_enumTypes[0].Descriptor() +} + +func (AuditLogConfig_LogType) Type() protoreflect.EnumType { + return &file_google_iam_v1_policy_proto_enumTypes[0] +} + +func (x AuditLogConfig_LogType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use AuditLogConfig_LogType.Descriptor instead. +func (AuditLogConfig_LogType) EnumDescriptor() ([]byte, []int) { + return file_google_iam_v1_policy_proto_rawDescGZIP(), []int{3, 0} +} + +// The type of action performed on a Binding in a policy. +type BindingDelta_Action int32 + +const ( + // Unspecified. + BindingDelta_ACTION_UNSPECIFIED BindingDelta_Action = 0 + // Addition of a Binding. + BindingDelta_ADD BindingDelta_Action = 1 + // Removal of a Binding. + BindingDelta_REMOVE BindingDelta_Action = 2 +) + +// Enum value maps for BindingDelta_Action. +var ( + BindingDelta_Action_name = map[int32]string{ + 0: "ACTION_UNSPECIFIED", + 1: "ADD", + 2: "REMOVE", + } + BindingDelta_Action_value = map[string]int32{ + "ACTION_UNSPECIFIED": 0, + "ADD": 1, + "REMOVE": 2, + } +) + +func (x BindingDelta_Action) Enum() *BindingDelta_Action { + p := new(BindingDelta_Action) + *p = x + return p +} + +func (x BindingDelta_Action) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (BindingDelta_Action) Descriptor() protoreflect.EnumDescriptor { + return file_google_iam_v1_policy_proto_enumTypes[1].Descriptor() +} + +func (BindingDelta_Action) Type() protoreflect.EnumType { + return &file_google_iam_v1_policy_proto_enumTypes[1] +} + +func (x BindingDelta_Action) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use BindingDelta_Action.Descriptor instead. +func (BindingDelta_Action) EnumDescriptor() ([]byte, []int) { + return file_google_iam_v1_policy_proto_rawDescGZIP(), []int{5, 0} +} + +// The type of action performed on an audit configuration in a policy. +type AuditConfigDelta_Action int32 + +const ( + // Unspecified. + AuditConfigDelta_ACTION_UNSPECIFIED AuditConfigDelta_Action = 0 + // Addition of an audit configuration. + AuditConfigDelta_ADD AuditConfigDelta_Action = 1 + // Removal of an audit configuration. + AuditConfigDelta_REMOVE AuditConfigDelta_Action = 2 +) + +// Enum value maps for AuditConfigDelta_Action. +var ( + AuditConfigDelta_Action_name = map[int32]string{ + 0: "ACTION_UNSPECIFIED", + 1: "ADD", + 2: "REMOVE", + } + AuditConfigDelta_Action_value = map[string]int32{ + "ACTION_UNSPECIFIED": 0, + "ADD": 1, + "REMOVE": 2, + } +) + +func (x AuditConfigDelta_Action) Enum() *AuditConfigDelta_Action { + p := new(AuditConfigDelta_Action) + *p = x + return p +} + +func (x AuditConfigDelta_Action) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (AuditConfigDelta_Action) Descriptor() protoreflect.EnumDescriptor { + return file_google_iam_v1_policy_proto_enumTypes[2].Descriptor() +} + +func (AuditConfigDelta_Action) Type() protoreflect.EnumType { + return &file_google_iam_v1_policy_proto_enumTypes[2] +} + +func (x AuditConfigDelta_Action) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use AuditConfigDelta_Action.Descriptor instead. +func (AuditConfigDelta_Action) EnumDescriptor() ([]byte, []int) { + return file_google_iam_v1_policy_proto_rawDescGZIP(), []int{6, 0} +} + +// An Identity and Access Management (IAM) policy, which specifies access +// controls for Google Cloud resources. +// +// A `Policy` is a collection of `bindings`. A `binding` binds one or more +// `members`, or principals, to a single `role`. Principals can be user +// accounts, service accounts, Google groups, and domains (such as G Suite). A +// `role` is a named list of permissions; each `role` can be an IAM predefined +// role or a user-created custom role. +// +// For some types of Google Cloud resources, a `binding` can also specify a +// `condition`, which is a logical expression that allows access to a resource +// only if the expression evaluates to `true`. A condition can add constraints +// based on attributes of the request, the resource, or both. To learn which +// resources support conditions in their IAM policies, see the +// [IAM documentation](https://cloud.google.com/iam/help/conditions/resource-policies). +// +// **JSON example:** +// +// { +// "bindings": [ +// { +// "role": "roles/resourcemanager.organizationAdmin", +// "members": [ +// "user:mike@example.com", +// "group:admins@example.com", +// "domain:google.com", +// "serviceAccount:my-project-id@appspot.gserviceaccount.com" +// ] +// }, +// { +// "role": "roles/resourcemanager.organizationViewer", +// "members": [ +// "user:eve@example.com" +// ], +// "condition": { +// "title": "expirable access", +// "description": "Does not grant access after Sep 2020", +// "expression": "request.time < timestamp('2020-10-01T00:00:00.000Z')", +// } +// } +// ], +// "etag": "BwWWja0YfJA=", +// "version": 3 +// } +// +// **YAML example:** +// +// bindings: +// - members: +// - user:mike@example.com +// - group:admins@example.com +// - domain:google.com +// - serviceAccount:my-project-id@appspot.gserviceaccount.com +// role: roles/resourcemanager.organizationAdmin +// - members: +// - user:eve@example.com +// role: roles/resourcemanager.organizationViewer +// condition: +// title: expirable access +// description: Does not grant access after Sep 2020 +// expression: request.time < timestamp('2020-10-01T00:00:00.000Z') +// etag: BwWWja0YfJA= +// version: 3 +// +// For a description of IAM and its features, see the +// [IAM documentation](https://cloud.google.com/iam/docs/). +type Policy struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Specifies the format of the policy. + // + // Valid values are `0`, `1`, and `3`. Requests that specify an invalid value + // are rejected. + // + // Any operation that affects conditional role bindings must specify version + // `3`. This requirement applies to the following operations: + // + // - Getting a policy that includes a conditional role binding + // - Adding a conditional role binding to a policy + // - Changing a conditional role binding in a policy + // - Removing any role binding, with or without a condition, from a policy + // that includes conditions + // + // **Important:** If you use IAM Conditions, you must include the `etag` field + // whenever you call `setIamPolicy`. If you omit this field, then IAM allows + // you to overwrite a version `3` policy with a version `1` policy, and all of + // the conditions in the version `3` policy are lost. + // + // If a policy does not include any conditions, operations on that policy may + // specify any valid version or leave the field unset. + // + // To learn which resources support conditions in their IAM policies, see the + // [IAM documentation](https://cloud.google.com/iam/help/conditions/resource-policies). + Version int32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` + // Associates a list of `members`, or principals, with a `role`. Optionally, + // may specify a `condition` that determines how and when the `bindings` are + // applied. Each of the `bindings` must contain at least one principal. + // + // The `bindings` in a `Policy` can refer to up to 1,500 principals; up to 250 + // of these principals can be Google groups. Each occurrence of a principal + // counts towards these limits. For example, if the `bindings` grant 50 + // different roles to `user:alice@example.com`, and not to any other + // principal, then you can add another 1,450 principals to the `bindings` in + // the `Policy`. + Bindings []*Binding `protobuf:"bytes,4,rep,name=bindings,proto3" json:"bindings,omitempty"` + // Specifies cloud audit logging configuration for this policy. + AuditConfigs []*AuditConfig `protobuf:"bytes,6,rep,name=audit_configs,json=auditConfigs,proto3" json:"audit_configs,omitempty"` + // `etag` is used for optimistic concurrency control as a way to help + // prevent simultaneous updates of a policy from overwriting each other. + // It is strongly suggested that systems make use of the `etag` in the + // read-modify-write cycle to perform policy updates in order to avoid race + // conditions: An `etag` is returned in the response to `getIamPolicy`, and + // systems are expected to put that etag in the request to `setIamPolicy` to + // ensure that their change will be applied to the same version of the policy. + // + // **Important:** If you use IAM Conditions, you must include the `etag` field + // whenever you call `setIamPolicy`. If you omit this field, then IAM allows + // you to overwrite a version `3` policy with a version `1` policy, and all of + // the conditions in the version `3` policy are lost. + Etag []byte `protobuf:"bytes,3,opt,name=etag,proto3" json:"etag,omitempty"` +} + +func (x *Policy) Reset() { + *x = Policy{} + if protoimpl.UnsafeEnabled { + mi := &file_google_iam_v1_policy_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Policy) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Policy) ProtoMessage() {} + +func (x *Policy) ProtoReflect() protoreflect.Message { + mi := &file_google_iam_v1_policy_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Policy.ProtoReflect.Descriptor instead. +func (*Policy) Descriptor() ([]byte, []int) { + return file_google_iam_v1_policy_proto_rawDescGZIP(), []int{0} +} + +func (x *Policy) GetVersion() int32 { + if x != nil { + return x.Version + } + return 0 +} + +func (x *Policy) GetBindings() []*Binding { + if x != nil { + return x.Bindings + } + return nil +} + +func (x *Policy) GetAuditConfigs() []*AuditConfig { + if x != nil { + return x.AuditConfigs + } + return nil +} + +func (x *Policy) GetEtag() []byte { + if x != nil { + return x.Etag + } + return nil +} + +// Associates `members`, or principals, with a `role`. +type Binding struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Role that is assigned to the list of `members`, or principals. + // For example, `roles/viewer`, `roles/editor`, or `roles/owner`. + Role string `protobuf:"bytes,1,opt,name=role,proto3" json:"role,omitempty"` + // Specifies the principals requesting access for a Cloud Platform resource. + // `members` can have the following values: + // + // - `allUsers`: A special identifier that represents anyone who is + // on the internet; with or without a Google account. + // + // - `allAuthenticatedUsers`: A special identifier that represents anyone + // who is authenticated with a Google account or a service account. + // + // - `user:{emailid}`: An email address that represents a specific Google + // account. For example, `alice@example.com` . + // + // - `serviceAccount:{emailid}`: An email address that represents a service + // account. For example, `my-other-app@appspot.gserviceaccount.com`. + // + // - `group:{emailid}`: An email address that represents a Google group. + // For example, `admins@example.com`. + // + // - `deleted:user:{emailid}?uid={uniqueid}`: An email address (plus unique + // identifier) representing a user that has been recently deleted. For + // example, `alice@example.com?uid=123456789012345678901`. If the user is + // recovered, this value reverts to `user:{emailid}` and the recovered user + // retains the role in the binding. + // + // - `deleted:serviceAccount:{emailid}?uid={uniqueid}`: An email address (plus + // unique identifier) representing a service account that has been recently + // deleted. For example, + // `my-other-app@appspot.gserviceaccount.com?uid=123456789012345678901`. + // If the service account is undeleted, this value reverts to + // `serviceAccount:{emailid}` and the undeleted service account retains the + // role in the binding. + // + // - `deleted:group:{emailid}?uid={uniqueid}`: An email address (plus unique + // identifier) representing a Google group that has been recently + // deleted. For example, `admins@example.com?uid=123456789012345678901`. If + // the group is recovered, this value reverts to `group:{emailid}` and the + // recovered group retains the role in the binding. + // + // - `domain:{domain}`: The G Suite domain (primary) that represents all the + // users of that domain. For example, `google.com` or `example.com`. + Members []string `protobuf:"bytes,2,rep,name=members,proto3" json:"members,omitempty"` + // The condition that is associated with this binding. + // + // If the condition evaluates to `true`, then this binding applies to the + // current request. + // + // If the condition evaluates to `false`, then this binding does not apply to + // the current request. However, a different role binding might grant the same + // role to one or more of the principals in this binding. + // + // To learn which resources support conditions in their IAM policies, see the + // [IAM + // documentation](https://cloud.google.com/iam/help/conditions/resource-policies). + Condition *expr.Expr `protobuf:"bytes,3,opt,name=condition,proto3" json:"condition,omitempty"` +} + +func (x *Binding) Reset() { + *x = Binding{} + if protoimpl.UnsafeEnabled { + mi := &file_google_iam_v1_policy_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Binding) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Binding) ProtoMessage() {} + +func (x *Binding) ProtoReflect() protoreflect.Message { + mi := &file_google_iam_v1_policy_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Binding.ProtoReflect.Descriptor instead. +func (*Binding) Descriptor() ([]byte, []int) { + return file_google_iam_v1_policy_proto_rawDescGZIP(), []int{1} +} + +func (x *Binding) GetRole() string { + if x != nil { + return x.Role + } + return "" +} + +func (x *Binding) GetMembers() []string { + if x != nil { + return x.Members + } + return nil +} + +func (x *Binding) GetCondition() *expr.Expr { + if x != nil { + return x.Condition + } + return nil +} + +// Specifies the audit configuration for a service. +// The configuration determines which permission types are logged, and what +// identities, if any, are exempted from logging. +// An AuditConfig must have one or more AuditLogConfigs. +// +// If there are AuditConfigs for both `allServices` and a specific service, +// the union of the two AuditConfigs is used for that service: the log_types +// specified in each AuditConfig are enabled, and the exempted_members in each +// AuditLogConfig are exempted. +// +// Example Policy with multiple AuditConfigs: +// +// { +// "audit_configs": [ +// { +// "service": "allServices", +// "audit_log_configs": [ +// { +// "log_type": "DATA_READ", +// "exempted_members": [ +// "user:jose@example.com" +// ] +// }, +// { +// "log_type": "DATA_WRITE" +// }, +// { +// "log_type": "ADMIN_READ" +// } +// ] +// }, +// { +// "service": "sampleservice.googleapis.com", +// "audit_log_configs": [ +// { +// "log_type": "DATA_READ" +// }, +// { +// "log_type": "DATA_WRITE", +// "exempted_members": [ +// "user:aliya@example.com" +// ] +// } +// ] +// } +// ] +// } +// +// For sampleservice, this policy enables DATA_READ, DATA_WRITE and ADMIN_READ +// logging. It also exempts jose@example.com from DATA_READ logging, and +// aliya@example.com from DATA_WRITE logging. +type AuditConfig struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Specifies a service that will be enabled for audit logging. + // For example, `storage.googleapis.com`, `cloudsql.googleapis.com`. + // `allServices` is a special value that covers all services. + Service string `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"` + // The configuration for logging of each type of permission. + AuditLogConfigs []*AuditLogConfig `protobuf:"bytes,3,rep,name=audit_log_configs,json=auditLogConfigs,proto3" json:"audit_log_configs,omitempty"` +} + +func (x *AuditConfig) Reset() { + *x = AuditConfig{} + if protoimpl.UnsafeEnabled { + mi := &file_google_iam_v1_policy_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AuditConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AuditConfig) ProtoMessage() {} + +func (x *AuditConfig) ProtoReflect() protoreflect.Message { + mi := &file_google_iam_v1_policy_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AuditConfig.ProtoReflect.Descriptor instead. +func (*AuditConfig) Descriptor() ([]byte, []int) { + return file_google_iam_v1_policy_proto_rawDescGZIP(), []int{2} +} + +func (x *AuditConfig) GetService() string { + if x != nil { + return x.Service + } + return "" +} + +func (x *AuditConfig) GetAuditLogConfigs() []*AuditLogConfig { + if x != nil { + return x.AuditLogConfigs + } + return nil +} + +// Provides the configuration for logging a type of permissions. +// Example: +// +// { +// "audit_log_configs": [ +// { +// "log_type": "DATA_READ", +// "exempted_members": [ +// "user:jose@example.com" +// ] +// }, +// { +// "log_type": "DATA_WRITE" +// } +// ] +// } +// +// This enables 'DATA_READ' and 'DATA_WRITE' logging, while exempting +// jose@example.com from DATA_READ logging. +type AuditLogConfig struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The log type that this config enables. + LogType AuditLogConfig_LogType `protobuf:"varint,1,opt,name=log_type,json=logType,proto3,enum=google.iam.v1.AuditLogConfig_LogType" json:"log_type,omitempty"` + // Specifies the identities that do not cause logging for this type of + // permission. + // Follows the same format of [Binding.members][google.iam.v1.Binding.members]. + ExemptedMembers []string `protobuf:"bytes,2,rep,name=exempted_members,json=exemptedMembers,proto3" json:"exempted_members,omitempty"` +} + +func (x *AuditLogConfig) Reset() { + *x = AuditLogConfig{} + if protoimpl.UnsafeEnabled { + mi := &file_google_iam_v1_policy_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AuditLogConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AuditLogConfig) ProtoMessage() {} + +func (x *AuditLogConfig) ProtoReflect() protoreflect.Message { + mi := &file_google_iam_v1_policy_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AuditLogConfig.ProtoReflect.Descriptor instead. +func (*AuditLogConfig) Descriptor() ([]byte, []int) { + return file_google_iam_v1_policy_proto_rawDescGZIP(), []int{3} +} + +func (x *AuditLogConfig) GetLogType() AuditLogConfig_LogType { + if x != nil { + return x.LogType + } + return AuditLogConfig_LOG_TYPE_UNSPECIFIED +} + +func (x *AuditLogConfig) GetExemptedMembers() []string { + if x != nil { + return x.ExemptedMembers + } + return nil +} + +// The difference delta between two policies. +type PolicyDelta struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The delta for Bindings between two policies. + BindingDeltas []*BindingDelta `protobuf:"bytes,1,rep,name=binding_deltas,json=bindingDeltas,proto3" json:"binding_deltas,omitempty"` + // The delta for AuditConfigs between two policies. + AuditConfigDeltas []*AuditConfigDelta `protobuf:"bytes,2,rep,name=audit_config_deltas,json=auditConfigDeltas,proto3" json:"audit_config_deltas,omitempty"` +} + +func (x *PolicyDelta) Reset() { + *x = PolicyDelta{} + if protoimpl.UnsafeEnabled { + mi := &file_google_iam_v1_policy_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PolicyDelta) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PolicyDelta) ProtoMessage() {} + +func (x *PolicyDelta) ProtoReflect() protoreflect.Message { + mi := &file_google_iam_v1_policy_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PolicyDelta.ProtoReflect.Descriptor instead. +func (*PolicyDelta) Descriptor() ([]byte, []int) { + return file_google_iam_v1_policy_proto_rawDescGZIP(), []int{4} +} + +func (x *PolicyDelta) GetBindingDeltas() []*BindingDelta { + if x != nil { + return x.BindingDeltas + } + return nil +} + +func (x *PolicyDelta) GetAuditConfigDeltas() []*AuditConfigDelta { + if x != nil { + return x.AuditConfigDeltas + } + return nil +} + +// One delta entry for Binding. Each individual change (only one member in each +// entry) to a binding will be a separate entry. +type BindingDelta struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The action that was performed on a Binding. + // Required + Action BindingDelta_Action `protobuf:"varint,1,opt,name=action,proto3,enum=google.iam.v1.BindingDelta_Action" json:"action,omitempty"` + // Role that is assigned to `members`. + // For example, `roles/viewer`, `roles/editor`, or `roles/owner`. + // Required + Role string `protobuf:"bytes,2,opt,name=role,proto3" json:"role,omitempty"` + // A single identity requesting access for a Cloud Platform resource. + // Follows the same format of Binding.members. + // Required + Member string `protobuf:"bytes,3,opt,name=member,proto3" json:"member,omitempty"` + // The condition that is associated with this binding. + Condition *expr.Expr `protobuf:"bytes,4,opt,name=condition,proto3" json:"condition,omitempty"` +} + +func (x *BindingDelta) Reset() { + *x = BindingDelta{} + if protoimpl.UnsafeEnabled { + mi := &file_google_iam_v1_policy_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BindingDelta) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BindingDelta) ProtoMessage() {} + +func (x *BindingDelta) ProtoReflect() protoreflect.Message { + mi := &file_google_iam_v1_policy_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BindingDelta.ProtoReflect.Descriptor instead. +func (*BindingDelta) Descriptor() ([]byte, []int) { + return file_google_iam_v1_policy_proto_rawDescGZIP(), []int{5} +} + +func (x *BindingDelta) GetAction() BindingDelta_Action { + if x != nil { + return x.Action + } + return BindingDelta_ACTION_UNSPECIFIED +} + +func (x *BindingDelta) GetRole() string { + if x != nil { + return x.Role + } + return "" +} + +func (x *BindingDelta) GetMember() string { + if x != nil { + return x.Member + } + return "" +} + +func (x *BindingDelta) GetCondition() *expr.Expr { + if x != nil { + return x.Condition + } + return nil +} + +// One delta entry for AuditConfig. Each individual change (only one +// exempted_member in each entry) to a AuditConfig will be a separate entry. +type AuditConfigDelta struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The action that was performed on an audit configuration in a policy. + // Required + Action AuditConfigDelta_Action `protobuf:"varint,1,opt,name=action,proto3,enum=google.iam.v1.AuditConfigDelta_Action" json:"action,omitempty"` + // Specifies a service that was configured for Cloud Audit Logging. + // For example, `storage.googleapis.com`, `cloudsql.googleapis.com`. + // `allServices` is a special value that covers all services. + // Required + Service string `protobuf:"bytes,2,opt,name=service,proto3" json:"service,omitempty"` + // A single identity that is exempted from "data access" audit + // logging for the `service` specified above. + // Follows the same format of Binding.members. + ExemptedMember string `protobuf:"bytes,3,opt,name=exempted_member,json=exemptedMember,proto3" json:"exempted_member,omitempty"` + // Specifies the log_type that was be enabled. ADMIN_ACTIVITY is always + // enabled, and cannot be configured. + // Required + LogType string `protobuf:"bytes,4,opt,name=log_type,json=logType,proto3" json:"log_type,omitempty"` +} + +func (x *AuditConfigDelta) Reset() { + *x = AuditConfigDelta{} + if protoimpl.UnsafeEnabled { + mi := &file_google_iam_v1_policy_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AuditConfigDelta) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AuditConfigDelta) ProtoMessage() {} + +func (x *AuditConfigDelta) ProtoReflect() protoreflect.Message { + mi := &file_google_iam_v1_policy_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AuditConfigDelta.ProtoReflect.Descriptor instead. +func (*AuditConfigDelta) Descriptor() ([]byte, []int) { + return file_google_iam_v1_policy_proto_rawDescGZIP(), []int{6} +} + +func (x *AuditConfigDelta) GetAction() AuditConfigDelta_Action { + if x != nil { + return x.Action + } + return AuditConfigDelta_ACTION_UNSPECIFIED +} + +func (x *AuditConfigDelta) GetService() string { + if x != nil { + return x.Service + } + return "" +} + +func (x *AuditConfigDelta) GetExemptedMember() string { + if x != nil { + return x.ExemptedMember + } + return "" +} + +func (x *AuditConfigDelta) GetLogType() string { + if x != nil { + return x.LogType + } + return "" +} + +var File_google_iam_v1_policy_proto protoreflect.FileDescriptor + +var file_google_iam_v1_policy_proto_rawDesc = []byte{ + 0x0a, 0x1a, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x69, 0x61, 0x6d, 0x2f, 0x76, 0x31, 0x2f, + 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0d, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x1a, 0x16, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x2f, 0x65, 0x78, 0x70, 0x72, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x22, 0xab, 0x01, 0x0a, 0x06, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x18, + 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x08, 0x62, 0x69, 0x6e, 0x64, + 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x69, 0x6e, 0x64, 0x69, + 0x6e, 0x67, 0x52, 0x08, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3f, 0x0a, 0x0d, + 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x18, 0x06, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x69, 0x61, 0x6d, + 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, + 0x0c, 0x61, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x12, 0x12, 0x0a, + 0x04, 0x65, 0x74, 0x61, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x65, 0x74, 0x61, + 0x67, 0x22, 0x68, 0x0a, 0x07, 0x42, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x12, 0x0a, 0x04, + 0x72, 0x6f, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, + 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x07, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x2f, 0x0a, 0x09, 0x63, 0x6f, + 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x2e, 0x45, 0x78, 0x70, 0x72, + 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x72, 0x0a, 0x0b, 0x41, + 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x12, 0x49, 0x0a, 0x11, 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, 0x6c, 0x6f, + 0x67, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x1d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x2e, + 0x41, 0x75, 0x64, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0f, + 0x61, 0x75, 0x64, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x22, + 0xd1, 0x01, 0x0a, 0x0e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x12, 0x40, 0x0a, 0x08, 0x6c, 0x6f, 0x67, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x25, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x69, 0x61, + 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x4c, 0x6f, 0x67, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x2e, 0x4c, 0x6f, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x07, 0x6c, 0x6f, 0x67, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x65, 0x78, 0x65, 0x6d, 0x70, 0x74, 0x65, 0x64, + 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, + 0x65, 0x78, 0x65, 0x6d, 0x70, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x22, + 0x52, 0x0a, 0x07, 0x4c, 0x6f, 0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x14, 0x4c, 0x4f, + 0x47, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, + 0x45, 0x44, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x5f, 0x52, 0x45, + 0x41, 0x44, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x57, 0x52, 0x49, + 0x54, 0x45, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x45, 0x41, + 0x44, 0x10, 0x03, 0x22, 0xa2, 0x01, 0x0a, 0x0b, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x44, 0x65, + 0x6c, 0x74, 0x61, 0x12, 0x42, 0x0a, 0x0e, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x64, + 0x65, 0x6c, 0x74, 0x61, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x69, 0x6e, 0x64, + 0x69, 0x6e, 0x67, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x52, 0x0d, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, + 0x67, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x73, 0x12, 0x4f, 0x0a, 0x13, 0x61, 0x75, 0x64, 0x69, 0x74, + 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x73, 0x18, 0x02, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x69, 0x61, + 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x44, 0x65, 0x6c, 0x74, 0x61, 0x52, 0x11, 0x61, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x73, 0x22, 0xde, 0x01, 0x0a, 0x0c, 0x42, 0x69, 0x6e, + 0x64, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x12, 0x3a, 0x0a, 0x06, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x69, 0x6e, 0x64, 0x69, 0x6e, + 0x67, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x6d, + 0x62, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65, 0x6d, 0x62, 0x65, + 0x72, 0x12, 0x2f, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x74, 0x79, + 0x70, 0x65, 0x2e, 0x45, 0x78, 0x70, 0x72, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x22, 0x35, 0x0a, 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x12, + 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, + 0x45, 0x44, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x44, 0x44, 0x10, 0x01, 0x12, 0x0a, 0x0a, + 0x06, 0x52, 0x45, 0x4d, 0x4f, 0x56, 0x45, 0x10, 0x02, 0x22, 0xe7, 0x01, 0x0a, 0x10, 0x41, 0x75, + 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x12, 0x3e, + 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x41, + 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x2e, + 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, + 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x65, 0x78, 0x65, 0x6d, + 0x70, 0x74, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0e, 0x65, 0x78, 0x65, 0x6d, 0x70, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, + 0x72, 0x12, 0x19, 0x0a, 0x08, 0x6c, 0x6f, 0x67, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x6c, 0x6f, 0x67, 0x54, 0x79, 0x70, 0x65, 0x22, 0x35, 0x0a, 0x06, + 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x12, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, + 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x07, + 0x0a, 0x03, 0x41, 0x44, 0x44, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x52, 0x45, 0x4d, 0x4f, 0x56, + 0x45, 0x10, 0x02, 0x42, 0x83, 0x01, 0x0a, 0x11, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x42, 0x0b, 0x50, 0x6f, 0x6c, 0x69, 0x63, + 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x65, 0x6e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2f, + 0x69, 0x61, 0x6d, 0x2f, 0x76, 0x31, 0x3b, 0x69, 0x61, 0x6d, 0xf8, 0x01, 0x01, 0xaa, 0x02, 0x13, + 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x49, 0x61, 0x6d, + 0x2e, 0x56, 0x31, 0xca, 0x02, 0x13, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x43, 0x6c, 0x6f, + 0x75, 0x64, 0x5c, 0x49, 0x61, 0x6d, 0x5c, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, +} + +var ( + file_google_iam_v1_policy_proto_rawDescOnce sync.Once + file_google_iam_v1_policy_proto_rawDescData = file_google_iam_v1_policy_proto_rawDesc +) + +func file_google_iam_v1_policy_proto_rawDescGZIP() []byte { + file_google_iam_v1_policy_proto_rawDescOnce.Do(func() { + file_google_iam_v1_policy_proto_rawDescData = protoimpl.X.CompressGZIP(file_google_iam_v1_policy_proto_rawDescData) + }) + return file_google_iam_v1_policy_proto_rawDescData +} + +var file_google_iam_v1_policy_proto_enumTypes = make([]protoimpl.EnumInfo, 3) +var file_google_iam_v1_policy_proto_msgTypes = make([]protoimpl.MessageInfo, 7) +var file_google_iam_v1_policy_proto_goTypes = []interface{}{ + (AuditLogConfig_LogType)(0), // 0: google.iam.v1.AuditLogConfig.LogType + (BindingDelta_Action)(0), // 1: google.iam.v1.BindingDelta.Action + (AuditConfigDelta_Action)(0), // 2: google.iam.v1.AuditConfigDelta.Action + (*Policy)(nil), // 3: google.iam.v1.Policy + (*Binding)(nil), // 4: google.iam.v1.Binding + (*AuditConfig)(nil), // 5: google.iam.v1.AuditConfig + (*AuditLogConfig)(nil), // 6: google.iam.v1.AuditLogConfig + (*PolicyDelta)(nil), // 7: google.iam.v1.PolicyDelta + (*BindingDelta)(nil), // 8: google.iam.v1.BindingDelta + (*AuditConfigDelta)(nil), // 9: google.iam.v1.AuditConfigDelta + (*expr.Expr)(nil), // 10: google.type.Expr +} +var file_google_iam_v1_policy_proto_depIdxs = []int32{ + 4, // 0: google.iam.v1.Policy.bindings:type_name -> google.iam.v1.Binding + 5, // 1: google.iam.v1.Policy.audit_configs:type_name -> google.iam.v1.AuditConfig + 10, // 2: google.iam.v1.Binding.condition:type_name -> google.type.Expr + 6, // 3: google.iam.v1.AuditConfig.audit_log_configs:type_name -> google.iam.v1.AuditLogConfig + 0, // 4: google.iam.v1.AuditLogConfig.log_type:type_name -> google.iam.v1.AuditLogConfig.LogType + 8, // 5: google.iam.v1.PolicyDelta.binding_deltas:type_name -> google.iam.v1.BindingDelta + 9, // 6: google.iam.v1.PolicyDelta.audit_config_deltas:type_name -> google.iam.v1.AuditConfigDelta + 1, // 7: google.iam.v1.BindingDelta.action:type_name -> google.iam.v1.BindingDelta.Action + 10, // 8: google.iam.v1.BindingDelta.condition:type_name -> google.type.Expr + 2, // 9: google.iam.v1.AuditConfigDelta.action:type_name -> google.iam.v1.AuditConfigDelta.Action + 10, // [10:10] is the sub-list for method output_type + 10, // [10:10] is the sub-list for method input_type + 10, // [10:10] is the sub-list for extension type_name + 10, // [10:10] is the sub-list for extension extendee + 0, // [0:10] is the sub-list for field type_name +} + +func init() { file_google_iam_v1_policy_proto_init() } +func file_google_iam_v1_policy_proto_init() { + if File_google_iam_v1_policy_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_google_iam_v1_policy_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Policy); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_iam_v1_policy_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Binding); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_iam_v1_policy_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AuditConfig); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_iam_v1_policy_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AuditLogConfig); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_iam_v1_policy_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PolicyDelta); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_iam_v1_policy_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BindingDelta); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_iam_v1_policy_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AuditConfigDelta); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_google_iam_v1_policy_proto_rawDesc, + NumEnums: 3, + NumMessages: 7, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_google_iam_v1_policy_proto_goTypes, + DependencyIndexes: file_google_iam_v1_policy_proto_depIdxs, + EnumInfos: file_google_iam_v1_policy_proto_enumTypes, + MessageInfos: file_google_iam_v1_policy_proto_msgTypes, + }.Build() + File_google_iam_v1_policy_proto = out.File + file_google_iam_v1_policy_proto_rawDesc = nil + file_google_iam_v1_policy_proto_goTypes = nil + file_google_iam_v1_policy_proto_depIdxs = nil +} diff --git a/vendor/cloud.google.com/go/iam/iam.go b/vendor/cloud.google.com/go/iam/iam.go index 0a06ea2e84d..f004a7afbca 100644 --- a/vendor/cloud.google.com/go/iam/iam.go +++ b/vendor/cloud.google.com/go/iam/iam.go @@ -26,8 +26,8 @@ import ( "fmt" "time" + pb "cloud.google.com/go/iam/apiv1/iampb" gax "github.com/googleapis/gax-go/v2" - pb "google.golang.org/genproto/googleapis/iam/v1" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" diff --git a/vendor/cloud.google.com/go/internal/.repo-metadata-full.json b/vendor/cloud.google.com/go/internal/.repo-metadata-full.json index b39a53da9ab..2dd0e181460 100644 --- a/vendor/cloud.google.com/go/internal/.repo-metadata-full.json +++ b/vendor/cloud.google.com/go/internal/.repo-metadata-full.json @@ -1,930 +1,2009 @@ { "cloud.google.com/go/accessapproval/apiv1": { "distribution_name": "cloud.google.com/go/accessapproval/apiv1", - "description": "", + "description": "Access Approval API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/accessapproval/apiv1", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/accessapproval/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/accesscontextmanager/apiv1": { + "distribution_name": "cloud.google.com/go/accesscontextmanager/apiv1", + "description": "Access Context Manager API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/accesscontextmanager/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/aiplatform/apiv1": { + "distribution_name": "cloud.google.com/go/aiplatform/apiv1", + "description": "Vertex AI API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/aiplatform/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/aiplatform/apiv1beta1": { + "distribution_name": "cloud.google.com/go/aiplatform/apiv1beta1", + "description": "Vertex AI API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/aiplatform/latest/apiv1beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/analytics/admin/apiv1alpha": { "distribution_name": "cloud.google.com/go/analytics/admin/apiv1alpha", - "description": "", + "description": "Google Analytics Admin API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/analytics/latest/admin/apiv1alpha", + "release_level": "alpha", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/apigateway/apiv1": { + "distribution_name": "cloud.google.com/go/apigateway/apiv1", + "description": "API Gateway API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/analytics/admin/apiv1alpha", - "release_level": "alpha" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/apigateway/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, - "cloud.google.com/go/analytics/data/apiv1alpha": { - "distribution_name": "cloud.google.com/go/analytics/data/apiv1alpha", - "description": "", + "cloud.google.com/go/apigeeconnect/apiv1": { + "distribution_name": "cloud.google.com/go/apigeeconnect/apiv1", + "description": "Apigee Connect API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/analytics/data/apiv1alpha", - "release_level": "alpha" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/apigeeconnect/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/apigeeregistry/apiv1": { + "distribution_name": "cloud.google.com/go/apigeeregistry/apiv1", + "description": "Apigee Registry API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/apigeeregistry/latest/apiv1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/apikeys/apiv2": { + "distribution_name": "cloud.google.com/go/apikeys/apiv2", + "description": "API Keys API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/apikeys/latest/apiv2", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/appengine/apiv1": { + "distribution_name": "cloud.google.com/go/appengine/apiv1", + "description": "App Engine Admin API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/appengine/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/area120/tables/apiv1alpha1": { "distribution_name": "cloud.google.com/go/area120/tables/apiv1alpha1", - "description": "", + "description": "Area120 Tables API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/area120/tables/apiv1alpha1", - "release_level": "alpha" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/area120/latest/tables/apiv1alpha1", + "release_level": "alpha", + "library_type": "GAPIC_AUTO" }, - "cloud.google.com/go/asset/apiv1": { - "distribution_name": "cloud.google.com/go/asset/apiv1", - "description": "Cloud Asset API", + "cloud.google.com/go/artifactregistry/apiv1": { + "distribution_name": "cloud.google.com/go/artifactregistry/apiv1", + "description": "Artifact Registry API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/artifactregistry/latest/apiv1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/artifactregistry/apiv1beta2": { + "distribution_name": "cloud.google.com/go/artifactregistry/apiv1beta2", + "description": "Artifact Registry API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/asset/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/artifactregistry/latest/apiv1beta2", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, - "cloud.google.com/go/asset/apiv1beta1": { - "distribution_name": "cloud.google.com/go/asset/apiv1beta1", + "cloud.google.com/go/asset/apiv1": { + "distribution_name": "cloud.google.com/go/asset/apiv1", "description": "Cloud Asset API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/asset/apiv1beta1", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/asset/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/asset/apiv1p2beta1": { "distribution_name": "cloud.google.com/go/asset/apiv1p2beta1", "description": "Cloud Asset API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/asset/apiv1p2beta1", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/asset/latest/apiv1p2beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/asset/apiv1p5beta1": { "distribution_name": "cloud.google.com/go/asset/apiv1p5beta1", "description": "Cloud Asset API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/asset/apiv1p5beta1", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/asset/latest/apiv1p5beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/assuredworkloads/apiv1": { + "distribution_name": "cloud.google.com/go/assuredworkloads/apiv1", + "description": "Assured Workloads API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/assuredworkloads/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/assuredworkloads/apiv1beta1": { "distribution_name": "cloud.google.com/go/assuredworkloads/apiv1beta1", - "description": "", + "description": "Assured Workloads API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/assuredworkloads/apiv1beta1", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/assuredworkloads/latest/apiv1beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/automl/apiv1": { "distribution_name": "cloud.google.com/go/automl/apiv1", "description": "Cloud AutoML API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/automl/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/automl/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/automl/apiv1beta1": { "distribution_name": "cloud.google.com/go/automl/apiv1beta1", "description": "Cloud AutoML API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/automl/apiv1beta1", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/automl/latest/apiv1beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/baremetalsolution/apiv2": { + "distribution_name": "cloud.google.com/go/baremetalsolution/apiv2", + "description": "Bare Metal Solution API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/baremetalsolution/latest/apiv2", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/batch/apiv1": { + "distribution_name": "cloud.google.com/go/batch/apiv1", + "description": "Batch API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/batch/latest/apiv1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/beyondcorp/appconnections/apiv1": { + "distribution_name": "cloud.google.com/go/beyondcorp/appconnections/apiv1", + "description": "BeyondCorp API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/beyondcorp/latest/appconnections/apiv1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/beyondcorp/appconnectors/apiv1": { + "distribution_name": "cloud.google.com/go/beyondcorp/appconnectors/apiv1", + "description": "BeyondCorp API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/beyondcorp/latest/appconnectors/apiv1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/beyondcorp/appgateways/apiv1": { + "distribution_name": "cloud.google.com/go/beyondcorp/appgateways/apiv1", + "description": "BeyondCorp API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/beyondcorp/latest/appgateways/apiv1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/beyondcorp/clientconnectorservices/apiv1": { + "distribution_name": "cloud.google.com/go/beyondcorp/clientconnectorservices/apiv1", + "description": "BeyondCorp API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/beyondcorp/latest/clientconnectorservices/apiv1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/beyondcorp/clientgateways/apiv1": { + "distribution_name": "cloud.google.com/go/beyondcorp/clientgateways/apiv1", + "description": "BeyondCorp API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/beyondcorp/latest/clientgateways/apiv1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/bigquery": { "distribution_name": "cloud.google.com/go/bigquery", "description": "BigQuery", "language": "Go", "client_library_type": "manual", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/bigquery", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/bigquery/latest", + "release_level": "ga", + "library_type": "GAPIC_MANUAL" + }, + "cloud.google.com/go/bigquery/analyticshub/apiv1": { + "distribution_name": "cloud.google.com/go/bigquery/analyticshub/apiv1", + "description": "Analytics Hub API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/bigquery/latest/analyticshub/apiv1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/bigquery/connection/apiv1": { "distribution_name": "cloud.google.com/go/bigquery/connection/apiv1", "description": "BigQuery Connection API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/bigquery/connection/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/bigquery/latest/connection/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/bigquery/connection/apiv1beta1": { "distribution_name": "cloud.google.com/go/bigquery/connection/apiv1beta1", "description": "BigQuery Connection API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/bigquery/connection/apiv1beta1", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/bigquery/latest/connection/apiv1beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/bigquery/dataexchange/apiv1beta1": { + "distribution_name": "cloud.google.com/go/bigquery/dataexchange/apiv1beta1", + "description": "Analytics Hub API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/bigquery/latest/dataexchange/apiv1beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/bigquery/datapolicies/apiv1": { + "distribution_name": "cloud.google.com/go/bigquery/datapolicies/apiv1", + "description": "BigQuery Data Policy API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/bigquery/latest/datapolicies/apiv1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/bigquery/datapolicies/apiv1beta1": { + "distribution_name": "cloud.google.com/go/bigquery/datapolicies/apiv1beta1", + "description": "BigQuery Data Policy API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/bigquery/latest/datapolicies/apiv1beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/bigquery/datatransfer/apiv1": { "distribution_name": "cloud.google.com/go/bigquery/datatransfer/apiv1", "description": "BigQuery Data Transfer API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/bigquery/datatransfer/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/bigquery/latest/datatransfer/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, - "cloud.google.com/go/bigquery/reservation/apiv1": { - "distribution_name": "cloud.google.com/go/bigquery/reservation/apiv1", - "description": "BigQuery Reservation API", + "cloud.google.com/go/bigquery/migration/apiv2": { + "distribution_name": "cloud.google.com/go/bigquery/migration/apiv2", + "description": "BigQuery Migration API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/bigquery/reservation/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/bigquery/latest/migration/apiv2", + "release_level": "beta", + "library_type": "GAPIC_AUTO" }, - "cloud.google.com/go/bigquery/reservation/apiv1beta1": { - "distribution_name": "cloud.google.com/go/bigquery/reservation/apiv1beta1", - "description": "BigQuery Reservation API", + "cloud.google.com/go/bigquery/migration/apiv2alpha": { + "distribution_name": "cloud.google.com/go/bigquery/migration/apiv2alpha", + "description": "BigQuery Migration API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/bigquery/reservation/apiv1beta1", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/bigquery/latest/migration/apiv2alpha", + "release_level": "alpha", + "library_type": "GAPIC_AUTO" }, - "cloud.google.com/go/bigquery/storage/apiv1": { - "distribution_name": "cloud.google.com/go/bigquery/storage/apiv1", - "description": "BigQuery Storage API", + "cloud.google.com/go/bigquery/reservation/apiv1": { + "distribution_name": "cloud.google.com/go/bigquery/reservation/apiv1", + "description": "BigQuery Reservation API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/bigquery/storage/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/bigquery/latest/reservation/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, - "cloud.google.com/go/bigquery/storage/apiv1alpha2": { - "distribution_name": "cloud.google.com/go/bigquery/storage/apiv1alpha2", + "cloud.google.com/go/bigquery/storage/apiv1": { + "distribution_name": "cloud.google.com/go/bigquery/storage/apiv1", "description": "BigQuery Storage API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/bigquery/storage/apiv1alpha2", - "release_level": "alpha" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/bigquery/latest/storage/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/bigquery/storage/apiv1beta1": { "distribution_name": "cloud.google.com/go/bigquery/storage/apiv1beta1", "description": "BigQuery Storage API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/bigquery/storage/apiv1beta1", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/bigquery/latest/storage/apiv1beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/bigquery/storage/apiv1beta2": { "distribution_name": "cloud.google.com/go/bigquery/storage/apiv1beta2", "description": "BigQuery Storage API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/bigquery/storage/apiv1beta2", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/bigquery/latest/storage/apiv1beta2", + "release_level": "beta", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/bigtable": { "distribution_name": "cloud.google.com/go/bigtable", "description": "Cloud BigTable", "language": "Go", "client_library_type": "manual", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/bigtable", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/bigtable/latest", + "release_level": "ga", + "library_type": "GAPIC_MANUAL" }, "cloud.google.com/go/billing/apiv1": { "distribution_name": "cloud.google.com/go/billing/apiv1", "description": "Cloud Billing API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/billing/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/billing/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/billing/budgets/apiv1": { "distribution_name": "cloud.google.com/go/billing/budgets/apiv1", "description": "Cloud Billing Budget API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/billing/budgets/apiv1", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/billing/latest/budgets/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/billing/budgets/apiv1beta1": { "distribution_name": "cloud.google.com/go/billing/budgets/apiv1beta1", - "description": "", + "description": "Cloud Billing Budget API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/billing/latest/budgets/apiv1beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/binaryauthorization/apiv1": { + "distribution_name": "cloud.google.com/go/binaryauthorization/apiv1", + "description": "Binary Authorization API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/binaryauthorization/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/binaryauthorization/apiv1beta1": { + "distribution_name": "cloud.google.com/go/binaryauthorization/apiv1beta1", + "description": "Binary Authorization API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/binaryauthorization/latest/apiv1beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/certificatemanager/apiv1": { + "distribution_name": "cloud.google.com/go/certificatemanager/apiv1", + "description": "Certificate Manager API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/certificatemanager/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/channel/apiv1": { + "distribution_name": "cloud.google.com/go/channel/apiv1", + "description": "Cloud Channel API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/billing/budgets/apiv1beta1", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/channel/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/cloudbuild/apiv1/v2": { "distribution_name": "cloud.google.com/go/cloudbuild/apiv1/v2", "description": "Cloud Build API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/cloudbuild/apiv1/v2", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/cloudbuild/latest/apiv1/v2", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/clouddms/apiv1": { + "distribution_name": "cloud.google.com/go/clouddms/apiv1", + "description": "Database Migration API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/clouddms/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/cloudtasks/apiv2": { "distribution_name": "cloud.google.com/go/cloudtasks/apiv2", "description": "Cloud Tasks API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/cloudtasks/apiv2", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/cloudtasks/latest/apiv2", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/cloudtasks/apiv2beta2": { "distribution_name": "cloud.google.com/go/cloudtasks/apiv2beta2", "description": "Cloud Tasks API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/cloudtasks/apiv2beta2", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/cloudtasks/latest/apiv2beta2", + "release_level": "beta", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/cloudtasks/apiv2beta3": { "distribution_name": "cloud.google.com/go/cloudtasks/apiv2beta3", "description": "Cloud Tasks API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/cloudtasks/apiv2beta3", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/cloudtasks/latest/apiv2beta3", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/compute/apiv1": { + "distribution_name": "cloud.google.com/go/compute/apiv1", + "description": "Google Compute Engine API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/compute/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/compute/metadata": { + "distribution_name": "cloud.google.com/go/compute/metadata", + "description": "Service Metadata API", + "language": "Go", + "client_library_type": "manual", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/compute/latest/metadata", + "release_level": "ga", + "library_type": "CORE" + }, + "cloud.google.com/go/contactcenterinsights/apiv1": { + "distribution_name": "cloud.google.com/go/contactcenterinsights/apiv1", + "description": "Contact Center AI Insights API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/contactcenterinsights/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/container/apiv1": { "distribution_name": "cloud.google.com/go/container/apiv1", "description": "Kubernetes Engine API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/container/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/container/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/containeranalysis/apiv1beta1": { "distribution_name": "cloud.google.com/go/containeranalysis/apiv1beta1", "description": "Container Analysis API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/containeranalysis/apiv1beta1", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/containeranalysis/latest/apiv1beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/datacatalog/apiv1": { "distribution_name": "cloud.google.com/go/datacatalog/apiv1", "description": "Google Cloud Data Catalog API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/datacatalog/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/datacatalog/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/datacatalog/apiv1beta1": { "distribution_name": "cloud.google.com/go/datacatalog/apiv1beta1", "description": "Google Cloud Data Catalog API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/datacatalog/apiv1beta1", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/datacatalog/latest/apiv1beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/datacatalog/lineage/apiv1": { + "distribution_name": "cloud.google.com/go/datacatalog/lineage/apiv1", + "description": "Data Lineage API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/datacatalog/latest/lineage/apiv1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/dataflow/apiv1beta3": { + "distribution_name": "cloud.google.com/go/dataflow/apiv1beta3", + "description": "Dataflow API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/dataflow/latest/apiv1beta3", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/dataform/apiv1alpha2": { + "distribution_name": "cloud.google.com/go/dataform/apiv1alpha2", + "description": "Dataform API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/dataform/latest/apiv1alpha2", + "release_level": "alpha", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/dataform/apiv1beta1": { + "distribution_name": "cloud.google.com/go/dataform/apiv1beta1", + "description": "Dataform API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/dataform/latest/apiv1beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/datafusion/apiv1": { + "distribution_name": "cloud.google.com/go/datafusion/apiv1", + "description": "Cloud Data Fusion API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/datafusion/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/datalabeling/apiv1beta1": { + "distribution_name": "cloud.google.com/go/datalabeling/apiv1beta1", + "description": "Data Labeling API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/datalabeling/latest/apiv1beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/dataplex/apiv1": { + "distribution_name": "cloud.google.com/go/dataplex/apiv1", + "description": "Cloud Dataplex API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/dataplex/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/dataproc/apiv1": { "distribution_name": "cloud.google.com/go/dataproc/apiv1", "description": "Cloud Dataproc API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/dataproc/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/dataproc/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, - "cloud.google.com/go/dataproc/apiv1beta2": { - "distribution_name": "cloud.google.com/go/dataproc/apiv1beta2", - "description": "Cloud Dataproc API", + "cloud.google.com/go/dataqna/apiv1alpha": { + "distribution_name": "cloud.google.com/go/dataqna/apiv1alpha", + "description": "Data QnA API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/dataproc/apiv1beta2", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/dataqna/latest/apiv1alpha", + "release_level": "alpha", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/datastore": { "distribution_name": "cloud.google.com/go/datastore", "description": "Cloud Datastore", "language": "Go", "client_library_type": "manual", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/datastore", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/datastore/latest", + "release_level": "ga", + "library_type": "GAPIC_MANUAL" }, "cloud.google.com/go/datastore/admin/apiv1": { "distribution_name": "cloud.google.com/go/datastore/admin/apiv1", "description": "Cloud Datastore API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/datastore/admin/apiv1", - "release_level": "alpha" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/datastore/latest/admin/apiv1", + "release_level": "alpha", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/datastream/apiv1": { + "distribution_name": "cloud.google.com/go/datastream/apiv1", + "description": "Datastream API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/datastream/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/datastream/apiv1alpha1": { + "distribution_name": "cloud.google.com/go/datastream/apiv1alpha1", + "description": "Datastream API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/datastream/latest/apiv1alpha1", + "release_level": "alpha", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/debugger/apiv2": { "distribution_name": "cloud.google.com/go/debugger/apiv2", "description": "Stackdriver Debugger API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/debugger/apiv2", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/latest/debugger/apiv2", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/deploy/apiv1": { + "distribution_name": "cloud.google.com/go/deploy/apiv1", + "description": "Google Cloud Deploy API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/deploy/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/dialogflow/apiv2": { "distribution_name": "cloud.google.com/go/dialogflow/apiv2", "description": "Dialogflow API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/dialogflow/apiv2", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/dialogflow/latest/apiv2", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/dialogflow/apiv2beta1": { + "distribution_name": "cloud.google.com/go/dialogflow/apiv2beta1", + "description": "Dialogflow API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/dialogflow/latest/apiv2beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/dialogflow/cx/apiv3": { + "distribution_name": "cloud.google.com/go/dialogflow/cx/apiv3", + "description": "Dialogflow API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/dialogflow/latest/cx/apiv3", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/dialogflow/cx/apiv3beta1": { "distribution_name": "cloud.google.com/go/dialogflow/cx/apiv3beta1", "description": "Dialogflow API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/dialogflow/cx/apiv3beta1", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/dialogflow/latest/cx/apiv3beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/discoveryengine/apiv1beta": { + "distribution_name": "cloud.google.com/go/discoveryengine/apiv1beta", + "description": "Discovery Engine API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/discoveryengine/latest/apiv1beta", + "release_level": "beta", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/dlp/apiv2": { "distribution_name": "cloud.google.com/go/dlp/apiv2", "description": "Cloud Data Loss Prevention (DLP) API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/dlp/apiv2", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/dlp/latest/apiv2", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/documentai/apiv1": { + "distribution_name": "cloud.google.com/go/documentai/apiv1", + "description": "Cloud Document AI API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/documentai/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/documentai/apiv1beta3": { + "distribution_name": "cloud.google.com/go/documentai/apiv1beta3", + "description": "Cloud Document AI API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/documentai/latest/apiv1beta3", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/domains/apiv1beta1": { + "distribution_name": "cloud.google.com/go/domains/apiv1beta1", + "description": "Cloud Domains API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/domains/latest/apiv1beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/edgecontainer/apiv1": { + "distribution_name": "cloud.google.com/go/edgecontainer/apiv1", + "description": "Distributed Cloud Edge Container API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/edgecontainer/latest/apiv1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/errorreporting": { "distribution_name": "cloud.google.com/go/errorreporting", "description": "Cloud Error Reporting API", "language": "Go", "client_library_type": "manual", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/errorreporting", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/errorreporting/latest", + "release_level": "beta", + "library_type": "GAPIC_MANUAL" }, "cloud.google.com/go/errorreporting/apiv1beta1": { "distribution_name": "cloud.google.com/go/errorreporting/apiv1beta1", - "description": "Cloud Error Reporting API", + "description": "Error Reporting API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/errorreporting/latest/apiv1beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/essentialcontacts/apiv1": { + "distribution_name": "cloud.google.com/go/essentialcontacts/apiv1", + "description": "Essential Contacts API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/essentialcontacts/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/eventarc/apiv1": { + "distribution_name": "cloud.google.com/go/eventarc/apiv1", + "description": "Eventarc API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/eventarc/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/eventarc/publishing/apiv1": { + "distribution_name": "cloud.google.com/go/eventarc/publishing/apiv1", + "description": "Eventarc Publishing API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/eventarc/latest/publishing/apiv1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/filestore/apiv1": { + "distribution_name": "cloud.google.com/go/filestore/apiv1", + "description": "Cloud Filestore API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/errorreporting/apiv1beta1", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/filestore/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/firestore": { "distribution_name": "cloud.google.com/go/firestore", "description": "Cloud Firestore API", "language": "Go", "client_library_type": "manual", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/firestore", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/firestore/latest", + "release_level": "ga", + "library_type": "GAPIC_MANUAL" }, "cloud.google.com/go/firestore/apiv1": { "distribution_name": "cloud.google.com/go/firestore/apiv1", "description": "Cloud Firestore API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/firestore/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/firestore/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/firestore/apiv1/admin": { "distribution_name": "cloud.google.com/go/firestore/apiv1/admin", - "description": "Google Cloud Firestore Admin API", + "description": "Cloud Firestore API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/firestore/apiv1/admin", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/firestore/latest/apiv1/admin", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/functions/apiv1": { "distribution_name": "cloud.google.com/go/functions/apiv1", - "description": "", + "description": "Cloud Functions API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/functions/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/functions/apiv2": { + "distribution_name": "cloud.google.com/go/functions/apiv2", + "description": "Cloud Functions API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/functions/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/functions/latest/apiv2", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/functions/apiv2beta": { + "distribution_name": "cloud.google.com/go/functions/apiv2beta", + "description": "Cloud Functions API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/functions/latest/apiv2beta", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/functions/metadata": { + "distribution_name": "cloud.google.com/go/functions/metadata", + "description": "Cloud Functions", + "language": "Go", + "client_library_type": "manual", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/functions/latest/metadata", + "release_level": "alpha", + "library_type": "CORE" }, "cloud.google.com/go/gaming/apiv1": { "distribution_name": "cloud.google.com/go/gaming/apiv1", - "description": "", + "description": "Game Services API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/gaming/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/gaming/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/gaming/apiv1beta": { "distribution_name": "cloud.google.com/go/gaming/apiv1beta", - "description": "", + "description": "Game Services API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/gaming/latest/apiv1beta", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/gkebackup/apiv1": { + "distribution_name": "cloud.google.com/go/gkebackup/apiv1", + "description": "Backup for GKE API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/gkebackup/latest/apiv1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/gkeconnect/gateway/apiv1beta1": { + "distribution_name": "cloud.google.com/go/gkeconnect/gateway/apiv1beta1", + "description": "Connect Gateway API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/gkeconnect/latest/gateway/apiv1beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/gkehub/apiv1beta1": { + "distribution_name": "cloud.google.com/go/gkehub/apiv1beta1", + "description": "GKE Hub API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/gaming/apiv1beta", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/gkehub/latest/apiv1beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/gkemulticloud/apiv1": { + "distribution_name": "cloud.google.com/go/gkemulticloud/apiv1", + "description": "Anthos Multi-Cloud API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/gkemulticloud/latest/apiv1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/gsuiteaddons/apiv1": { + "distribution_name": "cloud.google.com/go/gsuiteaddons/apiv1", + "description": "Google Workspace Add-ons API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/gsuiteaddons/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/iam": { "distribution_name": "cloud.google.com/go/iam", "description": "Cloud IAM", "language": "Go", "client_library_type": "manual", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/iam", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/iam/latest", + "release_level": "ga", + "library_type": "CORE" + }, + "cloud.google.com/go/iam/apiv1": { + "distribution_name": "cloud.google.com/go/iam/apiv1", + "description": "IAM Meta API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/iam/latest/apiv1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/iam/apiv2": { + "distribution_name": "cloud.google.com/go/iam/apiv2", + "description": "Identity and Access Management (IAM) API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/iam/latest/apiv2", + "release_level": "beta", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/iam/credentials/apiv1": { "distribution_name": "cloud.google.com/go/iam/credentials/apiv1", "description": "IAM Service Account Credentials API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/iam/credentials/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/iam/latest/credentials/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/iap/apiv1": { + "distribution_name": "cloud.google.com/go/iap/apiv1", + "description": "Cloud Identity-Aware Proxy API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/iap/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/ids/apiv1": { + "distribution_name": "cloud.google.com/go/ids/apiv1", + "description": "Cloud IDS API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/ids/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/iot/apiv1": { "distribution_name": "cloud.google.com/go/iot/apiv1", "description": "Cloud IoT API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/iot/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/iot/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/kms/apiv1": { "distribution_name": "cloud.google.com/go/kms/apiv1", "description": "Cloud Key Management Service (KMS) API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/kms/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/kms/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/language/apiv1": { "distribution_name": "cloud.google.com/go/language/apiv1", "description": "Cloud Natural Language API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/language/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/language/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/language/apiv1beta2": { "distribution_name": "cloud.google.com/go/language/apiv1beta2", "description": "Cloud Natural Language API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/language/apiv1beta2", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/language/latest/apiv1beta2", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/lifesciences/apiv2beta": { + "distribution_name": "cloud.google.com/go/lifesciences/apiv2beta", + "description": "Cloud Life Sciences API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/lifesciences/latest/apiv2beta", + "release_level": "beta", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/logging": { "distribution_name": "cloud.google.com/go/logging", "description": "Cloud Logging API", "language": "Go", "client_library_type": "manual", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/logging", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/logging/latest", + "release_level": "ga", + "library_type": "GAPIC_MANUAL" }, "cloud.google.com/go/logging/apiv2": { "distribution_name": "cloud.google.com/go/logging/apiv2", "description": "Cloud Logging API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/logging/apiv2", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/logging/latest/apiv2", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/longrunning/autogen": { "distribution_name": "cloud.google.com/go/longrunning/autogen", "description": "Long Running Operations API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/longrunning/autogen", - "release_level": "alpha" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/longrunning/latest/autogen", + "release_level": "alpha", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/managedidentities/apiv1": { "distribution_name": "cloud.google.com/go/managedidentities/apiv1", "description": "Managed Service for Microsoft Active Directory API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/managedidentities/apiv1", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/managedidentities/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/maps/addressvalidation/apiv1": { + "distribution_name": "cloud.google.com/go/maps/addressvalidation/apiv1", + "description": "Address Validation API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/maps/latest/addressvalidation/apiv1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/maps/mapsplatformdatasets/apiv1alpha": { + "distribution_name": "cloud.google.com/go/maps/mapsplatformdatasets/apiv1alpha", + "description": "Maps Platform Datasets API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/maps/latest/mapsplatformdatasets/apiv1alpha", + "release_level": "alpha", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/maps/routing/apiv2": { + "distribution_name": "cloud.google.com/go/maps/routing/apiv2", + "description": "Routes API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/maps/latest/routing/apiv2", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/mediatranslation/apiv1beta1": { + "distribution_name": "cloud.google.com/go/mediatranslation/apiv1beta1", + "description": "Media Translation API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/mediatranslation/latest/apiv1beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/memcache/apiv1": { + "distribution_name": "cloud.google.com/go/memcache/apiv1", + "description": "Cloud Memorystore for Memcached API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/memcache/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/memcache/apiv1beta2": { "distribution_name": "cloud.google.com/go/memcache/apiv1beta2", "description": "Cloud Memorystore for Memcached API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/memcache/apiv1beta2", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/memcache/latest/apiv1beta2", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/metastore/apiv1": { + "distribution_name": "cloud.google.com/go/metastore/apiv1", + "description": "Dataproc Metastore API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/metastore/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/metastore/apiv1alpha": { + "distribution_name": "cloud.google.com/go/metastore/apiv1alpha", + "description": "Dataproc Metastore API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/metastore/latest/apiv1alpha", + "release_level": "alpha", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/metastore/apiv1beta": { + "distribution_name": "cloud.google.com/go/metastore/apiv1beta", + "description": "Dataproc Metastore API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/metastore/latest/apiv1beta", + "release_level": "beta", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/monitoring/apiv3/v2": { "distribution_name": "cloud.google.com/go/monitoring/apiv3/v2", "description": "Cloud Monitoring API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/monitoring/apiv3/v2", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/monitoring/latest/apiv3/v2", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/monitoring/dashboard/apiv1": { "distribution_name": "cloud.google.com/go/monitoring/dashboard/apiv1", - "description": "", + "description": "Cloud Monitoring API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/monitoring/latest/dashboard/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/monitoring/metricsscope/apiv1": { + "distribution_name": "cloud.google.com/go/monitoring/metricsscope/apiv1", + "description": "Cloud Monitoring API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/monitoring/latest/metricsscope/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/networkconnectivity/apiv1": { + "distribution_name": "cloud.google.com/go/networkconnectivity/apiv1", + "description": "Network Connectivity API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/networkconnectivity/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/networkconnectivity/apiv1alpha1": { + "distribution_name": "cloud.google.com/go/networkconnectivity/apiv1alpha1", + "description": "Network Connectivity API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/monitoring/dashboard/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/networkconnectivity/latest/apiv1alpha1", + "release_level": "alpha", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/networkmanagement/apiv1": { + "distribution_name": "cloud.google.com/go/networkmanagement/apiv1", + "description": "Network Management API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/networkmanagement/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/networksecurity/apiv1beta1": { + "distribution_name": "cloud.google.com/go/networksecurity/apiv1beta1", + "description": "Network Security API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/networksecurity/latest/apiv1beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/notebooks/apiv1": { + "distribution_name": "cloud.google.com/go/notebooks/apiv1", + "description": "Notebooks API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/notebooks/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/notebooks/apiv1beta1": { "distribution_name": "cloud.google.com/go/notebooks/apiv1beta1", "description": "Notebooks API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/notebooks/apiv1beta1", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/notebooks/latest/apiv1beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/optimization/apiv1": { + "distribution_name": "cloud.google.com/go/optimization/apiv1", + "description": "Cloud Optimization API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/optimization/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/orchestration/airflow/service/apiv1": { + "distribution_name": "cloud.google.com/go/orchestration/airflow/service/apiv1", + "description": "Cloud Composer API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/orchestration/latest/airflow/service/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/orgpolicy/apiv2": { + "distribution_name": "cloud.google.com/go/orgpolicy/apiv2", + "description": "Organization Policy API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/orgpolicy/latest/apiv2", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/osconfig/agentendpoint/apiv1": { "distribution_name": "cloud.google.com/go/osconfig/agentendpoint/apiv1", - "description": "Cloud OS Config API", + "description": "OS Config API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/osconfig/agentendpoint/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/osconfig/latest/agentendpoint/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/osconfig/agentendpoint/apiv1beta": { "distribution_name": "cloud.google.com/go/osconfig/agentendpoint/apiv1beta", - "description": "Cloud OS Config API", + "description": "OS Config API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/osconfig/agentendpoint/apiv1beta", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/osconfig/latest/agentendpoint/apiv1beta", + "release_level": "beta", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/osconfig/apiv1": { "distribution_name": "cloud.google.com/go/osconfig/apiv1", - "description": "Cloud OS Config API", + "description": "OS Config API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/osconfig/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/osconfig/apiv1alpha": { + "distribution_name": "cloud.google.com/go/osconfig/apiv1alpha", + "description": "OS Config API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/osconfig/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/osconfig/latest/apiv1alpha", + "release_level": "alpha", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/osconfig/apiv1beta": { "distribution_name": "cloud.google.com/go/osconfig/apiv1beta", - "description": "Cloud OS Config API", + "description": "OS Config API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/osconfig/apiv1beta", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/osconfig/latest/apiv1beta", + "release_level": "beta", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/oslogin/apiv1": { "distribution_name": "cloud.google.com/go/oslogin/apiv1", "description": "Cloud OS Login API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/oslogin/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/oslogin/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/oslogin/apiv1beta": { "distribution_name": "cloud.google.com/go/oslogin/apiv1beta", "description": "Cloud OS Login API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/oslogin/apiv1beta", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/oslogin/latest/apiv1beta", + "release_level": "beta", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/phishingprotection/apiv1beta1": { "distribution_name": "cloud.google.com/go/phishingprotection/apiv1beta1", "description": "Phishing Protection API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/phishingprotection/apiv1beta1", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/phishingprotection/latest/apiv1beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/policytroubleshooter/apiv1": { "distribution_name": "cloud.google.com/go/policytroubleshooter/apiv1", "description": "Policy Troubleshooter API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/policytroubleshooter/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/policytroubleshooter/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/privatecatalog/apiv1beta1": { + "distribution_name": "cloud.google.com/go/privatecatalog/apiv1beta1", + "description": "Cloud Private Catalog API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/privatecatalog/latest/apiv1beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/profiler": { "distribution_name": "cloud.google.com/go/profiler", "description": "Cloud Profiler", "language": "Go", "client_library_type": "manual", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/profiler", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/profiler/latest", + "release_level": "ga", + "library_type": "AGENT" }, "cloud.google.com/go/pubsub": { "distribution_name": "cloud.google.com/go/pubsub", "description": "Cloud PubSub", "language": "Go", "client_library_type": "manual", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/pubsub", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/pubsub/latest", + "release_level": "ga", + "library_type": "GAPIC_MANUAL" }, "cloud.google.com/go/pubsub/apiv1": { "distribution_name": "cloud.google.com/go/pubsub/apiv1", "description": "Cloud Pub/Sub API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/pubsub/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/pubsub/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/pubsublite": { + "distribution_name": "cloud.google.com/go/pubsublite", + "description": "Cloud PubSub Lite", + "language": "Go", + "client_library_type": "manual", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/pubsublite/latest", + "release_level": "ga", + "library_type": "GAPIC_MANUAL" }, "cloud.google.com/go/pubsublite/apiv1": { "distribution_name": "cloud.google.com/go/pubsublite/apiv1", - "description": "", + "description": "Pub/Sub Lite API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/pubsublite/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/pubsublite/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, - "cloud.google.com/go/recaptchaenterprise/apiv1": { - "distribution_name": "cloud.google.com/go/recaptchaenterprise/apiv1", + "cloud.google.com/go/recaptchaenterprise/v2/apiv1": { + "distribution_name": "cloud.google.com/go/recaptchaenterprise/v2/apiv1", "description": "reCAPTCHA Enterprise API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/recaptchaenterprise/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/recaptchaenterprise/v2/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, - "cloud.google.com/go/recaptchaenterprise/apiv1beta1": { - "distribution_name": "cloud.google.com/go/recaptchaenterprise/apiv1beta1", + "cloud.google.com/go/recaptchaenterprise/v2/apiv1beta1": { + "distribution_name": "cloud.google.com/go/recaptchaenterprise/v2/apiv1beta1", "description": "reCAPTCHA Enterprise API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/recaptchaenterprise/apiv1beta1", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/recaptchaenterprise/v2/latest/apiv1beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/recommendationengine/apiv1beta1": { + "distribution_name": "cloud.google.com/go/recommendationengine/apiv1beta1", + "description": "Recommendations AI", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/recommendationengine/latest/apiv1beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/recommender/apiv1": { "distribution_name": "cloud.google.com/go/recommender/apiv1", "description": "Recommender API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/recommender/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/recommender/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/recommender/apiv1beta1": { "distribution_name": "cloud.google.com/go/recommender/apiv1beta1", "description": "Recommender API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/recommender/apiv1beta1", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/recommender/latest/apiv1beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/redis/apiv1": { "distribution_name": "cloud.google.com/go/redis/apiv1", "description": "Google Cloud Memorystore for Redis API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/redis/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/redis/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/redis/apiv1beta1": { "distribution_name": "cloud.google.com/go/redis/apiv1beta1", "description": "Google Cloud Memorystore for Redis API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/redis/apiv1beta1", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/redis/latest/apiv1beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/resourcemanager/apiv2": { + "distribution_name": "cloud.google.com/go/resourcemanager/apiv2", + "description": "Cloud Resource Manager API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/resourcemanager/latest/apiv2", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/resourcemanager/apiv3": { + "distribution_name": "cloud.google.com/go/resourcemanager/apiv3", + "description": "Cloud Resource Manager API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/resourcemanager/latest/apiv3", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/resourcesettings/apiv1": { + "distribution_name": "cloud.google.com/go/resourcesettings/apiv1", + "description": "Resource Settings API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/resourcesettings/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/retail/apiv2": { + "distribution_name": "cloud.google.com/go/retail/apiv2", + "description": "Retail API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/retail/latest/apiv2", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/retail/apiv2alpha": { + "distribution_name": "cloud.google.com/go/retail/apiv2alpha", + "description": "Retail API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/retail/latest/apiv2alpha", + "release_level": "alpha", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/retail/apiv2beta": { + "distribution_name": "cloud.google.com/go/retail/apiv2beta", + "description": "Retail API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/retail/latest/apiv2beta", + "release_level": "beta", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/rpcreplay": { "distribution_name": "cloud.google.com/go/rpcreplay", "description": "RPC Replay", "language": "Go", "client_library_type": "manual", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/rpcreplay", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/latest/rpcreplay", + "release_level": "ga", + "library_type": "OTHER" + }, + "cloud.google.com/go/run/apiv2": { + "distribution_name": "cloud.google.com/go/run/apiv2", + "description": "Cloud Run Admin API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/run/latest/apiv2", + "release_level": "beta", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/scheduler/apiv1": { "distribution_name": "cloud.google.com/go/scheduler/apiv1", "description": "Cloud Scheduler API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/scheduler/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/scheduler/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/scheduler/apiv1beta1": { "distribution_name": "cloud.google.com/go/scheduler/apiv1beta1", "description": "Cloud Scheduler API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/scheduler/apiv1beta1", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/scheduler/latest/apiv1beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/secretmanager/apiv1": { "distribution_name": "cloud.google.com/go/secretmanager/apiv1", "description": "Secret Manager API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/secretmanager/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/secretmanager/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, - "cloud.google.com/go/secretmanager/apiv1beta1": { - "distribution_name": "cloud.google.com/go/secretmanager/apiv1beta1", - "description": "Secret Manager API", + "cloud.google.com/go/security/privateca/apiv1": { + "distribution_name": "cloud.google.com/go/security/privateca/apiv1", + "description": "Certificate Authority API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/secretmanager/apiv1beta1", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/security/latest/privateca/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/security/privateca/apiv1beta1": { "distribution_name": "cloud.google.com/go/security/privateca/apiv1beta1", - "description": "", + "description": "Certificate Authority API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/security/latest/privateca/apiv1beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/security/publicca/apiv1beta1": { + "distribution_name": "cloud.google.com/go/security/publicca/apiv1beta1", + "description": "Public Certificate Authority API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/security/privateca/apiv1beta1", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/security/latest/publicca/apiv1beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/securitycenter/apiv1": { "distribution_name": "cloud.google.com/go/securitycenter/apiv1", "description": "Security Command Center API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/securitycenter/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/securitycenter/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/securitycenter/apiv1beta1": { "distribution_name": "cloud.google.com/go/securitycenter/apiv1beta1", "description": "Security Command Center API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/securitycenter/apiv1beta1", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/securitycenter/latest/apiv1beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/securitycenter/apiv1p1beta1": { "distribution_name": "cloud.google.com/go/securitycenter/apiv1p1beta1", "description": "Security Command Center API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/securitycenter/apiv1p1beta1", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/securitycenter/latest/apiv1p1beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/securitycenter/settings/apiv1beta1": { "distribution_name": "cloud.google.com/go/securitycenter/settings/apiv1beta1", "description": "Cloud Security Command Center API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/securitycenter/settings/apiv1beta1", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/securitycenter/latest/settings/apiv1beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/servicecontrol/apiv1": { + "distribution_name": "cloud.google.com/go/servicecontrol/apiv1", + "description": "Service Control API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/servicecontrol/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/servicedirectory/apiv1": { + "distribution_name": "cloud.google.com/go/servicedirectory/apiv1", + "description": "Service Directory API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/servicedirectory/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/servicedirectory/apiv1beta1": { "distribution_name": "cloud.google.com/go/servicedirectory/apiv1beta1", "description": "Service Directory API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/servicedirectory/apiv1beta1", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/servicedirectory/latest/apiv1beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/servicemanagement/apiv1": { + "distribution_name": "cloud.google.com/go/servicemanagement/apiv1", + "description": "Service Management API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/servicemanagement/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/serviceusage/apiv1": { + "distribution_name": "cloud.google.com/go/serviceusage/apiv1", + "description": "Service Usage API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/serviceusage/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/shell/apiv1": { + "distribution_name": "cloud.google.com/go/shell/apiv1", + "description": "Cloud Shell API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/shell/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/spanner": { "distribution_name": "cloud.google.com/go/spanner", "description": "Cloud Spanner", "language": "Go", "client_library_type": "manual", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/spanner", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/spanner/latest", + "release_level": "ga", + "library_type": "GAPIC_MANUAL" }, "cloud.google.com/go/spanner/admin/database/apiv1": { "distribution_name": "cloud.google.com/go/spanner/admin/database/apiv1", - "description": "Cloud Spanner Database Admin API", + "description": "Cloud Spanner API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/spanner/admin/database/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/spanner/latest/admin/database/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/spanner/admin/instance/apiv1": { "distribution_name": "cloud.google.com/go/spanner/admin/instance/apiv1", "description": "Cloud Spanner Instance Admin API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/spanner/admin/instance/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/spanner/latest/admin/instance/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/spanner/apiv1": { "distribution_name": "cloud.google.com/go/spanner/apiv1", "description": "Cloud Spanner API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/spanner/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/spanner/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/speech/apiv1": { "distribution_name": "cloud.google.com/go/speech/apiv1", "description": "Cloud Speech-to-Text API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/speech/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/speech/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/speech/apiv1p1beta1": { "distribution_name": "cloud.google.com/go/speech/apiv1p1beta1", "description": "Cloud Speech-to-Text API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/speech/apiv1p1beta1", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/speech/latest/apiv1p1beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/speech/apiv2": { + "distribution_name": "cloud.google.com/go/speech/apiv2", + "description": "Cloud Speech-to-Text API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/speech/latest/apiv2", + "release_level": "beta", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/storage": { "distribution_name": "cloud.google.com/go/storage", "description": "Cloud Storage (GCS)", "language": "Go", "client_library_type": "manual", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/storage", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/storage/latest", + "release_level": "ga", + "library_type": "GAPIC_MANUAL" + }, + "cloud.google.com/go/storage/internal/apiv2": { + "distribution_name": "cloud.google.com/go/storage/internal/apiv2", + "description": "Cloud Storage API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/storage/latest/internal/apiv2", + "release_level": "alpha", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/storagetransfer/apiv1": { + "distribution_name": "cloud.google.com/go/storagetransfer/apiv1", + "description": "Storage Transfer API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/storagetransfer/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/talent/apiv4": { "distribution_name": "cloud.google.com/go/talent/apiv4", - "description": "", + "description": "Cloud Talent Solution API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/talent/apiv4", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/talent/latest/apiv4", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/talent/apiv4beta1": { "distribution_name": "cloud.google.com/go/talent/apiv4beta1", "description": "Cloud Talent Solution API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/talent/apiv4beta1", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/talent/latest/apiv4beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/texttospeech/apiv1": { "distribution_name": "cloud.google.com/go/texttospeech/apiv1", "description": "Cloud Text-to-Speech API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/texttospeech/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/texttospeech/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, - "cloud.google.com/go/trace": { - "distribution_name": "cloud.google.com/go/trace", - "description": "Stackdriver Trace", + "cloud.google.com/go/tpu/apiv1": { + "distribution_name": "cloud.google.com/go/tpu/apiv1", + "description": "Cloud TPU API", "language": "Go", - "client_library_type": "manual", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/trace", - "release_level": "ga" + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/tpu/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/trace/apiv1": { "distribution_name": "cloud.google.com/go/trace/apiv1", "description": "Stackdriver Trace API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/trace/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/trace/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/trace/apiv2": { "distribution_name": "cloud.google.com/go/trace/apiv2", "description": "Stackdriver Trace API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/trace/apiv2", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/trace/latest/apiv2", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/translate/apiv3": { "distribution_name": "cloud.google.com/go/translate/apiv3", "description": "Cloud Translation API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/translate/apiv3", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/translate/latest/apiv3", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/video/livestream/apiv1": { + "distribution_name": "cloud.google.com/go/video/livestream/apiv1", + "description": "Live Stream API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/video/latest/livestream/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, - "cloud.google.com/go/video/transcoder/apiv1beta1": { - "distribution_name": "cloud.google.com/go/video/transcoder/apiv1beta1", - "description": "", + "cloud.google.com/go/video/stitcher/apiv1": { + "distribution_name": "cloud.google.com/go/video/stitcher/apiv1", + "description": "Video Stitcher API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/video/transcoder/apiv1beta1", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/video/latest/stitcher/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/video/transcoder/apiv1": { + "distribution_name": "cloud.google.com/go/video/transcoder/apiv1", + "description": "Transcoder API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/video/latest/transcoder/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/videointelligence/apiv1": { "distribution_name": "cloud.google.com/go/videointelligence/apiv1", "description": "Cloud Video Intelligence API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/videointelligence/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/videointelligence/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/videointelligence/apiv1beta2": { "distribution_name": "cloud.google.com/go/videointelligence/apiv1beta2", "description": "Google Cloud Video Intelligence API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/videointelligence/apiv1beta2", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/videointelligence/latest/apiv1beta2", + "release_level": "beta", + "library_type": "GAPIC_AUTO" }, - "cloud.google.com/go/vision/apiv1": { - "distribution_name": "cloud.google.com/go/vision/apiv1", + "cloud.google.com/go/videointelligence/apiv1p3beta1": { + "distribution_name": "cloud.google.com/go/videointelligence/apiv1p3beta1", + "description": "Cloud Video Intelligence API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/videointelligence/latest/apiv1p3beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/vision/v2/apiv1": { + "distribution_name": "cloud.google.com/go/vision/v2/apiv1", "description": "Cloud Vision API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/vision/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/vision/v2/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, - "cloud.google.com/go/vision/apiv1p1beta1": { - "distribution_name": "cloud.google.com/go/vision/apiv1p1beta1", + "cloud.google.com/go/vision/v2/apiv1p1beta1": { + "distribution_name": "cloud.google.com/go/vision/v2/apiv1p1beta1", "description": "Cloud Vision API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/vision/apiv1p1beta1", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/vision/v2/latest/apiv1p1beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/vmmigration/apiv1": { + "distribution_name": "cloud.google.com/go/vmmigration/apiv1", + "description": "VM Migration API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/vmmigration/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/vmwareengine/apiv1": { + "distribution_name": "cloud.google.com/go/vmwareengine/apiv1", + "description": "VMware Engine API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/vmwareengine/latest/apiv1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/vpcaccess/apiv1": { + "distribution_name": "cloud.google.com/go/vpcaccess/apiv1", + "description": "Serverless VPC Access API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/vpcaccess/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/webrisk/apiv1": { "distribution_name": "cloud.google.com/go/webrisk/apiv1", "description": "Web Risk API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/webrisk/apiv1", - "release_level": "ga" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/webrisk/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/webrisk/apiv1beta1": { "distribution_name": "cloud.google.com/go/webrisk/apiv1beta1", "description": "Web Risk API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/webrisk/apiv1beta1", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/webrisk/latest/apiv1beta1", + "release_level": "beta", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/websecurityscanner/apiv1": { "distribution_name": "cloud.google.com/go/websecurityscanner/apiv1", "description": "Web Security Scanner API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/websecurityscanner/apiv1", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/websecurityscanner/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/workflows/apiv1": { + "distribution_name": "cloud.google.com/go/workflows/apiv1", + "description": "Workflows API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/workflows/latest/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/workflows/apiv1beta": { "distribution_name": "cloud.google.com/go/workflows/apiv1beta", - "description": "", + "description": "Workflows API", + "language": "Go", + "client_library_type": "generated", + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/workflows/latest/apiv1beta", + "release_level": "beta", + "library_type": "GAPIC_AUTO" + }, + "cloud.google.com/go/workflows/executions/apiv1": { + "distribution_name": "cloud.google.com/go/workflows/executions/apiv1", + "description": "Workflow Executions API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/workflows/apiv1beta", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/workflows/latest/executions/apiv1", + "release_level": "ga", + "library_type": "GAPIC_AUTO" }, "cloud.google.com/go/workflows/executions/apiv1beta": { "distribution_name": "cloud.google.com/go/workflows/executions/apiv1beta", - "description": "", + "description": "Workflow Executions API", "language": "Go", "client_library_type": "generated", - "docs_url": "https://pkg.go.dev/cloud.google.com/go/workflows/executions/apiv1beta", - "release_level": "beta" + "docs_url": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/workflows/latest/executions/apiv1beta", + "release_level": "beta", + "library_type": "GAPIC_AUTO" } } diff --git a/vendor/cloud.google.com/go/internal/README.md b/vendor/cloud.google.com/go/internal/README.md index 8857c8f6fea..c1dc6bdff46 100644 --- a/vendor/cloud.google.com/go/internal/README.md +++ b/vendor/cloud.google.com/go/internal/README.md @@ -15,4 +15,29 @@ One day, we may want to create individual `.repo-metadata.json` files next to each package, which is the pattern followed by some other languages. External tools would then talk to pkg.go.dev or some other service to get the overall list of packages and use the `.repo-metadata.json` files to get the additional -metadata required. For now, `.repo-metadata-full.json` includes everything. \ No newline at end of file +metadata required. For now, `.repo-metadata-full.json` includes everything. + +## cloudbuild.yaml + +To kick off a build locally run from the repo root: + +```bash +gcloud builds submit --project=cloud-devrel-kokoro-resources --config=internal/cloudbuild.yaml +``` + +### Updating OwlBot SHA + +You may want to manually update the which version of the post processor will be +used -- to do this you need to update the SHA in the OwlBot lock file. Start by +running the following commands: + +```bash +docker pull gcr.io/cloud-devrel-public-resources/owlbot-go:latest +docker inspect --format='{{index .RepoDigests 0}}' gcr.io/cloud-devrel-public-resources/owlbot-go:latest +``` + +This will give you a SHA. You can use this value to update the value in +`.github/.OwlBot.lock.yaml`. + +*Note*: OwlBot will eventually open a pull request to update this value if it +discovers a new version of the container. diff --git a/vendor/cloud.google.com/go/internal/annotate.go b/vendor/cloud.google.com/go/internal/annotate.go index 6435695ba34..30d7bcf77ac 100644 --- a/vendor/cloud.google.com/go/internal/annotate.go +++ b/vendor/cloud.google.com/go/internal/annotate.go @@ -31,7 +31,8 @@ import ( // - "google.golang.org/api/googleapi".Error // If the error is not one of these types, Annotate behaves // like -// fmt.Errorf("%s: %v", msg, err) +// +// fmt.Errorf("%s: %v", msg, err) func Annotate(err error, msg string) error { if err == nil { panic("Annotate called with nil") diff --git a/vendor/cloud.google.com/go/internal/cloudbuild.yaml b/vendor/cloud.google.com/go/internal/cloudbuild.yaml new file mode 100644 index 00000000000..71281cec24a --- /dev/null +++ b/vendor/cloud.google.com/go/internal/cloudbuild.yaml @@ -0,0 +1,25 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# note: /workspace is a special directory in the docker image where all the files in this folder +# get placed on your behalf + +timeout: 7200s # 2 hours +steps: +- name: gcr.io/cloud-builders/docker + args: ['build', '-t', 'gcr.io/cloud-devrel-public-resources/owlbot-go', '-f', 'postprocessor/Dockerfile', '.'] + dir: internal + +images: +- gcr.io/cloud-devrel-public-resources/owlbot-go:latest diff --git a/vendor/cloud.google.com/go/internal/retry.go b/vendor/cloud.google.com/go/internal/retry.go index 7a7b4c2052d..2943a6d0b45 100644 --- a/vendor/cloud.google.com/go/internal/retry.go +++ b/vendor/cloud.google.com/go/internal/retry.go @@ -16,9 +16,11 @@ package internal import ( "context" + "fmt" "time" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/grpc/status" ) // Retry calls the supplied function f repeatedly according to the provided @@ -44,11 +46,40 @@ func retry(ctx context.Context, bo gax.Backoff, f func() (stop bool, err error), lastErr = err } p := bo.Pause() - if cerr := sleep(ctx, p); cerr != nil { + if ctxErr := sleep(ctx, p); ctxErr != nil { if lastErr != nil { - return Annotatef(lastErr, "retry failed with %v; last error", cerr) + return wrappedCallErr{ctxErr: ctxErr, wrappedErr: lastErr} } - return cerr + return ctxErr } } } + +// Use this error type to return an error which allows introspection of both +// the context error and the error from the service. +type wrappedCallErr struct { + ctxErr error + wrappedErr error +} + +func (e wrappedCallErr) Error() string { + return fmt.Sprintf("retry failed with %v; last error: %v", e.ctxErr, e.wrappedErr) +} + +func (e wrappedCallErr) Unwrap() error { + return e.wrappedErr +} + +// Is allows errors.Is to match the error from the call as well as context +// sentinel errors. +func (e wrappedCallErr) Is(err error) bool { + return e.ctxErr == err || e.wrappedErr == err +} + +// GRPCStatus allows the wrapped error to be used with status.FromError. +func (e wrappedCallErr) GRPCStatus() *status.Status { + if s, ok := status.FromError(e.wrappedErr); ok { + return s + } + return nil +} diff --git a/vendor/cloud.google.com/go/internal/trace/trace.go b/vendor/cloud.google.com/go/internal/trace/trace.go index 66dc391166a..c201d343e98 100644 --- a/vendor/cloud.google.com/go/internal/trace/trace.go +++ b/vendor/cloud.google.com/go/internal/trace/trace.go @@ -19,6 +19,7 @@ import ( "fmt" "go.opencensus.io/trace" + "golang.org/x/xerrors" "google.golang.org/api/googleapi" "google.golang.org/genproto/googleapis/rpc/code" "google.golang.org/grpc/status" @@ -42,7 +43,8 @@ func EndSpan(ctx context.Context, err error) { // toStatus interrogates an error and converts it to an appropriate // OpenCensus status. func toStatus(err error) trace.Status { - if err2, ok := err.(*googleapi.Error); ok { + var err2 *googleapi.Error + if ok := xerrors.As(err, &err2); ok { return trace.Status{Code: httpStatusCodeToOCCode(err2.Code), Message: err2.Message} } else if s, ok := status.FromError(err); ok { return trace.Status{Code: int32(s.Code()), Message: s.Message()} diff --git a/vendor/cloud.google.com/go/storage/CHANGES.md b/vendor/cloud.google.com/go/storage/CHANGES.md index f6d57be5085..f12da250ef3 100644 --- a/vendor/cloud.google.com/go/storage/CHANGES.md +++ b/vendor/cloud.google.com/go/storage/CHANGES.md @@ -1,5 +1,252 @@ # Changes + +## [1.28.1](https://github.com/googleapis/google-cloud-go/compare/storage/v1.28.0...storage/v1.28.1) (2022-12-02) + + +### Bug Fixes + +* **storage:** downgrade some dependencies ([7540152](https://github.com/googleapis/google-cloud-go/commit/754015236d5af7c82a75da218b71a87b9ead6eb5)) + +## [1.28.0](https://github.com/googleapis/google-cloud-go/compare/storage/v1.27.0...storage/v1.28.0) (2022-11-03) + + +### Features + +* **storage/internal:** Add routing annotations ([ce3f945](https://github.com/googleapis/google-cloud-go/commit/ce3f9458e511eca0910992763232abbcd64698f1)) +* **storage:** Add Autoclass support ([#6828](https://github.com/googleapis/google-cloud-go/issues/6828)) ([f7c7f41](https://github.com/googleapis/google-cloud-go/commit/f7c7f41e4d7fcffe05860e1114cb20f40c869da8)) + + +### Bug Fixes + +* **storage:** Fix read-write race in Writer.Write ([#6817](https://github.com/googleapis/google-cloud-go/issues/6817)) ([4766d3e](https://github.com/googleapis/google-cloud-go/commit/4766d3e1004119b93c6bd352024b5bf3404252eb)) +* **storage:** Fix request token passing for Copier.Run ([#6863](https://github.com/googleapis/google-cloud-go/issues/6863)) ([faaab06](https://github.com/googleapis/google-cloud-go/commit/faaab066d8e509dc440bcbc87391557ecee7dbf2)), refs [#6857](https://github.com/googleapis/google-cloud-go/issues/6857) + + +### Documentation + +* **storage:** Update broken links for SignURL and PostPolicy ([#6779](https://github.com/googleapis/google-cloud-go/issues/6779)) ([776138b](https://github.com/googleapis/google-cloud-go/commit/776138bc06a1e5fd45acbf8f9d36e9dc6ce31dd3)) + +## [1.27.0](https://github.com/googleapis/google-cloud-go/compare/storage/v1.26.0...storage/v1.27.0) (2022-09-22) + + +### Features + +* **storage:** Find GoogleAccessID when using impersonated creds ([#6591](https://github.com/googleapis/google-cloud-go/issues/6591)) ([a2d16a7](https://github.com/googleapis/google-cloud-go/commit/a2d16a7a778c85d13217fc67955ec5dac1da34e8)) + +## [1.26.0](https://github.com/googleapis/google-cloud-go/compare/storage/v1.25.0...storage/v1.26.0) (2022-08-29) + + +### Features + +* **storage:** export ShouldRetry ([#6370](https://github.com/googleapis/google-cloud-go/issues/6370)) ([0da9ab0](https://github.com/googleapis/google-cloud-go/commit/0da9ab0831540569dc04c0a23437b084b1564e15)), refs [#6362](https://github.com/googleapis/google-cloud-go/issues/6362) + + +### Bug Fixes + +* **storage:** allow to use age=0 in OLM conditions ([#6204](https://github.com/googleapis/google-cloud-go/issues/6204)) ([c85704f](https://github.com/googleapis/google-cloud-go/commit/c85704f4284626ce728cb48f3b130f2ce2a0165e)) + +## [1.25.0](https://github.com/googleapis/google-cloud-go/compare/storage/v1.24.0...storage/v1.25.0) (2022-08-11) + + +### Features + +* **storage/internal:** Add routing annotations ([8a8ba85](https://github.com/googleapis/google-cloud-go/commit/8a8ba85311f85701c97fd7c10f1d88b738ce423f)) +* **storage:** refactor to use transport-agnostic interface ([#6465](https://github.com/googleapis/google-cloud-go/issues/6465)) ([d03c3e1](https://github.com/googleapis/google-cloud-go/commit/d03c3e15a79fe9afa1232d9c8bd4c484a9bb927e)) + +## [1.24.0](https://github.com/googleapis/google-cloud-go/compare/storage/v1.23.0...storage/v1.24.0) (2022-07-20) + + +### Features + +* **storage:** add Custom Placement Config Dual Region Support ([#6294](https://github.com/googleapis/google-cloud-go/issues/6294)) ([5a8c607](https://github.com/googleapis/google-cloud-go/commit/5a8c607e3a9a3265887e27cb13f8943f3e3fa23d)) + +## [1.23.0](https://github.com/googleapis/google-cloud-go/compare/storage/v1.22.1...storage/v1.23.0) (2022-06-23) + + +### Features + +* **storage:** add support for OLM Prefix/Suffix ([#5929](https://github.com/googleapis/google-cloud-go/issues/5929)) ([ec21d10](https://github.com/googleapis/google-cloud-go/commit/ec21d10d6d1b01aa97a52560319775041707690d)) +* **storage:** support AbortIncompleteMultipartUpload LifecycleAction ([#5812](https://github.com/googleapis/google-cloud-go/issues/5812)) ([fdec929](https://github.com/googleapis/google-cloud-go/commit/fdec929b9da6e01dda0ab3c72544d44d6bd82bd4)), refs [#5795](https://github.com/googleapis/google-cloud-go/issues/5795) + + +### Bug Fixes + +* **storage:** allow for Age *int64 type and int64 type ([#6230](https://github.com/googleapis/google-cloud-go/issues/6230)) ([cc7acb8](https://github.com/googleapis/google-cloud-go/commit/cc7acb8bffb31828e9e96d4834a65f9728494473)) + +### [1.22.1](https://github.com/googleapis/google-cloud-go/compare/storage/v1.22.0...storage/v1.22.1) (2022-05-19) + + +### Bug Fixes + +* **storage:** bump genproto, remove deadcode ([#6059](https://github.com/googleapis/google-cloud-go/issues/6059)) ([bb10f9f](https://github.com/googleapis/google-cloud-go/commit/bb10f9faca57dc3b987e0fb601090887b3507f07)) +* **storage:** remove field that no longer exists ([#6061](https://github.com/googleapis/google-cloud-go/issues/6061)) ([ee150cf](https://github.com/googleapis/google-cloud-go/commit/ee150cfd194463ddfcb59898cfb0237e47777973)) + +## [1.22.0](https://github.com/googleapis/google-cloud-go/compare/storage/v1.21.0...storage/v1.22.0) (2022-03-31) + + +### Features + +* **storage:** allow specifying includeTrailingDelimiter ([#5617](https://github.com/googleapis/google-cloud-go/issues/5617)) ([a34503b](https://github.com/googleapis/google-cloud-go/commit/a34503bc0f0b95399285e8db66976b227e3b0072)) +* **storage:** set versionClient to module version ([55f0d92](https://github.com/googleapis/google-cloud-go/commit/55f0d92bf112f14b024b4ab0076c9875a17423c9)) + + +### Bug Fixes + +* **storage:** respect STORAGE_EMULATOR_HOST in signedURL ([#5673](https://github.com/googleapis/google-cloud-go/issues/5673)) ([1c249ae](https://github.com/googleapis/google-cloud-go/commit/1c249ae5b4980cf53fa74635943ca8bf6a96a341)) + +## [1.21.0](https://github.com/googleapis/google-cloud-go/compare/storage/v1.20.0...storage/v1.21.0) (2022-02-17) + + +### Features + +* **storage:** add better version metadata to calls ([#5507](https://github.com/googleapis/google-cloud-go/issues/5507)) ([13fe0bc](https://github.com/googleapis/google-cloud-go/commit/13fe0bc0d8acbffd46b59ab69b25449f1cbd6a88)), refs [#2749](https://github.com/googleapis/google-cloud-go/issues/2749) +* **storage:** add Writer.ChunkRetryDeadline ([#5482](https://github.com/googleapis/google-cloud-go/issues/5482)) ([498a746](https://github.com/googleapis/google-cloud-go/commit/498a746769fa43958b92af8875b927879947128e)) + +## [1.20.0](https://www.github.com/googleapis/google-cloud-go/compare/storage/v1.19.0...storage/v1.20.0) (2022-02-04) + + +### Features + +* **storage/internal:** Update definition of RewriteObjectRequest to bring to parity with JSON API support ([#5447](https://www.github.com/googleapis/google-cloud-go/issues/5447)) ([7d175ef](https://www.github.com/googleapis/google-cloud-go/commit/7d175ef12b7b3e75585427f5dd2aab4a175e92d6)) + +## [1.19.0](https://www.github.com/googleapis/google-cloud-go/compare/storage/v1.18.2...storage/v1.19.0) (2022-01-25) + + +### Features + +* **storage:** add fully configurable and idempotency-aware retry strategy ([#5384](https://www.github.com/googleapis/google-cloud-go/issues/5384), [#5185](https://www.github.com/googleapis/google-cloud-go/issues/5185), [#5170](https://www.github.com/googleapis/google-cloud-go/issues/5170), [#5223](https://www.github.com/googleapis/google-cloud-go/issues/5223), [#5221](https://www.github.com/googleapis/google-cloud-go/issues/5221), [#5193](https://www.github.com/googleapis/google-cloud-go/issues/5193), [#5159](https://www.github.com/googleapis/google-cloud-go/issues/5159), [#5165](https://www.github.com/googleapis/google-cloud-go/issues/5165), [#5166](https://www.github.com/googleapis/google-cloud-go/issues/5166), [#5210](https://www.github.com/googleapis/google-cloud-go/issues/5210), [#5172](https://www.github.com/googleapis/google-cloud-go/issues/5172), [#5314](https://www.github.com/googleapis/google-cloud-go/issues/5314)) + * This release contains changes to fully align this library's retry strategy + with best practices as described in the + Cloud Storage [docs](https://cloud.google.com/storage/docs/retry-strategy). + * The library will now retry only idempotent operations by default. This means + that for certain operations, including object upload, compose, rewrite, + update, and delete, requests will not be retried by default unless + [idempotency conditions](https://cloud.google.com/storage/docs/retry-strategy#idempotency) + for the request have been met. + * The library now has methods to configure aspects of retry policy for + API calls, including which errors are retried, the timing of the + exponential backoff, and how idempotency is taken into account. + * If you wish to re-enable retries for a non-idempotent request, use the + [RetryAlways](https://pkg.go.dev/cloud.google.com/go/storage@main#RetryAlways) + policy. + * For full details on how to configure retries, see the + [package docs](https://pkg.go.dev/cloud.google.com/go/storage@main#hdr-Retrying_failed_requests) + and the + [Cloud Storage docs](https://cloud.google.com/storage/docs/retry-strategy) +* **storage:** GenerateSignedPostPolicyV4 can use existing creds to authenticate ([#5105](https://www.github.com/googleapis/google-cloud-go/issues/5105)) ([46489f4](https://www.github.com/googleapis/google-cloud-go/commit/46489f4c8a634068a3e7cf2fd5e5ca11b555c0a8)) +* **storage:** post policy can be signed with a fn that takes raw bytes ([#5079](https://www.github.com/googleapis/google-cloud-go/issues/5079)) ([25d1278](https://www.github.com/googleapis/google-cloud-go/commit/25d1278cab539fbfdd8563ed6b297e30d3fe555c)) +* **storage:** add rpo (turbo replication) support ([#5003](https://www.github.com/googleapis/google-cloud-go/issues/5003)) ([3bd5995](https://www.github.com/googleapis/google-cloud-go/commit/3bd59958e0c06d2655b67fcb5410668db3c52af0)) + +### Bug Fixes + +* **storage:** fix nil check in gRPC Reader ([#5376](https://www.github.com/googleapis/google-cloud-go/issues/5376)) ([5e7d722](https://www.github.com/googleapis/google-cloud-go/commit/5e7d722d18a62b28ba98169b3bdbb49401377264)) + +### [1.18.2](https://www.github.com/googleapis/google-cloud-go/compare/storage/v1.18.1...storage/v1.18.2) (2021-10-18) + + +### Bug Fixes + +* **storage:** upgrade genproto ([#4993](https://www.github.com/googleapis/google-cloud-go/issues/4993)) ([5ca462d](https://www.github.com/googleapis/google-cloud-go/commit/5ca462d99fe851b7cddfd70108798e2fa959bdfd)), refs [#4991](https://www.github.com/googleapis/google-cloud-go/issues/4991) + +### [1.18.1](https://www.github.com/googleapis/google-cloud-go/compare/storage/v1.18.0...storage/v1.18.1) (2021-10-14) + + +### Bug Fixes + +* **storage:** don't assume auth from a client option ([#4982](https://www.github.com/googleapis/google-cloud-go/issues/4982)) ([e17334d](https://www.github.com/googleapis/google-cloud-go/commit/e17334d1fe7645d89d14ae7148313498b984dfbb)) + +## [1.18.0](https://www.github.com/googleapis/google-cloud-go/compare/storage/v1.17.0...storage/v1.18.0) (2021-10-11) + + +### Features + +* **storage:** returned wrapped error for timeouts ([#4802](https://www.github.com/googleapis/google-cloud-go/issues/4802)) ([0e102a3](https://www.github.com/googleapis/google-cloud-go/commit/0e102a385dc67a06f6b444b3a93e6998428529be)), refs [#4197](https://www.github.com/googleapis/google-cloud-go/issues/4197) +* **storage:** SignedUrl can use existing creds to authenticate ([#4604](https://www.github.com/googleapis/google-cloud-go/issues/4604)) ([b824c89](https://www.github.com/googleapis/google-cloud-go/commit/b824c897e6941270747b612f6d36a8d6ae081315)) + + +### Bug Fixes + +* **storage:** update PAP to use inherited instead of unspecified ([#4909](https://www.github.com/googleapis/google-cloud-go/issues/4909)) ([dac26b1](https://www.github.com/googleapis/google-cloud-go/commit/dac26b1af2f2972f12775341173bcc5f982438b8)) + +## [1.17.0](https://www.github.com/googleapis/google-cloud-go/compare/storage/v1.16.1...storage/v1.17.0) (2021-09-28) + + +### Features + +* **storage:** add projectNumber field to bucketAttrs. ([#4805](https://www.github.com/googleapis/google-cloud-go/issues/4805)) ([07343af](https://www.github.com/googleapis/google-cloud-go/commit/07343afc15085b164cc41d202d13f9d46f5c0d02)) + + +### Bug Fixes + +* **storage:** align retry idempotency (part 1) ([#4715](https://www.github.com/googleapis/google-cloud-go/issues/4715)) ([ffa903e](https://www.github.com/googleapis/google-cloud-go/commit/ffa903eeec61aa3869e5220e2f09371127b5c393)) + +### [1.16.1](https://www.github.com/googleapis/google-cloud-go/compare/storage/v1.16.0...storage/v1.16.1) (2021-08-30) + + +### Bug Fixes + +* **storage/internal:** Update encryption_key fields to "bytes" type. fix: Improve date/times and field name clarity in lifecycle conditions. ([a52baa4](https://www.github.com/googleapis/google-cloud-go/commit/a52baa456ed8513ec492c4b573c191eb61468758)) +* **storage:** accept emulator env var without scheme ([#4616](https://www.github.com/googleapis/google-cloud-go/issues/4616)) ([5f8cbb9](https://www.github.com/googleapis/google-cloud-go/commit/5f8cbb98070109e2a34409ac775ed63b94d37efd)) +* **storage:** preserve supplied endpoint's scheme ([#4609](https://www.github.com/googleapis/google-cloud-go/issues/4609)) ([ee2756f](https://www.github.com/googleapis/google-cloud-go/commit/ee2756fb0a335d591464a770c9fa4f8fe0ba2e01)) +* **storage:** remove unnecessary variable ([#4608](https://www.github.com/googleapis/google-cloud-go/issues/4608)) ([27fc784](https://www.github.com/googleapis/google-cloud-go/commit/27fc78456fb251652bdf5cdb493734a7e1e643e1)) +* **storage:** retry LockRetentionPolicy ([#4439](https://www.github.com/googleapis/google-cloud-go/issues/4439)) ([09879ea](https://www.github.com/googleapis/google-cloud-go/commit/09879ea80cb67f9bfd8fc9384b0fda335567cba9)), refs [#4437](https://www.github.com/googleapis/google-cloud-go/issues/4437) +* **storage:** revise Reader to send XML preconditions ([#4479](https://www.github.com/googleapis/google-cloud-go/issues/4479)) ([e36b29a](https://www.github.com/googleapis/google-cloud-go/commit/e36b29a3d43bce5c1c044f7daf6e1db00b0a49e0)), refs [#4470](https://www.github.com/googleapis/google-cloud-go/issues/4470) + +## [1.16.0](https://www.github.com/googleapis/google-cloud-go/compare/storage/v1.15.0...storage/v1.16.0) (2021-06-28) + + +### Features + +* **storage:** support PublicAccessPrevention ([#3608](https://www.github.com/googleapis/google-cloud-go/issues/3608)) ([99bc782](https://www.github.com/googleapis/google-cloud-go/commit/99bc782fb50a47602b45278384ef5d5b5da9263b)), refs [#3203](https://www.github.com/googleapis/google-cloud-go/issues/3203) + + +### Bug Fixes + +* **storage:** fix Writer.ChunkSize validation ([#4255](https://www.github.com/googleapis/google-cloud-go/issues/4255)) ([69c2e9d](https://www.github.com/googleapis/google-cloud-go/commit/69c2e9dc6303e1a004d3104a8178532fa738e742)), refs [#4167](https://www.github.com/googleapis/google-cloud-go/issues/4167) +* **storage:** try to reopen for failed Reads ([#4226](https://www.github.com/googleapis/google-cloud-go/issues/4226)) ([564102b](https://www.github.com/googleapis/google-cloud-go/commit/564102b335dbfb558bec8af883e5f898efb5dd10)), refs [#3040](https://www.github.com/googleapis/google-cloud-go/issues/3040) + +## [1.15.0](https://www.github.com/googleapis/google-cloud-go/compare/storage/v1.13.0...storage/v1.15.0) (2021-04-21) + + +### Features + +* **transport** Bump dependency on google.golang.org/api to pick up HTTP/2 + config updates (see [googleapis/google-api-go-client#882](https://github.com/googleapis/google-api-go-client/pull/882)). + +### Bug Fixes + +* **storage:** retry io.ErrUnexpectedEOF ([#3957](https://www.github.com/googleapis/google-cloud-go/issues/3957)) ([f6590cd](https://www.github.com/googleapis/google-cloud-go/commit/f6590cdc26c8479be5df48949fa59f879e0c24fc)) + + +## v1.14.0 + +- Updates to various dependencies. + +## [1.13.0](https://www.github.com/googleapis/google-cloud-go/compare/storage/v1.12.0...v1.13.0) (2021-02-03) + + +### Features + +* **storage:** add missing StorageClass in BucketAttrsToUpdate ([#3038](https://www.github.com/googleapis/google-cloud-go/issues/3038)) ([2fa1b72](https://www.github.com/googleapis/google-cloud-go/commit/2fa1b727f8a7b20aa62fe0990530744f6c109be0)) +* **storage:** add projection parameter for BucketHandle.Objects() ([#3549](https://www.github.com/googleapis/google-cloud-go/issues/3549)) ([9b9c3dc](https://www.github.com/googleapis/google-cloud-go/commit/9b9c3dce3ee10af5b6c4d070821bf47a861efd5b)) + + +### Bug Fixes + +* **storage:** fix endpoint selection logic ([#3172](https://www.github.com/googleapis/google-cloud-go/issues/3172)) ([99edf0d](https://www.github.com/googleapis/google-cloud-go/commit/99edf0d211a9e617f2586fbc83b6f9630da3c537)) + +## v1.12.0 +- V4 signed URL fixes: + - Fix encoding of spaces in query parameters. + - Add fields that were missing from PostPolicyV4 policy conditions. +- Fix Query to correctly list prefixes as well as objects when SetAttrSelection + is used. + +## v1.11.0 +- Add support for CustomTime and NoncurrentTime object lifecycle management + features. + ## v1.10.0 - Bump dependency on google.golang.org/api to capture changes to retry logic which will make retries on writes more resilient. diff --git a/vendor/cloud.google.com/go/storage/README.md b/vendor/cloud.google.com/go/storage/README.md index a2253c4bb5a..b2f411210ca 100644 --- a/vendor/cloud.google.com/go/storage/README.md +++ b/vendor/cloud.google.com/go/storage/README.md @@ -1,9 +1,9 @@ -## Cloud Storage [![GoDoc](https://godoc.org/cloud.google.com/go/storage?status.svg)](https://godoc.org/cloud.google.com/go/storage) +## Cloud Storage [![Go Reference](https://pkg.go.dev/badge/cloud.google.com/go/storage.svg)](https://pkg.go.dev/cloud.google.com/go/storage) - [About Cloud Storage](https://cloud.google.com/storage/) - [API documentation](https://cloud.google.com/storage/docs) -- [Go client documentation](https://godoc.org/cloud.google.com/go/storage) -- [Complete sample programs](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/storage) +- [Go client documentation](https://cloud.google.com/go/docs/reference/cloud.google.com/go/storage/latest) +- [Complete sample programs](https://github.com/GoogleCloudPlatform/golang-samples/tree/main/storage) ### Example Usage @@ -25,8 +25,8 @@ if err != nil { log.Fatal(err) } defer rc.Close() -body, err := ioutil.ReadAll(rc) +body, err := io.ReadAll(rc) if err != nil { log.Fatal(err) } -``` \ No newline at end of file +``` diff --git a/vendor/cloud.google.com/go/storage/acl.go b/vendor/cloud.google.com/go/storage/acl.go index 7855d110ad4..e0ab60073c2 100644 --- a/vendor/cloud.google.com/go/storage/acl.go +++ b/vendor/cloud.google.com/go/storage/acl.go @@ -20,7 +20,7 @@ import ( "reflect" "cloud.google.com/go/internal/trace" - "google.golang.org/api/googleapi" + storagepb "cloud.google.com/go/storage/internal/apiv2/stubs" raw "google.golang.org/api/storage/v1" ) @@ -66,12 +66,15 @@ type ProjectTeam struct { } // ACLHandle provides operations on an access control list for a Google Cloud Storage bucket or object. +// ACLHandle on an object operates on the latest generation of that object by default. +// Selecting a specific generation of an object is not currently supported by the client. type ACLHandle struct { c *Client bucket string object string isDefault bool userProject string // for requester-pays buckets + retry *retryConfig } // Delete permanently deletes the ACL entry for the given entity. @@ -117,114 +120,46 @@ func (a *ACLHandle) List(ctx context.Context) (rules []ACLRule, err error) { } func (a *ACLHandle) bucketDefaultList(ctx context.Context) ([]ACLRule, error) { - var acls *raw.ObjectAccessControls - var err error - err = runWithRetry(ctx, func() error { - req := a.c.raw.DefaultObjectAccessControls.List(a.bucket) - a.configureCall(ctx, req) - acls, err = req.Do() - return err - }) - if err != nil { - return nil, err - } - return toObjectACLRules(acls.Items), nil + opts := makeStorageOpts(true, a.retry, a.userProject) + return a.c.tc.ListDefaultObjectACLs(ctx, a.bucket, opts...) } func (a *ACLHandle) bucketDefaultDelete(ctx context.Context, entity ACLEntity) error { - return runWithRetry(ctx, func() error { - req := a.c.raw.DefaultObjectAccessControls.Delete(a.bucket, string(entity)) - a.configureCall(ctx, req) - return req.Do() - }) + opts := makeStorageOpts(false, a.retry, a.userProject) + return a.c.tc.DeleteDefaultObjectACL(ctx, a.bucket, entity, opts...) } func (a *ACLHandle) bucketList(ctx context.Context) ([]ACLRule, error) { - var acls *raw.BucketAccessControls - var err error - err = runWithRetry(ctx, func() error { - req := a.c.raw.BucketAccessControls.List(a.bucket) - a.configureCall(ctx, req) - acls, err = req.Do() - return err - }) - if err != nil { - return nil, err - } - return toBucketACLRules(acls.Items), nil + opts := makeStorageOpts(true, a.retry, a.userProject) + return a.c.tc.ListBucketACLs(ctx, a.bucket, opts...) } func (a *ACLHandle) bucketSet(ctx context.Context, entity ACLEntity, role ACLRole) error { - acl := &raw.BucketAccessControl{ - Bucket: a.bucket, - Entity: string(entity), - Role: string(role), - } - err := runWithRetry(ctx, func() error { - req := a.c.raw.BucketAccessControls.Update(a.bucket, string(entity), acl) - a.configureCall(ctx, req) - _, err := req.Do() - return err - }) - if err != nil { - return err - } - return nil + opts := makeStorageOpts(false, a.retry, a.userProject) + return a.c.tc.UpdateBucketACL(ctx, a.bucket, entity, role, opts...) } func (a *ACLHandle) bucketDelete(ctx context.Context, entity ACLEntity) error { - return runWithRetry(ctx, func() error { - req := a.c.raw.BucketAccessControls.Delete(a.bucket, string(entity)) - a.configureCall(ctx, req) - return req.Do() - }) + opts := makeStorageOpts(false, a.retry, a.userProject) + return a.c.tc.DeleteBucketACL(ctx, a.bucket, entity, opts...) } func (a *ACLHandle) objectList(ctx context.Context) ([]ACLRule, error) { - var acls *raw.ObjectAccessControls - var err error - err = runWithRetry(ctx, func() error { - req := a.c.raw.ObjectAccessControls.List(a.bucket, a.object) - a.configureCall(ctx, req) - acls, err = req.Do() - return err - }) - if err != nil { - return nil, err - } - return toObjectACLRules(acls.Items), nil + opts := makeStorageOpts(true, a.retry, a.userProject) + return a.c.tc.ListObjectACLs(ctx, a.bucket, a.object, opts...) } func (a *ACLHandle) objectSet(ctx context.Context, entity ACLEntity, role ACLRole, isBucketDefault bool) error { - type setRequest interface { - Do(opts ...googleapi.CallOption) (*raw.ObjectAccessControl, error) - Header() http.Header - } - - acl := &raw.ObjectAccessControl{ - Bucket: a.bucket, - Entity: string(entity), - Role: string(role), - } - var req setRequest + opts := makeStorageOpts(false, a.retry, a.userProject) if isBucketDefault { - req = a.c.raw.DefaultObjectAccessControls.Update(a.bucket, string(entity), acl) - } else { - req = a.c.raw.ObjectAccessControls.Update(a.bucket, a.object, string(entity), acl) + return a.c.tc.UpdateDefaultObjectACL(ctx, a.bucket, entity, role, opts...) } - a.configureCall(ctx, req) - return runWithRetry(ctx, func() error { - _, err := req.Do() - return err - }) + return a.c.tc.UpdateObjectACL(ctx, a.bucket, a.object, entity, role, opts...) } func (a *ACLHandle) objectDelete(ctx context.Context, entity ACLEntity) error { - return runWithRetry(ctx, func() error { - req := a.c.raw.ObjectAccessControls.Delete(a.bucket, a.object, string(entity)) - a.configureCall(ctx, req) - return req.Do() - }) + opts := makeStorageOpts(false, a.retry, a.userProject) + return a.c.tc.DeleteObjectACL(ctx, a.bucket, a.object, entity, opts...) } func (a *ACLHandle) configureCall(ctx context.Context, call interface{ Header() http.Header }) { @@ -244,6 +179,14 @@ func toObjectACLRules(items []*raw.ObjectAccessControl) []ACLRule { return rs } +func toObjectACLRulesFromProto(items []*storagepb.ObjectAccessControl) []ACLRule { + var rs []ACLRule + for _, item := range items { + rs = append(rs, toObjectACLRuleFromProto(item)) + } + return rs +} + func toBucketACLRules(items []*raw.BucketAccessControl) []ACLRule { var rs []ACLRule for _, item := range items { @@ -252,6 +195,14 @@ func toBucketACLRules(items []*raw.BucketAccessControl) []ACLRule { return rs } +func toBucketACLRulesFromProto(items []*storagepb.BucketAccessControl) []ACLRule { + var rs []ACLRule + for _, item := range items { + rs = append(rs, toBucketACLRuleFromProto(item)) + } + return rs +} + func toObjectACLRule(a *raw.ObjectAccessControl) ACLRule { return ACLRule{ Entity: ACLEntity(a.Entity), @@ -263,6 +214,17 @@ func toObjectACLRule(a *raw.ObjectAccessControl) ACLRule { } } +func toObjectACLRuleFromProto(a *storagepb.ObjectAccessControl) ACLRule { + return ACLRule{ + Entity: ACLEntity(a.GetEntity()), + EntityID: a.GetEntityId(), + Role: ACLRole(a.GetRole()), + Domain: a.GetDomain(), + Email: a.GetEmail(), + ProjectTeam: toProjectTeamFromProto(a.GetProjectTeam()), + } +} + func toBucketACLRule(a *raw.BucketAccessControl) ACLRule { return ACLRule{ Entity: ACLEntity(a.Entity), @@ -274,6 +236,17 @@ func toBucketACLRule(a *raw.BucketAccessControl) ACLRule { } } +func toBucketACLRuleFromProto(a *storagepb.BucketAccessControl) ACLRule { + return ACLRule{ + Entity: ACLEntity(a.GetEntity()), + EntityID: a.GetEntityId(), + Role: ACLRole(a.GetRole()), + Domain: a.GetDomain(), + Email: a.GetEmail(), + ProjectTeam: toProjectTeamFromProto(a.GetProjectTeam()), + } +} + func toRawObjectACL(rules []ACLRule) []*raw.ObjectAccessControl { if len(rules) == 0 { return nil @@ -285,6 +258,17 @@ func toRawObjectACL(rules []ACLRule) []*raw.ObjectAccessControl { return r } +func toProtoObjectACL(rules []ACLRule) []*storagepb.ObjectAccessControl { + if len(rules) == 0 { + return nil + } + r := make([]*storagepb.ObjectAccessControl, 0, len(rules)) + for _, rule := range rules { + r = append(r, rule.toProtoObjectAccessControl("")) // bucket name unnecessary + } + return r +} + func toRawBucketACL(rules []ACLRule) []*raw.BucketAccessControl { if len(rules) == 0 { return nil @@ -296,6 +280,17 @@ func toRawBucketACL(rules []ACLRule) []*raw.BucketAccessControl { return r } +func toProtoBucketACL(rules []ACLRule) []*storagepb.BucketAccessControl { + if len(rules) == 0 { + return nil + } + r := make([]*storagepb.BucketAccessControl, 0, len(rules)) + for _, rule := range rules { + r = append(r, rule.toProtoBucketAccessControl()) + } + return r +} + func (r ACLRule) toRawBucketAccessControl(bucket string) *raw.BucketAccessControl { return &raw.BucketAccessControl{ Bucket: bucket, @@ -314,6 +309,22 @@ func (r ACLRule) toRawObjectAccessControl(bucket string) *raw.ObjectAccessContro } } +func (r ACLRule) toProtoObjectAccessControl(bucket string) *storagepb.ObjectAccessControl { + return &storagepb.ObjectAccessControl{ + Entity: string(r.Entity), + Role: string(r.Role), + // The other fields are not settable. + } +} + +func (r ACLRule) toProtoBucketAccessControl() *storagepb.BucketAccessControl { + return &storagepb.BucketAccessControl{ + Entity: string(r.Entity), + Role: string(r.Role), + // The other fields are not settable. + } +} + func toBucketProjectTeam(p *raw.BucketAccessControlProjectTeam) *ProjectTeam { if p == nil { return nil @@ -324,6 +335,16 @@ func toBucketProjectTeam(p *raw.BucketAccessControlProjectTeam) *ProjectTeam { } } +func toProjectTeamFromProto(p *storagepb.ProjectTeam) *ProjectTeam { + if p == nil { + return nil + } + return &ProjectTeam{ + ProjectNumber: p.GetProjectNumber(), + Team: p.GetTeam(), + } +} + func toObjectProjectTeam(p *raw.ObjectAccessControlProjectTeam) *ProjectTeam { if p == nil { return nil diff --git a/vendor/cloud.google.com/go/storage/bucket.go b/vendor/cloud.google.com/go/storage/bucket.go index 478482645fa..28a73b8d995 100644 --- a/vendor/cloud.google.com/go/storage/bucket.go +++ b/vendor/cloud.google.com/go/storage/bucket.go @@ -16,16 +16,25 @@ package storage import ( "context" + "encoding/base64" + "encoding/json" + "errors" "fmt" - "net/http" "reflect" + "strings" "time" + "cloud.google.com/go/compute/metadata" "cloud.google.com/go/internal/optional" "cloud.google.com/go/internal/trace" + storagepb "cloud.google.com/go/storage/internal/apiv2/stubs" "google.golang.org/api/googleapi" + "google.golang.org/api/iamcredentials/v1" "google.golang.org/api/iterator" + "google.golang.org/api/option" raw "google.golang.org/api/storage/v1" + dpb "google.golang.org/genproto/googleapis/type/date" + "google.golang.org/protobuf/proto" ) // BucketHandle provides operations on a Google Cloud Storage bucket. @@ -37,6 +46,7 @@ type BucketHandle struct { defaultObjectACL ACLHandle conds *BucketConditions userProject string // project for Requester Pays buckets + retry *retryConfig } // Bucket returns a BucketHandle, which provides operations on the named bucket. @@ -45,20 +55,25 @@ type BucketHandle struct { // The supplied name must contain only lowercase letters, numbers, dashes, // underscores, and dots. The full specification for valid bucket names can be // found at: -// https://cloud.google.com/storage/docs/bucket-naming +// +// https://cloud.google.com/storage/docs/bucket-naming func (c *Client) Bucket(name string) *BucketHandle { + retry := c.retry.clone() return &BucketHandle{ c: c, name: name, acl: ACLHandle{ c: c, bucket: name, + retry: retry, }, defaultObjectACL: ACLHandle{ c: c, bucket: name, isDefault: true, + retry: retry, }, + retry: retry, } } @@ -68,27 +83,11 @@ func (b *BucketHandle) Create(ctx context.Context, projectID string, attrs *Buck ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Create") defer func() { trace.EndSpan(ctx, err) }() - var bkt *raw.Bucket - if attrs != nil { - bkt = attrs.toRawBucket() - } else { - bkt = &raw.Bucket{} - } - bkt.Name = b.name - // If there is lifecycle information but no location, explicitly set - // the location. This is a GCS quirk/bug. - if bkt.Location == "" && bkt.Lifecycle != nil { - bkt.Location = "US" - } - req := b.c.raw.Buckets.Insert(projectID, bkt) - setClientHeader(req.Header()) - if attrs != nil && attrs.PredefinedACL != "" { - req.PredefinedAcl(attrs.PredefinedACL) - } - if attrs != nil && attrs.PredefinedDefaultObjectACL != "" { - req.PredefinedDefaultObjectAcl(attrs.PredefinedDefaultObjectACL) + o := makeStorageOpts(true, b.retry, b.userProject) + if _, err := b.c.tc.CreateBucket(ctx, projectID, b.name, attrs, o...); err != nil { + return err } - return runWithRetry(ctx, func() error { _, err := req.Context(ctx).Do(); return err }) + return nil } // Delete deletes the Bucket. @@ -96,23 +95,8 @@ func (b *BucketHandle) Delete(ctx context.Context) (err error) { ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Delete") defer func() { trace.EndSpan(ctx, err) }() - req, err := b.newDeleteCall() - if err != nil { - return err - } - return runWithRetry(ctx, func() error { return req.Context(ctx).Do() }) -} - -func (b *BucketHandle) newDeleteCall() (*raw.BucketsDeleteCall, error) { - req := b.c.raw.Buckets.Delete(b.name) - setClientHeader(req.Header()) - if err := applyBucketConds("BucketHandle.Delete", b.conds, req); err != nil { - return nil, err - } - if b.userProject != "" { - req.UserProject(b.userProject) - } - return req, nil + o := makeStorageOpts(true, b.retry, b.userProject) + return b.c.tc.DeleteBucket(ctx, b.name, b.conds, o...) } // ACL returns an ACLHandle, which provides access to the bucket's access control list. @@ -130,12 +114,15 @@ func (b *BucketHandle) DefaultObjectACL() *ACLHandle { } // Object returns an ObjectHandle, which provides operations on the named object. -// This call does not perform any network operations. +// This call does not perform any network operations such as fetching the object or verifying its existence. +// Use methods on ObjectHandle to perform network operations. // // name must consist entirely of valid UTF-8-encoded runes. The full specification // for valid object names can be found at: -// https://cloud.google.com/storage/docs/bucket-naming +// +// https://cloud.google.com/storage/docs/naming-objects func (b *BucketHandle) Object(name string) *ObjectHandle { + retry := b.retry.clone() return &ObjectHandle{ c: b.c, bucket: b.name, @@ -145,9 +132,11 @@ func (b *BucketHandle) Object(name string) *ObjectHandle { bucket: b.name, object: name, userProject: b.userProject, + retry: retry, }, gen: -1, userProject: b.userProject, + retry: retry, } } @@ -156,34 +145,8 @@ func (b *BucketHandle) Attrs(ctx context.Context) (attrs *BucketAttrs, err error ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Attrs") defer func() { trace.EndSpan(ctx, err) }() - req, err := b.newGetCall() - if err != nil { - return nil, err - } - var resp *raw.Bucket - err = runWithRetry(ctx, func() error { - resp, err = req.Context(ctx).Do() - return err - }) - if e, ok := err.(*googleapi.Error); ok && e.Code == http.StatusNotFound { - return nil, ErrBucketNotExist - } - if err != nil { - return nil, err - } - return newBucket(resp) -} - -func (b *BucketHandle) newGetCall() (*raw.BucketsGetCall, error) { - req := b.c.raw.Buckets.Get(b.name).Projection("full") - setClientHeader(req.Header()) - if err := applyBucketConds("BucketHandle.Attrs", b.conds, req); err != nil { - return nil, err - } - if b.userProject != "" { - req.UserProject(b.userProject) - } - return req, nil + o := makeStorageOpts(true, b.retry, b.userProject) + return b.c.tc.GetBucket(ctx, b.name, b.conds, o...) } // Update updates a bucket's attributes. @@ -191,35 +154,165 @@ func (b *BucketHandle) Update(ctx context.Context, uattrs BucketAttrsToUpdate) ( ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Create") defer func() { trace.EndSpan(ctx, err) }() - req, err := b.newPatchCall(&uattrs) - if err != nil { - return nil, err + isIdempotent := b.conds != nil && b.conds.MetagenerationMatch != 0 + o := makeStorageOpts(isIdempotent, b.retry, b.userProject) + return b.c.tc.UpdateBucket(ctx, b.name, &uattrs, b.conds, o...) +} + +// SignedURL returns a URL for the specified object. Signed URLs allow anyone +// access to a restricted resource for a limited time without needing a Google +// account or signing in. +// For more information about signed URLs, see "[Overview of access control]." +// +// This method requires the Method and Expires fields in the specified +// SignedURLOptions to be non-nil. You may need to set the GoogleAccessID and +// PrivateKey fields in some cases. Read more on the [automatic detection of credentials] +// for this method. +// +// [Overview of access control]: https://cloud.google.com/storage/docs/accesscontrol#signed_urls_query_string_authentication +// [automatic detection of credentials]: https://pkg.go.dev/cloud.google.com/go/storage#hdr-Credential_requirements_for_signing +func (b *BucketHandle) SignedURL(object string, opts *SignedURLOptions) (string, error) { + if opts.GoogleAccessID != "" && (opts.SignBytes != nil || len(opts.PrivateKey) > 0) { + return SignedURL(b.name, object, opts) } - if uattrs.PredefinedACL != "" { - req.PredefinedAcl(uattrs.PredefinedACL) + // Make a copy of opts so we don't modify the pointer parameter. + newopts := opts.clone() + + if newopts.GoogleAccessID == "" { + id, err := b.detectDefaultGoogleAccessID() + if err != nil { + return "", err + } + newopts.GoogleAccessID = id + } + if newopts.SignBytes == nil && len(newopts.PrivateKey) == 0 { + if b.c.creds != nil && len(b.c.creds.JSON) > 0 { + var sa struct { + PrivateKey string `json:"private_key"` + } + err := json.Unmarshal(b.c.creds.JSON, &sa) + if err == nil && sa.PrivateKey != "" { + newopts.PrivateKey = []byte(sa.PrivateKey) + } + } + + // Don't error out if we can't unmarshal the private key from the client, + // fallback to the default sign function for the service account. + if len(newopts.PrivateKey) == 0 { + newopts.SignBytes = b.defaultSignBytesFunc(newopts.GoogleAccessID) + } } - if uattrs.PredefinedDefaultObjectACL != "" { - req.PredefinedDefaultObjectAcl(uattrs.PredefinedDefaultObjectACL) + return SignedURL(b.name, object, newopts) +} + +// GenerateSignedPostPolicyV4 generates a PostPolicyV4 value from bucket, object and opts. +// The generated URL and fields will then allow an unauthenticated client to perform multipart uploads. +// +// This method requires the Expires field in the specified PostPolicyV4Options +// to be non-nil. You may need to set the GoogleAccessID and PrivateKey fields +// in some cases. Read more on the [automatic detection of credentials] for this method. +// +// [automatic detection of credentials]: https://pkg.go.dev/cloud.google.com/go/storage#hdr-Credential_requirements_for_signing +func (b *BucketHandle) GenerateSignedPostPolicyV4(object string, opts *PostPolicyV4Options) (*PostPolicyV4, error) { + if opts.GoogleAccessID != "" && (opts.SignRawBytes != nil || opts.SignBytes != nil || len(opts.PrivateKey) > 0) { + return GenerateSignedPostPolicyV4(b.name, object, opts) } - // TODO(jba): retry iff metagen is set? - rb, err := req.Context(ctx).Do() - if err != nil { - return nil, err + // Make a copy of opts so we don't modify the pointer parameter. + newopts := opts.clone() + + if newopts.GoogleAccessID == "" { + id, err := b.detectDefaultGoogleAccessID() + if err != nil { + return nil, err + } + newopts.GoogleAccessID = id + } + if newopts.SignBytes == nil && newopts.SignRawBytes == nil && len(newopts.PrivateKey) == 0 { + if b.c.creds != nil && len(b.c.creds.JSON) > 0 { + var sa struct { + PrivateKey string `json:"private_key"` + } + err := json.Unmarshal(b.c.creds.JSON, &sa) + if err == nil && sa.PrivateKey != "" { + newopts.PrivateKey = []byte(sa.PrivateKey) + } + } + + // Don't error out if we can't unmarshal the private key from the client, + // fallback to the default sign function for the service account. + if len(newopts.PrivateKey) == 0 { + newopts.SignRawBytes = b.defaultSignBytesFunc(newopts.GoogleAccessID) + } } - return newBucket(rb) + return GenerateSignedPostPolicyV4(b.name, object, newopts) } -func (b *BucketHandle) newPatchCall(uattrs *BucketAttrsToUpdate) (*raw.BucketsPatchCall, error) { - rb := uattrs.toRawBucket() - req := b.c.raw.Buckets.Patch(b.name, rb).Projection("full") - setClientHeader(req.Header()) - if err := applyBucketConds("BucketHandle.Update", b.conds, req); err != nil { - return nil, err +func (b *BucketHandle) detectDefaultGoogleAccessID() (string, error) { + returnErr := errors.New("no credentials found on client and not on GCE (Google Compute Engine)") + + if b.c.creds != nil && len(b.c.creds.JSON) > 0 { + var sa struct { + ClientEmail string `json:"client_email"` + SAImpersonationURL string `json:"service_account_impersonation_url"` + CredType string `json:"type"` + } + + err := json.Unmarshal(b.c.creds.JSON, &sa) + if err != nil { + returnErr = err + } else if sa.CredType == "impersonated_service_account" { + start, end := strings.LastIndex(sa.SAImpersonationURL, "/"), strings.LastIndex(sa.SAImpersonationURL, ":") + + if end <= start { + returnErr = errors.New("error parsing impersonated service account credentials") + } else { + return sa.SAImpersonationURL[start+1 : end], nil + } + } else if sa.CredType == "service_account" && sa.ClientEmail != "" { + return sa.ClientEmail, nil + } else { + returnErr = errors.New("unable to parse credentials; only service_account and impersonated_service_account credentials are supported") + } } - if b.userProject != "" { - req.UserProject(b.userProject) + + // Don't error out if we can't unmarshal, fallback to GCE check. + if metadata.OnGCE() { + email, err := metadata.Email("default") + if err == nil && email != "" { + return email, nil + } else if err != nil { + returnErr = err + } else { + returnErr = errors.New("empty email from GCE metadata service") + } + + } + return "", fmt.Errorf("storage: unable to detect default GoogleAccessID: %w. Please provide the GoogleAccessID or use a supported means for autodetecting it (see https://pkg.go.dev/cloud.google.com/go/storage#hdr-Credential_requirements_for_[BucketHandle.SignedURL]_and_[BucketHandle.GenerateSignedPostPolicyV4])", returnErr) +} + +func (b *BucketHandle) defaultSignBytesFunc(email string) func([]byte) ([]byte, error) { + return func(in []byte) ([]byte, error) { + ctx := context.Background() + + // It's ok to recreate this service per call since we pass in the http client, + // circumventing the cost of recreating the auth/transport layer + svc, err := iamcredentials.NewService(ctx, option.WithHTTPClient(b.c.hc)) + if err != nil { + return nil, fmt.Errorf("unable to create iamcredentials client: %w", err) + } + + resp, err := svc.Projects.ServiceAccounts.SignBlob(fmt.Sprintf("projects/-/serviceAccounts/%s", email), &iamcredentials.SignBlobRequest{ + Payload: base64.StdEncoding.EncodeToString(in), + }).Do() + if err != nil { + return nil, fmt.Errorf("unable to sign bytes: %w", err) + } + out, err := base64.StdEncoding.DecodeString(resp.SignedBlob) + if err != nil { + return nil, fmt.Errorf("unable to base64 decode response: %w", err) + } + return out, nil } - return req, nil } // BucketAttrs represents the metadata for a Google Cloud Storage bucket. @@ -244,6 +337,13 @@ type BucketAttrs struct { // for more information. UniformBucketLevelAccess UniformBucketLevelAccess + // PublicAccessPrevention is the setting for the bucket's + // PublicAccessPrevention policy, which can be used to prevent public access + // of data in the bucket. See + // https://cloud.google.com/storage/docs/public-access-prevention for more + // information. + PublicAccessPrevention PublicAccessPrevention + // DefaultObjectACL is the list of access controls to // apply to new objects when no object ACL is provided. DefaultObjectACL []ACLRule @@ -267,8 +367,13 @@ type BucketAttrs struct { PredefinedDefaultObjectACL string // Location is the location of the bucket. It defaults to "US". + // If specifying a dual-region, CustomPlacementConfig should be set in conjunction. Location string + // The bucket's custom placement configuration that holds a list of + // regional locations for custom dual regions. + CustomPlacementConfig *CustomPlacementConfig + // MetaGeneration is the metadata generation of the bucket. // This field is read-only. MetaGeneration int64 @@ -329,6 +434,21 @@ type BucketAttrs struct { // Typical values are "multi-region", "region" and "dual-region". // This field is read-only. LocationType string + + // The project number of the project the bucket belongs to. + // This field is read-only. + ProjectNumber uint64 + + // RPO configures the Recovery Point Objective (RPO) policy of the bucket. + // Set to RPOAsyncTurbo to turn on Turbo Replication for a bucket. + // See https://cloud.google.com/storage/docs/managing-turbo-replication for + // more information. + RPO RPO + + // Autoclass holds the bucket's autoclass configuration. If enabled, + // allows for the automatic selection of the best storage class + // based on object access patterns. + Autoclass *Autoclass } // BucketPolicyOnly is an alias for UniformBucketLevelAccess. @@ -353,6 +473,47 @@ type UniformBucketLevelAccess struct { LockedTime time.Time } +// PublicAccessPrevention configures the Public Access Prevention feature, which +// can be used to disallow public access to any data in a bucket. See +// https://cloud.google.com/storage/docs/public-access-prevention for more +// information. +type PublicAccessPrevention int + +const ( + // PublicAccessPreventionUnknown is a zero value, used only if this field is + // not set in a call to GCS. + PublicAccessPreventionUnknown PublicAccessPrevention = iota + + // PublicAccessPreventionUnspecified corresponds to a value of "unspecified". + // Deprecated: use PublicAccessPreventionInherited + PublicAccessPreventionUnspecified + + // PublicAccessPreventionEnforced corresponds to a value of "enforced". This + // enforces Public Access Prevention on the bucket. + PublicAccessPreventionEnforced + + // PublicAccessPreventionInherited corresponds to a value of "inherited" + // and is the default for buckets. + PublicAccessPreventionInherited + + publicAccessPreventionUnknown string = "" + // TODO: remove unspecified when change is fully completed + publicAccessPreventionUnspecified = "unspecified" + publicAccessPreventionEnforced = "enforced" + publicAccessPreventionInherited = "inherited" +) + +func (p PublicAccessPrevention) String() string { + switch p { + case PublicAccessPreventionInherited, PublicAccessPreventionUnspecified: + return publicAccessPreventionInherited + case PublicAccessPreventionEnforced: + return publicAccessPreventionEnforced + default: + return publicAccessPreventionUnknown + } +} + // Lifecycle is the lifecycle configuration for objects in the bucket. type Lifecycle struct { Rules []LifecycleRule @@ -389,7 +550,8 @@ type RetentionPolicy struct { } const ( - // RFC3339 date with only the date segment, used for CreatedBefore in LifecycleRule. + // RFC3339 timestamp with only the date segment, used for CreatedBefore, + // CustomTimeBefore, and NoncurrentTimeBefore in LifecycleRule. rfc3339Date = "2006-01-02" // DeleteAction is a lifecycle action that deletes a live and/or archived @@ -399,6 +561,13 @@ const ( // SetStorageClassAction changes the storage class of live and/or archived // objects. SetStorageClassAction = "SetStorageClass" + + // AbortIncompleteMPUAction is a lifecycle action that aborts an incomplete + // multipart upload when the multipart upload meets the conditions specified + // in the lifecycle rule. The AgeInDays condition is the only allowed + // condition for this action. AgeInDays is measured from the time the + // multipart upload was created. + AbortIncompleteMPUAction = "AbortIncompleteMultipartUpload" ) // LifecycleRule is a lifecycle configuration rule. @@ -419,9 +588,8 @@ type LifecycleRule struct { type LifecycleAction struct { // Type is the type of action to take on matching objects. // - // Acceptable values are "Delete" to delete matching objects and - // "SetStorageClass" to set the storage class defined in StorageClass on - // matching objects. + // Acceptable values are storage.DeleteAction, storage.SetStorageClassAction, + // and storage.AbortIncompleteMPUAction. Type string // StorageClass is the storage class to set on matching objects if the Action @@ -446,7 +614,12 @@ const ( // // All configured conditions must be met for the associated action to be taken. type LifecycleCondition struct { + // AllObjects is used to select all objects in a bucket by + // setting AgeInDays to 0. + AllObjects bool + // AgeInDays is the age of the object in days. + // If you want to set AgeInDays to `0` use AllObjects set to `true`. AgeInDays int64 // CreatedBefore is the time the object was created. @@ -455,20 +628,53 @@ type LifecycleCondition struct { // the specified date in UTC. CreatedBefore time.Time + // CustomTimeBefore is the CustomTime metadata field of the object. This + // condition is satisfied when an object's CustomTime timestamp is before + // midnight of the specified date in UTC. + // + // This condition can only be satisfied if CustomTime has been set. + CustomTimeBefore time.Time + + // DaysSinceCustomTime is the days elapsed since the CustomTime date of the + // object. This condition can only be satisfied if CustomTime has been set. + // Note: Using `0` as the value will be ignored by the library and not sent to the API. + DaysSinceCustomTime int64 + + // DaysSinceNoncurrentTime is the days elapsed since the noncurrent timestamp + // of the object. This condition is relevant only for versioned objects. + // Note: Using `0` as the value will be ignored by the library and not sent to the API. + DaysSinceNoncurrentTime int64 + // Liveness specifies the object's liveness. Relevant only for versioned objects Liveness Liveness + // MatchesPrefix is the condition matching an object if any of the + // matches_prefix strings are an exact prefix of the object's name. + MatchesPrefix []string + // MatchesStorageClasses is the condition matching the object's storage // class. // // Values include "STANDARD", "NEARLINE", "COLDLINE" and "ARCHIVE". MatchesStorageClasses []string + // MatchesSuffix is the condition matching an object if any of the + // matches_suffix strings are an exact suffix of the object's name. + MatchesSuffix []string + + // NoncurrentTimeBefore is the noncurrent timestamp of the object. This + // condition is satisfied when an object's noncurrent timestamp is before + // midnight of the specified date in UTC. + // + // This condition is relevant only for versioned objects. + NoncurrentTimeBefore time.Time + // NumNewerVersions is the condition matching objects with a number of newer versions. // // If the value is N, this condition is satisfied when there are at least N // versions (including the live version) newer than this version of the // object. + // Note: Using `0` as the value will be ignored by the library and not sent to the API. NumNewerVersions int64 } @@ -500,6 +706,29 @@ type BucketWebsite struct { NotFoundPage string } +// CustomPlacementConfig holds the bucket's custom placement +// configuration for Custom Dual Regions. See +// https://cloud.google.com/storage/docs/locations#location-dr for more information. +type CustomPlacementConfig struct { + // The list of regional locations in which data is placed. + // Custom Dual Regions require exactly 2 regional locations. + DataLocations []string +} + +// Autoclass holds the bucket's autoclass configuration. If enabled, +// allows for the automatic selection of the best storage class +// based on object access patterns. See +// https://cloud.google.com/storage/docs/using-autoclass for more information. +type Autoclass struct { + // Enabled specifies whether the autoclass feature is enabled + // on the bucket. + Enabled bool + // ToggleTime is the time from which Autoclass was last toggled. + // If Autoclass is enabled when the bucket is created, the ToggleTime + // is set to the bucket creation time. This field is read-only. + ToggleTime time.Time +} + func newBucket(b *raw.Bucket) (*BucketAttrs, error) { if b == nil { return nil, nil @@ -528,11 +757,49 @@ func newBucket(b *raw.Bucket) (*BucketAttrs, error) { Website: toBucketWebsite(b.Website), BucketPolicyOnly: toBucketPolicyOnly(b.IamConfiguration), UniformBucketLevelAccess: toUniformBucketLevelAccess(b.IamConfiguration), + PublicAccessPrevention: toPublicAccessPrevention(b.IamConfiguration), Etag: b.Etag, LocationType: b.LocationType, + ProjectNumber: b.ProjectNumber, + RPO: toRPO(b), + CustomPlacementConfig: customPlacementFromRaw(b.CustomPlacementConfig), + Autoclass: toAutoclassFromRaw(b.Autoclass), }, nil } +func newBucketFromProto(b *storagepb.Bucket) *BucketAttrs { + if b == nil { + return nil + } + return &BucketAttrs{ + Name: parseBucketName(b.GetName()), + Location: b.GetLocation(), + MetaGeneration: b.GetMetageneration(), + DefaultEventBasedHold: b.GetDefaultEventBasedHold(), + StorageClass: b.GetStorageClass(), + Created: b.GetCreateTime().AsTime(), + VersioningEnabled: b.GetVersioning().GetEnabled(), + ACL: toBucketACLRulesFromProto(b.GetAcl()), + DefaultObjectACL: toObjectACLRulesFromProto(b.GetDefaultObjectAcl()), + Labels: b.GetLabels(), + RequesterPays: b.GetBilling().GetRequesterPays(), + Lifecycle: toLifecycleFromProto(b.GetLifecycle()), + RetentionPolicy: toRetentionPolicyFromProto(b.GetRetentionPolicy()), + CORS: toCORSFromProto(b.GetCors()), + Encryption: toBucketEncryptionFromProto(b.GetEncryption()), + Logging: toBucketLoggingFromProto(b.GetLogging()), + Website: toBucketWebsiteFromProto(b.GetWebsite()), + BucketPolicyOnly: toBucketPolicyOnlyFromProto(b.GetIamConfig()), + UniformBucketLevelAccess: toUniformBucketLevelAccessFromProto(b.GetIamConfig()), + PublicAccessPrevention: toPublicAccessPreventionFromProto(b.GetIamConfig()), + LocationType: b.GetLocationType(), + RPO: toRPOFromProto(b), + CustomPlacementConfig: customPlacementFromProto(b.GetCustomPlacementConfig()), + ProjectNumber: parseProjectNumber(b.GetProject()), // this can return 0 the project resource name is ID based + Autoclass: toAutoclassFromProto(b.GetAutoclass()), + } +} + // toRawBucket copies the editable attribute from b to the raw library's Bucket type. func (b *BucketAttrs) toRawBucket() *raw.Bucket { // Copy label map. @@ -555,29 +822,179 @@ func (b *BucketAttrs) toRawBucket() *raw.Bucket { bb = &raw.BucketBilling{RequesterPays: true} } var bktIAM *raw.BucketIamConfiguration - if b.UniformBucketLevelAccess.Enabled || b.BucketPolicyOnly.Enabled { - bktIAM = &raw.BucketIamConfiguration{ - UniformBucketLevelAccess: &raw.BucketIamConfigurationUniformBucketLevelAccess{ + if b.UniformBucketLevelAccess.Enabled || b.BucketPolicyOnly.Enabled || b.PublicAccessPrevention != PublicAccessPreventionUnknown { + bktIAM = &raw.BucketIamConfiguration{} + if b.UniformBucketLevelAccess.Enabled || b.BucketPolicyOnly.Enabled { + bktIAM.UniformBucketLevelAccess = &raw.BucketIamConfigurationUniformBucketLevelAccess{ Enabled: true, - }, + } + } + if b.PublicAccessPrevention != PublicAccessPreventionUnknown { + bktIAM.PublicAccessPrevention = b.PublicAccessPrevention.String() } } return &raw.Bucket{ - Name: b.Name, - Location: b.Location, - StorageClass: b.StorageClass, - Acl: toRawBucketACL(b.ACL), - DefaultObjectAcl: toRawObjectACL(b.DefaultObjectACL), - Versioning: v, - Labels: labels, - Billing: bb, - Lifecycle: toRawLifecycle(b.Lifecycle), - RetentionPolicy: b.RetentionPolicy.toRawRetentionPolicy(), - Cors: toRawCORS(b.CORS), - Encryption: b.Encryption.toRawBucketEncryption(), - Logging: b.Logging.toRawBucketLogging(), - Website: b.Website.toRawBucketWebsite(), - IamConfiguration: bktIAM, + Name: b.Name, + Location: b.Location, + StorageClass: b.StorageClass, + Acl: toRawBucketACL(b.ACL), + DefaultObjectAcl: toRawObjectACL(b.DefaultObjectACL), + Versioning: v, + Labels: labels, + Billing: bb, + Lifecycle: toRawLifecycle(b.Lifecycle), + RetentionPolicy: b.RetentionPolicy.toRawRetentionPolicy(), + Cors: toRawCORS(b.CORS), + Encryption: b.Encryption.toRawBucketEncryption(), + Logging: b.Logging.toRawBucketLogging(), + Website: b.Website.toRawBucketWebsite(), + IamConfiguration: bktIAM, + Rpo: b.RPO.String(), + CustomPlacementConfig: b.CustomPlacementConfig.toRawCustomPlacement(), + Autoclass: b.Autoclass.toRawAutoclass(), + } +} + +func (b *BucketAttrs) toProtoBucket() *storagepb.Bucket { + if b == nil { + return &storagepb.Bucket{} + } + + // Copy label map. + var labels map[string]string + if len(b.Labels) > 0 { + labels = make(map[string]string, len(b.Labels)) + for k, v := range b.Labels { + labels[k] = v + } + } + + // Ignore VersioningEnabled if it is false. This is OK because + // we only call this method when creating a bucket, and by default + // new buckets have versioning off. + var v *storagepb.Bucket_Versioning + if b.VersioningEnabled { + v = &storagepb.Bucket_Versioning{Enabled: true} + } + var bb *storagepb.Bucket_Billing + if b.RequesterPays { + bb = &storagepb.Bucket_Billing{RequesterPays: true} + } + var bktIAM *storagepb.Bucket_IamConfig + if b.UniformBucketLevelAccess.Enabled || b.BucketPolicyOnly.Enabled || b.PublicAccessPrevention != PublicAccessPreventionUnknown { + bktIAM = &storagepb.Bucket_IamConfig{} + if b.UniformBucketLevelAccess.Enabled || b.BucketPolicyOnly.Enabled { + bktIAM.UniformBucketLevelAccess = &storagepb.Bucket_IamConfig_UniformBucketLevelAccess{ + Enabled: true, + } + } + if b.PublicAccessPrevention != PublicAccessPreventionUnknown { + bktIAM.PublicAccessPrevention = b.PublicAccessPrevention.String() + } + } + + return &storagepb.Bucket{ + Name: b.Name, + Location: b.Location, + StorageClass: b.StorageClass, + Acl: toProtoBucketACL(b.ACL), + DefaultObjectAcl: toProtoObjectACL(b.DefaultObjectACL), + Versioning: v, + Labels: labels, + Billing: bb, + Lifecycle: toProtoLifecycle(b.Lifecycle), + RetentionPolicy: b.RetentionPolicy.toProtoRetentionPolicy(), + Cors: toProtoCORS(b.CORS), + Encryption: b.Encryption.toProtoBucketEncryption(), + Logging: b.Logging.toProtoBucketLogging(), + Website: b.Website.toProtoBucketWebsite(), + IamConfig: bktIAM, + Rpo: b.RPO.String(), + CustomPlacementConfig: b.CustomPlacementConfig.toProtoCustomPlacement(), + Autoclass: b.Autoclass.toProtoAutoclass(), + } +} + +func (ua *BucketAttrsToUpdate) toProtoBucket() *storagepb.Bucket { + if ua == nil { + return &storagepb.Bucket{} + } + + // TODO(cathyo): Handle labels. Pending b/230510191. + + var v *storagepb.Bucket_Versioning + if ua.VersioningEnabled != nil { + v = &storagepb.Bucket_Versioning{Enabled: optional.ToBool(ua.VersioningEnabled)} + } + var bb *storagepb.Bucket_Billing + if ua.RequesterPays != nil { + bb = &storagepb.Bucket_Billing{RequesterPays: optional.ToBool(ua.RequesterPays)} + } + + var bktIAM *storagepb.Bucket_IamConfig + if ua.UniformBucketLevelAccess != nil || ua.BucketPolicyOnly != nil || ua.PublicAccessPrevention != PublicAccessPreventionUnknown { + bktIAM = &storagepb.Bucket_IamConfig{} + + if ua.BucketPolicyOnly != nil { + bktIAM.UniformBucketLevelAccess = &storagepb.Bucket_IamConfig_UniformBucketLevelAccess{ + Enabled: optional.ToBool(ua.BucketPolicyOnly.Enabled), + } + } + + if ua.UniformBucketLevelAccess != nil { + // UniformBucketLevelAccess takes precedence over BucketPolicyOnly, + // so Enabled will be overriden here if both are set + bktIAM.UniformBucketLevelAccess = &storagepb.Bucket_IamConfig_UniformBucketLevelAccess{ + Enabled: optional.ToBool(ua.UniformBucketLevelAccess.Enabled), + } + } + + if ua.PublicAccessPrevention != PublicAccessPreventionUnknown { + bktIAM.PublicAccessPrevention = ua.PublicAccessPrevention.String() + } + } + + var defaultHold bool + if ua.DefaultEventBasedHold != nil { + defaultHold = optional.ToBool(ua.DefaultEventBasedHold) + } + var lifecycle Lifecycle + if ua.Lifecycle != nil { + lifecycle = *ua.Lifecycle + } + var bktACL []*storagepb.BucketAccessControl + if ua.acl != nil { + bktACL = toProtoBucketACL(ua.acl) + } + if ua.PredefinedACL != "" { + // Clear ACL or the call will fail. + bktACL = nil + } + var bktDefaultObjectACL []*storagepb.ObjectAccessControl + if ua.defaultObjectACL != nil { + bktDefaultObjectACL = toProtoObjectACL(ua.defaultObjectACL) + } + if ua.PredefinedDefaultObjectACL != "" { + // Clear ACLs or the call will fail. + bktDefaultObjectACL = nil + } + + return &storagepb.Bucket{ + StorageClass: ua.StorageClass, + Acl: bktACL, + DefaultObjectAcl: bktDefaultObjectACL, + DefaultEventBasedHold: defaultHold, + Versioning: v, + Billing: bb, + Lifecycle: toProtoLifecycle(lifecycle), + RetentionPolicy: ua.RetentionPolicy.toProtoRetentionPolicy(), + Cors: toProtoCORS(ua.CORS), + Encryption: ua.Encryption.toProtoBucketEncryption(), + Logging: ua.Logging.toProtoBucketLogging(), + Website: ua.Website.toProtoBucketWebsite(), + IamConfig: bktIAM, + Rpo: ua.RPO.String(), + Autoclass: ua.Autoclass.toProtoAutoclass(), } } @@ -638,6 +1055,21 @@ type BucketAttrsToUpdate struct { // for more information. UniformBucketLevelAccess *UniformBucketLevelAccess + // PublicAccessPrevention is the setting for the bucket's + // PublicAccessPrevention policy, which can be used to prevent public access + // of data in the bucket. See + // https://cloud.google.com/storage/docs/public-access-prevention for more + // information. + PublicAccessPrevention PublicAccessPrevention + + // StorageClass is the default storage class of the bucket. This defines + // how objects in the bucket are stored and determines the SLA + // and the cost of storage. Typical values are "STANDARD", "NEARLINE", + // "COLDLINE" and "ARCHIVE". Defaults to "STANDARD". + // See https://cloud.google.com/storage/docs/storage-classes for all + // valid values. + StorageClass string + // If set, updates the retention policy of the bucket. Using // RetentionPolicy.RetentionPeriod = 0 will delete the existing policy. // @@ -672,6 +1104,27 @@ type BucketAttrsToUpdate struct { // See https://cloud.google.com/storage/docs/json_api/v1/buckets/patch. PredefinedDefaultObjectACL string + // RPO configures the Recovery Point Objective (RPO) policy of the bucket. + // Set to RPOAsyncTurbo to turn on Turbo Replication for a bucket. + // See https://cloud.google.com/storage/docs/managing-turbo-replication for + // more information. + RPO RPO + + // If set, updates the autoclass configuration of the bucket. + // See https://cloud.google.com/storage/docs/using-autoclass for more information. + Autoclass *Autoclass + + // acl is the list of access control rules on the bucket. + // It is unexported and only used internally by the gRPC client. + // Library users should use ACLHandle methods directly. + acl []ACLRule + + // defaultObjectACL is the list of access controls to + // apply to new objects when no object ACL is provided. + // It is unexported and only used internally by the gRPC client. + // Library users should use ACLHandle methods directly. + defaultObjectACL []ACLRule + setLabels map[string]string deleteLabels map[string]bool } @@ -740,6 +1193,12 @@ func (ua *BucketAttrsToUpdate) toRawBucket() *raw.Bucket { }, } } + if ua.PublicAccessPrevention != PublicAccessPreventionUnknown { + if rb.IamConfiguration == nil { + rb.IamConfiguration = &raw.BucketIamConfiguration{} + } + rb.IamConfiguration.PublicAccessPrevention = ua.PublicAccessPrevention.String() + } if ua.Encryption != nil { if ua.Encryption.DefaultKMSKeyName == "" { rb.NullFields = append(rb.NullFields, "Encryption") @@ -768,6 +1227,12 @@ func (ua *BucketAttrsToUpdate) toRawBucket() *raw.Bucket { rb.Website = ua.Website.toRawBucketWebsite() } } + if ua.Autoclass != nil { + rb.Autoclass = &raw.BucketAutoclass{ + Enabled: ua.Autoclass.Enabled, + ForceSendFields: []string{"Enabled"}, + } + } if ua.PredefinedACL != "" { // Clear ACL or the call will fail. rb.Acl = nil @@ -778,6 +1243,10 @@ func (ua *BucketAttrsToUpdate) toRawBucket() *raw.Bucket { rb.DefaultObjectAcl = nil rb.ForceSendFields = append(rb.ForceSendFields, "DefaultObjectAcl") } + + rb.StorageClass = ua.StorageClass + rb.Rpo = ua.RPO.String() + if ua.setLabels != nil || ua.deleteLabels != nil { rb.Labels = map[string]string{} for k, v := range ua.setLabels { @@ -852,13 +1321,8 @@ func (b *BucketHandle) UserProject(projectID string) *BucketHandle { // most customers. It might be changed in backwards-incompatible ways and is not // subject to any SLA or deprecation policy. func (b *BucketHandle) LockRetentionPolicy(ctx context.Context) error { - var metageneration int64 - if b.conds != nil { - metageneration = b.conds.MetagenerationMatch - } - req := b.c.raw.Buckets.LockRetentionPolicy(b.name, metageneration) - _, err := req.Context(ctx).Do() - return err + o := makeStorageOpts(true, b.retry, b.userProject) + return b.c.tc.LockBucketRetentionPolicy(ctx, b.name, b.conds, o...) } // applyBucketConds modifies the provided call using the conditions in conds. @@ -884,6 +1348,32 @@ func applyBucketConds(method string, conds *BucketConditions, call interface{}) return nil } +// applyBucketConds modifies the provided request message using the conditions +// in conds. msg is a protobuf Message that has fields if_metageneration_match +// and if_metageneration_not_match. +func applyBucketCondsProto(method string, conds *BucketConditions, msg proto.Message) error { + rmsg := msg.ProtoReflect() + + if conds == nil { + return nil + } + if err := conds.validate(method); err != nil { + return err + } + + switch { + case conds.MetagenerationMatch != 0: + if !setConditionProtoField(rmsg, "if_metageneration_match", conds.MetagenerationMatch) { + return fmt.Errorf("storage: %s: ifMetagenerationMatch not supported", method) + } + case conds.MetagenerationNotMatch != 0: + if !setConditionProtoField(rmsg, "if_metageneration_not_match", conds.MetagenerationNotMatch) { + return fmt.Errorf("storage: %s: ifMetagenerationNotMatch not supported", method) + } + } + return nil +} + func (rp *RetentionPolicy) toRawRetentionPolicy() *raw.BucketRetentionPolicy { if rp == nil { return nil @@ -893,8 +1383,23 @@ func (rp *RetentionPolicy) toRawRetentionPolicy() *raw.BucketRetentionPolicy { } } -func toRetentionPolicy(rp *raw.BucketRetentionPolicy) (*RetentionPolicy, error) { +func (rp *RetentionPolicy) toProtoRetentionPolicy() *storagepb.Bucket_RetentionPolicy { if rp == nil { + return nil + } + // RetentionPeriod must be greater than 0, so if it is 0, the user left it + // unset, and so we should not send it in the request i.e. nil is sent. + var period *int64 + if rp.RetentionPeriod != 0 { + period = proto.Int64(int64(rp.RetentionPeriod / time.Second)) + } + return &storagepb.Bucket_RetentionPolicy{ + RetentionPeriod: period, + } +} + +func toRetentionPolicy(rp *raw.BucketRetentionPolicy) (*RetentionPolicy, error) { + if rp == nil || rp.EffectiveTime == "" { return nil, nil } t, err := time.Parse(time.RFC3339, rp.EffectiveTime) @@ -908,6 +1413,17 @@ func toRetentionPolicy(rp *raw.BucketRetentionPolicy) (*RetentionPolicy, error) }, nil } +func toRetentionPolicyFromProto(rp *storagepb.Bucket_RetentionPolicy) *RetentionPolicy { + if rp == nil || rp.GetEffectiveTime().AsTime().Unix() == 0 { + return nil + } + return &RetentionPolicy{ + RetentionPeriod: time.Duration(rp.GetRetentionPeriod()) * time.Second, + EffectiveTime: rp.GetEffectiveTime().AsTime(), + IsLocked: rp.GetIsLocked(), + } +} + func toRawCORS(c []CORS) []*raw.BucketCors { var out []*raw.BucketCors for _, v := range c { @@ -921,6 +1437,19 @@ func toRawCORS(c []CORS) []*raw.BucketCors { return out } +func toProtoCORS(c []CORS) []*storagepb.Bucket_Cors { + var out []*storagepb.Bucket_Cors + for _, v := range c { + out = append(out, &storagepb.Bucket_Cors{ + MaxAgeSeconds: int32(v.MaxAge / time.Second), + Method: v.Methods, + Origin: v.Origins, + ResponseHeader: v.ResponseHeaders, + }) + } + return out +} + func toCORS(rc []*raw.BucketCors) []CORS { var out []CORS for _, v := range rc { @@ -934,6 +1463,19 @@ func toCORS(rc []*raw.BucketCors) []CORS { return out } +func toCORSFromProto(rc []*storagepb.Bucket_Cors) []CORS { + var out []CORS + for _, v := range rc { + out = append(out, CORS{ + MaxAge: time.Duration(v.GetMaxAgeSeconds()) * time.Second, + Methods: v.GetMethod(), + Origins: v.GetOrigin(), + ResponseHeaders: v.GetResponseHeader(), + }) + } + return out +} + func toRawLifecycle(l Lifecycle) *raw.BucketLifecycle { var rl raw.BucketLifecycle if len(l.Rules) == 0 { @@ -946,12 +1488,25 @@ func toRawLifecycle(l Lifecycle) *raw.BucketLifecycle { StorageClass: r.Action.StorageClass, }, Condition: &raw.BucketLifecycleRuleCondition{ - Age: r.Condition.AgeInDays, - MatchesStorageClass: r.Condition.MatchesStorageClasses, - NumNewerVersions: r.Condition.NumNewerVersions, + DaysSinceCustomTime: r.Condition.DaysSinceCustomTime, + DaysSinceNoncurrentTime: r.Condition.DaysSinceNoncurrentTime, + MatchesPrefix: r.Condition.MatchesPrefix, + MatchesStorageClass: r.Condition.MatchesStorageClasses, + MatchesSuffix: r.Condition.MatchesSuffix, + NumNewerVersions: r.Condition.NumNewerVersions, }, } + // AllObjects takes precedent when both AllObjects and AgeInDays are set + // Rationale: If you've opted into using AllObjects, it makes sense that you + // understand the implications of how this option works with AgeInDays. + if r.Condition.AllObjects { + rr.Condition.Age = googleapi.Int64(0) + rr.Condition.ForceSendFields = []string{"Age"} + } else if r.Condition.AgeInDays > 0 { + rr.Condition.Age = googleapi.Int64(r.Condition.AgeInDays) + } + switch r.Condition.Liveness { case LiveAndArchived: rr.Condition.IsLive = nil @@ -964,6 +1519,64 @@ func toRawLifecycle(l Lifecycle) *raw.BucketLifecycle { if !r.Condition.CreatedBefore.IsZero() { rr.Condition.CreatedBefore = r.Condition.CreatedBefore.Format(rfc3339Date) } + if !r.Condition.CustomTimeBefore.IsZero() { + rr.Condition.CustomTimeBefore = r.Condition.CustomTimeBefore.Format(rfc3339Date) + } + if !r.Condition.NoncurrentTimeBefore.IsZero() { + rr.Condition.NoncurrentTimeBefore = r.Condition.NoncurrentTimeBefore.Format(rfc3339Date) + } + rl.Rule = append(rl.Rule, rr) + } + return &rl +} + +func toProtoLifecycle(l Lifecycle) *storagepb.Bucket_Lifecycle { + var rl storagepb.Bucket_Lifecycle + + for _, r := range l.Rules { + rr := &storagepb.Bucket_Lifecycle_Rule{ + Action: &storagepb.Bucket_Lifecycle_Rule_Action{ + Type: r.Action.Type, + StorageClass: r.Action.StorageClass, + }, + Condition: &storagepb.Bucket_Lifecycle_Rule_Condition{ + // Note: The Apiary types use int64 (even though the Discovery + // doc states "format: int32"), so the client types used int64, + // but the proto uses int32 so we have a potentially lossy + // conversion. + AgeDays: proto.Int32(int32(r.Condition.AgeInDays)), + DaysSinceCustomTime: proto.Int32(int32(r.Condition.DaysSinceCustomTime)), + DaysSinceNoncurrentTime: proto.Int32(int32(r.Condition.DaysSinceNoncurrentTime)), + MatchesPrefix: r.Condition.MatchesPrefix, + MatchesStorageClass: r.Condition.MatchesStorageClasses, + MatchesSuffix: r.Condition.MatchesSuffix, + NumNewerVersions: proto.Int32(int32(r.Condition.NumNewerVersions)), + }, + } + + // TODO(#6205): This may not be needed for gRPC + if r.Condition.AllObjects { + rr.Condition.AgeDays = proto.Int32(0) + } + + switch r.Condition.Liveness { + case LiveAndArchived: + rr.Condition.IsLive = nil + case Live: + rr.Condition.IsLive = proto.Bool(true) + case Archived: + rr.Condition.IsLive = proto.Bool(false) + } + + if !r.Condition.CreatedBefore.IsZero() { + rr.Condition.CreatedBefore = timeToProtoDate(r.Condition.CreatedBefore) + } + if !r.Condition.CustomTimeBefore.IsZero() { + rr.Condition.CustomTimeBefore = timeToProtoDate(r.Condition.CustomTimeBefore) + } + if !r.Condition.NoncurrentTimeBefore.IsZero() { + rr.Condition.NoncurrentTimeBefore = timeToProtoDate(r.Condition.NoncurrentTimeBefore) + } rl.Rule = append(rl.Rule, rr) } return &rl @@ -981,11 +1594,20 @@ func toLifecycle(rl *raw.BucketLifecycle) Lifecycle { StorageClass: rr.Action.StorageClass, }, Condition: LifecycleCondition{ - AgeInDays: rr.Condition.Age, - MatchesStorageClasses: rr.Condition.MatchesStorageClass, - NumNewerVersions: rr.Condition.NumNewerVersions, + DaysSinceCustomTime: rr.Condition.DaysSinceCustomTime, + DaysSinceNoncurrentTime: rr.Condition.DaysSinceNoncurrentTime, + MatchesPrefix: rr.Condition.MatchesPrefix, + MatchesStorageClasses: rr.Condition.MatchesStorageClass, + MatchesSuffix: rr.Condition.MatchesSuffix, + NumNewerVersions: rr.Condition.NumNewerVersions, }, } + if rr.Condition.Age != nil { + r.Condition.AgeInDays = *rr.Condition.Age + if *rr.Condition.Age == 0 { + r.Condition.AllObjects = true + } + } if rr.Condition.IsLive == nil { r.Condition.Liveness = LiveAndArchived @@ -998,6 +1620,61 @@ func toLifecycle(rl *raw.BucketLifecycle) Lifecycle { if rr.Condition.CreatedBefore != "" { r.Condition.CreatedBefore, _ = time.Parse(rfc3339Date, rr.Condition.CreatedBefore) } + if rr.Condition.CustomTimeBefore != "" { + r.Condition.CustomTimeBefore, _ = time.Parse(rfc3339Date, rr.Condition.CustomTimeBefore) + } + if rr.Condition.NoncurrentTimeBefore != "" { + r.Condition.NoncurrentTimeBefore, _ = time.Parse(rfc3339Date, rr.Condition.NoncurrentTimeBefore) + } + l.Rules = append(l.Rules, r) + } + return l +} + +func toLifecycleFromProto(rl *storagepb.Bucket_Lifecycle) Lifecycle { + var l Lifecycle + if rl == nil { + return l + } + for _, rr := range rl.GetRule() { + r := LifecycleRule{ + Action: LifecycleAction{ + Type: rr.GetAction().GetType(), + StorageClass: rr.GetAction().GetStorageClass(), + }, + Condition: LifecycleCondition{ + AgeInDays: int64(rr.GetCondition().GetAgeDays()), + DaysSinceCustomTime: int64(rr.GetCondition().GetDaysSinceCustomTime()), + DaysSinceNoncurrentTime: int64(rr.GetCondition().GetDaysSinceNoncurrentTime()), + MatchesPrefix: rr.GetCondition().GetMatchesPrefix(), + MatchesStorageClasses: rr.GetCondition().GetMatchesStorageClass(), + MatchesSuffix: rr.GetCondition().GetMatchesSuffix(), + NumNewerVersions: int64(rr.GetCondition().GetNumNewerVersions()), + }, + } + + // TODO(#6205): This may not be needed for gRPC + if rr.GetCondition().GetAgeDays() == 0 { + r.Condition.AllObjects = true + } + + if rr.GetCondition().IsLive == nil { + r.Condition.Liveness = LiveAndArchived + } else if rr.GetCondition().GetIsLive() { + r.Condition.Liveness = Live + } else { + r.Condition.Liveness = Archived + } + + if rr.GetCondition().GetCreatedBefore() != nil { + r.Condition.CreatedBefore = protoDateToUTCTime(rr.GetCondition().GetCreatedBefore()) + } + if rr.GetCondition().GetCustomTimeBefore() != nil { + r.Condition.CustomTimeBefore = protoDateToUTCTime(rr.GetCondition().GetCustomTimeBefore()) + } + if rr.GetCondition().GetNoncurrentTimeBefore() != nil { + r.Condition.NoncurrentTimeBefore = protoDateToUTCTime(rr.GetCondition().GetNoncurrentTimeBefore()) + } l.Rules = append(l.Rules, r) } return l @@ -1012,6 +1689,15 @@ func (e *BucketEncryption) toRawBucketEncryption() *raw.BucketEncryption { } } +func (e *BucketEncryption) toProtoBucketEncryption() *storagepb.Bucket_Encryption { + if e == nil { + return nil + } + return &storagepb.Bucket_Encryption{ + DefaultKmsKey: e.DefaultKMSKeyName, + } +} + func toBucketEncryption(e *raw.BucketEncryption) *BucketEncryption { if e == nil { return nil @@ -1019,6 +1705,13 @@ func toBucketEncryption(e *raw.BucketEncryption) *BucketEncryption { return &BucketEncryption{DefaultKMSKeyName: e.DefaultKmsKeyName} } +func toBucketEncryptionFromProto(e *storagepb.Bucket_Encryption) *BucketEncryption { + if e == nil { + return nil + } + return &BucketEncryption{DefaultKMSKeyName: e.GetDefaultKmsKey()} +} + func (b *BucketLogging) toRawBucketLogging() *raw.BucketLogging { if b == nil { return nil @@ -1029,6 +1722,16 @@ func (b *BucketLogging) toRawBucketLogging() *raw.BucketLogging { } } +func (b *BucketLogging) toProtoBucketLogging() *storagepb.Bucket_Logging { + if b == nil { + return nil + } + return &storagepb.Bucket_Logging{ + LogBucket: bucketResourceName(globalProjectAlias, b.LogBucket), + LogObjectPrefix: b.LogObjectPrefix, + } +} + func toBucketLogging(b *raw.BucketLogging) *BucketLogging { if b == nil { return nil @@ -1039,6 +1742,17 @@ func toBucketLogging(b *raw.BucketLogging) *BucketLogging { } } +func toBucketLoggingFromProto(b *storagepb.Bucket_Logging) *BucketLogging { + if b == nil { + return nil + } + lb := parseBucketName(b.GetLogBucket()) + return &BucketLogging{ + LogBucket: lb, + LogObjectPrefix: b.GetLogObjectPrefix(), + } +} + func (w *BucketWebsite) toRawBucketWebsite() *raw.BucketWebsite { if w == nil { return nil @@ -1049,6 +1763,16 @@ func (w *BucketWebsite) toRawBucketWebsite() *raw.BucketWebsite { } } +func (w *BucketWebsite) toProtoBucketWebsite() *storagepb.Bucket_Website { + if w == nil { + return nil + } + return &storagepb.Bucket_Website{ + MainPageSuffix: w.MainPageSuffix, + NotFoundPage: w.NotFoundPage, + } +} + func toBucketWebsite(w *raw.BucketWebsite) *BucketWebsite { if w == nil { return nil @@ -1059,6 +1783,16 @@ func toBucketWebsite(w *raw.BucketWebsite) *BucketWebsite { } } +func toBucketWebsiteFromProto(w *storagepb.Bucket_Website) *BucketWebsite { + if w == nil { + return nil + } + return &BucketWebsite{ + MainPageSuffix: w.GetMainPageSuffix(), + NotFoundPage: w.GetNotFoundPage(), + } +} + func toBucketPolicyOnly(b *raw.BucketIamConfiguration) BucketPolicyOnly { if b == nil || b.BucketPolicyOnly == nil || !b.BucketPolicyOnly.Enabled { return BucketPolicyOnly{} @@ -1075,6 +1809,16 @@ func toBucketPolicyOnly(b *raw.BucketIamConfiguration) BucketPolicyOnly { } } +func toBucketPolicyOnlyFromProto(b *storagepb.Bucket_IamConfig) BucketPolicyOnly { + if b == nil || !b.GetUniformBucketLevelAccess().GetEnabled() { + return BucketPolicyOnly{} + } + return BucketPolicyOnly{ + Enabled: true, + LockedTime: b.GetUniformBucketLevelAccess().GetLockTime().AsTime(), + } +} + func toUniformBucketLevelAccess(b *raw.BucketIamConfiguration) UniformBucketLevelAccess { if b == nil || b.UniformBucketLevelAccess == nil || !b.UniformBucketLevelAccess.Enabled { return UniformBucketLevelAccess{} @@ -1091,23 +1835,186 @@ func toUniformBucketLevelAccess(b *raw.BucketIamConfiguration) UniformBucketLeve } } -// Objects returns an iterator over the objects in the bucket that match the Query q. -// If q is nil, no filtering is done. +func toUniformBucketLevelAccessFromProto(b *storagepb.Bucket_IamConfig) UniformBucketLevelAccess { + if b == nil || !b.GetUniformBucketLevelAccess().GetEnabled() { + return UniformBucketLevelAccess{} + } + return UniformBucketLevelAccess{ + Enabled: true, + LockedTime: b.GetUniformBucketLevelAccess().GetLockTime().AsTime(), + } +} + +func toPublicAccessPrevention(b *raw.BucketIamConfiguration) PublicAccessPrevention { + if b == nil { + return PublicAccessPreventionUnknown + } + switch b.PublicAccessPrevention { + case publicAccessPreventionInherited, publicAccessPreventionUnspecified: + return PublicAccessPreventionInherited + case publicAccessPreventionEnforced: + return PublicAccessPreventionEnforced + default: + return PublicAccessPreventionUnknown + } +} + +func toPublicAccessPreventionFromProto(b *storagepb.Bucket_IamConfig) PublicAccessPrevention { + if b == nil { + return PublicAccessPreventionUnknown + } + switch b.GetPublicAccessPrevention() { + case publicAccessPreventionInherited, publicAccessPreventionUnspecified: + return PublicAccessPreventionInherited + case publicAccessPreventionEnforced: + return PublicAccessPreventionEnforced + default: + return PublicAccessPreventionUnknown + } +} + +func toRPO(b *raw.Bucket) RPO { + if b == nil { + return RPOUnknown + } + switch b.Rpo { + case rpoDefault: + return RPODefault + case rpoAsyncTurbo: + return RPOAsyncTurbo + default: + return RPOUnknown + } +} + +func toRPOFromProto(b *storagepb.Bucket) RPO { + if b == nil { + return RPOUnknown + } + switch b.GetRpo() { + case rpoDefault: + return RPODefault + case rpoAsyncTurbo: + return RPOAsyncTurbo + default: + return RPOUnknown + } +} + +func customPlacementFromRaw(c *raw.BucketCustomPlacementConfig) *CustomPlacementConfig { + if c == nil { + return nil + } + return &CustomPlacementConfig{DataLocations: c.DataLocations} +} + +func (c *CustomPlacementConfig) toRawCustomPlacement() *raw.BucketCustomPlacementConfig { + if c == nil { + return nil + } + return &raw.BucketCustomPlacementConfig{ + DataLocations: c.DataLocations, + } +} + +func (c *CustomPlacementConfig) toProtoCustomPlacement() *storagepb.Bucket_CustomPlacementConfig { + if c == nil { + return nil + } + return &storagepb.Bucket_CustomPlacementConfig{ + DataLocations: c.DataLocations, + } +} + +func customPlacementFromProto(c *storagepb.Bucket_CustomPlacementConfig) *CustomPlacementConfig { + if c == nil { + return nil + } + return &CustomPlacementConfig{DataLocations: c.GetDataLocations()} +} + +func (a *Autoclass) toRawAutoclass() *raw.BucketAutoclass { + if a == nil { + return nil + } + // Excluding read only field ToggleTime. + return &raw.BucketAutoclass{ + Enabled: a.Enabled, + } +} + +func (a *Autoclass) toProtoAutoclass() *storagepb.Bucket_Autoclass { + if a == nil { + return nil + } + // Excluding read only field ToggleTime. + return &storagepb.Bucket_Autoclass{ + Enabled: a.Enabled, + } +} + +func toAutoclassFromRaw(a *raw.BucketAutoclass) *Autoclass { + if a == nil || a.ToggleTime == "" { + return nil + } + // Return Autoclass.ToggleTime only if parsed with a valid value. + t, err := time.Parse(time.RFC3339, a.ToggleTime) + if err != nil { + return &Autoclass{ + Enabled: a.Enabled, + } + } + return &Autoclass{ + Enabled: a.Enabled, + ToggleTime: t, + } +} + +func toAutoclassFromProto(a *storagepb.Bucket_Autoclass) *Autoclass { + if a == nil || a.GetToggleTime().AsTime().Unix() == 0 { + return nil + } + return &Autoclass{ + Enabled: a.GetEnabled(), + ToggleTime: a.GetToggleTime().AsTime(), + } +} + +// Objects returns an iterator over the objects in the bucket that match the +// Query q. If q is nil, no filtering is done. Objects will be iterated over +// lexicographically by name. // // Note: The returned iterator is not safe for concurrent operations without explicit synchronization. func (b *BucketHandle) Objects(ctx context.Context, q *Query) *ObjectIterator { - it := &ObjectIterator{ - ctx: ctx, - bucket: b, + o := makeStorageOpts(true, b.retry, b.userProject) + return b.c.tc.ListObjects(ctx, b.name, q, o...) +} + +// Retryer returns a bucket handle that is configured with custom retry +// behavior as specified by the options that are passed to it. All operations +// on the new handle will use the customized retry configuration. +// Retry options set on a object handle will take precedence over options set on +// the bucket handle. +// These retry options will merge with the client's retry configuration (if set) +// for the returned handle. Options passed into this method will take precedence +// over retry options on the client. Note that you must explicitly pass in each +// option you want to override. +func (b *BucketHandle) Retryer(opts ...RetryOption) *BucketHandle { + b2 := *b + var retry *retryConfig + if b.retry != nil { + // merge the options with the existing retry + retry = b.retry + } else { + retry = &retryConfig{} } - it.pageInfo, it.nextFunc = iterator.NewPageInfo( - it.fetch, - func() int { return len(it.items) }, - func() interface{} { b := it.items; it.items = nil; return b }) - if q != nil { - it.query = *q + for _, opt := range opts { + opt.apply(retry) } - return it + b2.retry = retry + b2.acl.retry = retry + b2.defaultObjectACL.retry = retry + return &b2 } // An ObjectIterator is an iterator over ObjectAttrs. @@ -1115,7 +2022,6 @@ func (b *BucketHandle) Objects(ctx context.Context, q *Query) *ObjectIterator { // Note: This iterator is not safe for concurrent operations without explicit synchronization. type ObjectIterator struct { ctx context.Context - bucket *BucketHandle query Query pageInfo *iterator.PageInfo nextFunc func() error @@ -1131,6 +2037,13 @@ func (it *ObjectIterator) PageInfo() *iterator.PageInfo { return it.pageInfo } // there are no more results. Once Next returns iterator.Done, all subsequent // calls will return iterator.Done. // +// In addition, if Next returns an error other than iterator.Done, all +// subsequent calls will return the same error. To continue iteration, a new +// `ObjectIterator` must be created. Since objects are ordered lexicographically +// by name, `Query.StartOffset` can be used to create a new iterator which will +// start at the desired place. See +// https://pkg.go.dev/cloud.google.com/go/storage?tab=doc#hdr-Listing_objects. +// // If Query.Delimiter is non-empty, some of the ObjectAttrs returned by Next will // have a non-empty Prefix field, and a zero value for all other fields. These // represent prefixes. @@ -1145,44 +2058,6 @@ func (it *ObjectIterator) Next() (*ObjectAttrs, error) { return item, nil } -func (it *ObjectIterator) fetch(pageSize int, pageToken string) (string, error) { - req := it.bucket.c.raw.Objects.List(it.bucket.name) - setClientHeader(req.Header()) - req.Projection("full") - req.Delimiter(it.query.Delimiter) - req.Prefix(it.query.Prefix) - req.Versions(it.query.Versions) - if len(it.query.fieldSelection) > 0 { - req.Fields("nextPageToken", googleapi.Field(it.query.fieldSelection)) - } - req.PageToken(pageToken) - if it.bucket.userProject != "" { - req.UserProject(it.bucket.userProject) - } - if pageSize > 0 { - req.MaxResults(int64(pageSize)) - } - var resp *raw.Objects - var err error - err = runWithRetry(it.ctx, func() error { - resp, err = req.Context(it.ctx).Do() - return err - }) - if err != nil { - if e, ok := err.(*googleapi.Error); ok && e.Code == http.StatusNotFound { - err = ErrBucketNotExist - } - return "", err - } - for _, item := range resp.Items { - it.items = append(it.items, newObject(item)) - } - for _, prefix := range resp.Prefixes { - it.items = append(it.items, &ObjectAttrs{Prefix: prefix}) - } - return resp.NextPageToken, nil -} - // Buckets returns an iterator over the buckets in the project. You may // optionally set the iterator's Prefix field to restrict the list to buckets // whose names begin with the prefix. By default, all buckets in the project @@ -1190,17 +2065,8 @@ func (it *ObjectIterator) fetch(pageSize int, pageToken string) (string, error) // // Note: The returned iterator is not safe for concurrent operations without explicit synchronization. func (c *Client) Buckets(ctx context.Context, projectID string) *BucketIterator { - it := &BucketIterator{ - ctx: ctx, - client: c, - projectID: projectID, - } - it.pageInfo, it.nextFunc = iterator.NewPageInfo( - it.fetch, - func() int { return len(it.buckets) }, - func() interface{} { b := it.buckets; it.buckets = nil; return b }) - - return it + o := makeStorageOpts(true, c.retry, "") + return c.tc.ListBuckets(ctx, projectID, o...) } // A BucketIterator is an iterator over BucketAttrs. @@ -1211,7 +2077,6 @@ type BucketIterator struct { Prefix string ctx context.Context - client *Client projectID string buckets []*BucketAttrs pageInfo *iterator.PageInfo @@ -1237,29 +2102,63 @@ func (it *BucketIterator) Next() (*BucketAttrs, error) { // Note: This method is not safe for concurrent operations without explicit synchronization. func (it *BucketIterator) PageInfo() *iterator.PageInfo { return it.pageInfo } -func (it *BucketIterator) fetch(pageSize int, pageToken string) (token string, err error) { - req := it.client.raw.Buckets.List(it.projectID) - setClientHeader(req.Header()) - req.Projection("full") - req.Prefix(it.Prefix) - req.PageToken(pageToken) - if pageSize > 0 { - req.MaxResults(int64(pageSize)) - } - var resp *raw.Buckets - err = runWithRetry(it.ctx, func() error { - resp, err = req.Context(it.ctx).Do() - return err - }) - if err != nil { - return "", err +// RPO (Recovery Point Objective) configures the turbo replication feature. See +// https://cloud.google.com/storage/docs/managing-turbo-replication for more information. +type RPO int + +const ( + // RPOUnknown is a zero value. It may be returned from bucket.Attrs() if RPO + // is not present in the bucket metadata, that is, the bucket is not dual-region. + // This value is also used if the RPO field is not set in a call to GCS. + RPOUnknown RPO = iota + + // RPODefault represents default replication. It is used to reset RPO on an + // existing bucket that has this field set to RPOAsyncTurbo. Otherwise it + // is equivalent to RPOUnknown, and is always ignored. This value is valid + // for dual- or multi-region buckets. + RPODefault + + // RPOAsyncTurbo represents turbo replication and is used to enable Turbo + // Replication on a bucket. This value is only valid for dual-region buckets. + RPOAsyncTurbo + + rpoUnknown string = "" + rpoDefault = "DEFAULT" + rpoAsyncTurbo = "ASYNC_TURBO" +) + +func (rpo RPO) String() string { + switch rpo { + case RPODefault: + return rpoDefault + case RPOAsyncTurbo: + return rpoAsyncTurbo + default: + return rpoUnknown } - for _, item := range resp.Items { - b, err := newBucket(item) - if err != nil { - return "", err - } - it.buckets = append(it.buckets, b) +} + +// protoDateToUTCTime returns a new Time based on the google.type.Date, in UTC. +// +// Hours, minutes, seconds, and nanoseconds are set to 0. +func protoDateToUTCTime(d *dpb.Date) time.Time { + return protoDateToTime(d, time.UTC) +} + +// protoDateToTime returns a new Time based on the google.type.Date and provided +// *time.Location. +// +// Hours, minutes, seconds, and nanoseconds are set to 0. +func protoDateToTime(d *dpb.Date, l *time.Location) time.Time { + return time.Date(int(d.GetYear()), time.Month(d.GetMonth()), int(d.GetDay()), 0, 0, 0, 0, l) +} + +// timeToProtoDate returns a new google.type.Date based on the provided time.Time. +// The location is ignored, as is anything more precise than the day. +func timeToProtoDate(t time.Time) *dpb.Date { + return &dpb.Date{ + Year: int32(t.Year()), + Month: int32(t.Month()), + Day: int32(t.Day()), } - return resp.NextPageToken, nil } diff --git a/vendor/cloud.google.com/go/storage/client.go b/vendor/cloud.google.com/go/storage/client.go new file mode 100644 index 00000000000..d579a2b1ee7 --- /dev/null +++ b/vendor/cloud.google.com/go/storage/client.go @@ -0,0 +1,333 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package storage + +import ( + "context" + "io" + "time" + + gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/option" + iampb "google.golang.org/genproto/googleapis/iam/v1" +) + +// TODO(noahdietz): Move existing factory methods to this file. + +// storageClient is an internal-only interface designed to separate the +// transport-specific logic of making Storage API calls from the logic of the +// client library. +// +// Implementation requirements beyond implementing the interface include: +// * factory method(s) must accept a `userProject string` param +// * `settings` must be retained per instance +// * `storageOption`s must be resolved in the order they are received +// * all API errors must be wrapped in the gax-go APIError type +// * any unimplemented interface methods must return a StorageUnimplementedErr +// +// TODO(noahdietz): This interface is currently not used in the production code +// paths +type storageClient interface { + + // Top-level methods. + + GetServiceAccount(ctx context.Context, project string, opts ...storageOption) (string, error) + CreateBucket(ctx context.Context, project, bucket string, attrs *BucketAttrs, opts ...storageOption) (*BucketAttrs, error) + ListBuckets(ctx context.Context, project string, opts ...storageOption) *BucketIterator + Close() error + + // Bucket methods. + + DeleteBucket(ctx context.Context, bucket string, conds *BucketConditions, opts ...storageOption) error + GetBucket(ctx context.Context, bucket string, conds *BucketConditions, opts ...storageOption) (*BucketAttrs, error) + UpdateBucket(ctx context.Context, bucket string, uattrs *BucketAttrsToUpdate, conds *BucketConditions, opts ...storageOption) (*BucketAttrs, error) + LockBucketRetentionPolicy(ctx context.Context, bucket string, conds *BucketConditions, opts ...storageOption) error + ListObjects(ctx context.Context, bucket string, q *Query, opts ...storageOption) *ObjectIterator + + // Object metadata methods. + + DeleteObject(ctx context.Context, bucket, object string, gen int64, conds *Conditions, opts ...storageOption) error + GetObject(ctx context.Context, bucket, object string, gen int64, encryptionKey []byte, conds *Conditions, opts ...storageOption) (*ObjectAttrs, error) + UpdateObject(ctx context.Context, bucket, object string, uattrs *ObjectAttrsToUpdate, gen int64, encryptionKey []byte, conds *Conditions, opts ...storageOption) (*ObjectAttrs, error) + + // Default Object ACL methods. + + DeleteDefaultObjectACL(ctx context.Context, bucket string, entity ACLEntity, opts ...storageOption) error + ListDefaultObjectACLs(ctx context.Context, bucket string, opts ...storageOption) ([]ACLRule, error) + UpdateDefaultObjectACL(ctx context.Context, bucket string, entity ACLEntity, role ACLRole, opts ...storageOption) error + + // Bucket ACL methods. + + DeleteBucketACL(ctx context.Context, bucket string, entity ACLEntity, opts ...storageOption) error + ListBucketACLs(ctx context.Context, bucket string, opts ...storageOption) ([]ACLRule, error) + UpdateBucketACL(ctx context.Context, bucket string, entity ACLEntity, role ACLRole, opts ...storageOption) error + + // Object ACL methods. + + DeleteObjectACL(ctx context.Context, bucket, object string, entity ACLEntity, opts ...storageOption) error + ListObjectACLs(ctx context.Context, bucket, object string, opts ...storageOption) ([]ACLRule, error) + UpdateObjectACL(ctx context.Context, bucket, object string, entity ACLEntity, role ACLRole, opts ...storageOption) error + + // Media operations. + + ComposeObject(ctx context.Context, req *composeObjectRequest, opts ...storageOption) (*ObjectAttrs, error) + RewriteObject(ctx context.Context, req *rewriteObjectRequest, opts ...storageOption) (*rewriteObjectResponse, error) + + NewRangeReader(ctx context.Context, params *newRangeReaderParams, opts ...storageOption) (*Reader, error) + OpenWriter(params *openWriterParams, opts ...storageOption) (*io.PipeWriter, error) + + // IAM methods. + + GetIamPolicy(ctx context.Context, resource string, version int32, opts ...storageOption) (*iampb.Policy, error) + SetIamPolicy(ctx context.Context, resource string, policy *iampb.Policy, opts ...storageOption) error + TestIamPermissions(ctx context.Context, resource string, permissions []string, opts ...storageOption) ([]string, error) + + // HMAC Key methods. + + GetHMACKey(ctx context.Context, project, accessID string, opts ...storageOption) (*HMACKey, error) + ListHMACKeys(ctx context.Context, project, serviceAccountEmail string, showDeletedKeys bool, opts ...storageOption) *HMACKeysIterator + UpdateHMACKey(ctx context.Context, project, serviceAccountEmail, accessID string, attrs *HMACKeyAttrsToUpdate, opts ...storageOption) (*HMACKey, error) + CreateHMACKey(ctx context.Context, project, serviceAccountEmail string, opts ...storageOption) (*HMACKey, error) + DeleteHMACKey(ctx context.Context, project, accessID string, opts ...storageOption) error + + // Notification methods. + ListNotifications(ctx context.Context, bucket string, opts ...storageOption) (map[string]*Notification, error) + CreateNotification(ctx context.Context, bucket string, n *Notification, opts ...storageOption) (*Notification, error) + DeleteNotification(ctx context.Context, bucket string, id string, opts ...storageOption) error +} + +// settings contains transport-agnostic configuration for API calls made via +// the storageClient inteface. All implementations must utilize settings +// and respect those that are applicable. +type settings struct { + // retry is the complete retry configuration to use when evaluating if an + // API call should be retried. + retry *retryConfig + + // gax is a set of gax.CallOption to be conveyed to gax.Invoke. + // Note: Not all storageClient interfaces will must use gax.Invoke. + gax []gax.CallOption + + // idempotent indicates if the call is idempotent or not when considering + // if the call should be retired or not. + idempotent bool + + // clientOption is a set of option.ClientOption to be used during client + // transport initialization. See https://pkg.go.dev/google.golang.org/api/option + // for a list of supported options. + clientOption []option.ClientOption + + // userProject is the user project that should be billed for the request. + userProject string +} + +func initSettings(opts ...storageOption) *settings { + s := &settings{} + resolveOptions(s, opts...) + return s +} + +func resolveOptions(s *settings, opts ...storageOption) { + for _, o := range opts { + o.Apply(s) + } +} + +// callSettings is a helper for resolving storage options against the settings +// in the context of an individual call. This is to ensure that client-level +// default settings are not mutated by two different calls getting options. +// +// Example: s := callSettings(c.settings, opts...) +func callSettings(defaults *settings, opts ...storageOption) *settings { + if defaults == nil { + return nil + } + // This does not make a deep copy of the pointer/slice fields, but all + // options replace the settings fields rather than modify their values in + // place. + cs := *defaults + resolveOptions(&cs, opts...) + return &cs +} + +// makeStorageOpts is a helper for generating a set of storageOption based on +// idempotency, retryConfig, and userProject. All top-level client operations +// will generally have to pass these options through the interface. +func makeStorageOpts(isIdempotent bool, retry *retryConfig, userProject string) []storageOption { + opts := []storageOption{idempotent(isIdempotent)} + if retry != nil { + opts = append(opts, withRetryConfig(retry)) + } + if userProject != "" { + opts = append(opts, withUserProject(userProject)) + } + return opts +} + +// storageOption is the transport-agnostic call option for the storageClient +// interface. +type storageOption interface { + Apply(s *settings) +} + +func withGAXOptions(opts ...gax.CallOption) storageOption { + return &gaxOption{opts} +} + +type gaxOption struct { + opts []gax.CallOption +} + +func (o *gaxOption) Apply(s *settings) { s.gax = o.opts } + +func withRetryConfig(rc *retryConfig) storageOption { + return &retryOption{rc} +} + +type retryOption struct { + rc *retryConfig +} + +func (o *retryOption) Apply(s *settings) { s.retry = o.rc } + +func idempotent(i bool) storageOption { + return &idempotentOption{i} +} + +type idempotentOption struct { + idempotency bool +} + +func (o *idempotentOption) Apply(s *settings) { s.idempotent = o.idempotency } + +func withClientOptions(opts ...option.ClientOption) storageOption { + return &clientOption{opts: opts} +} + +type clientOption struct { + opts []option.ClientOption +} + +func (o *clientOption) Apply(s *settings) { s.clientOption = o.opts } + +func withUserProject(project string) storageOption { + return &userProjectOption{project} +} + +type userProjectOption struct { + project string +} + +func (o *userProjectOption) Apply(s *settings) { s.userProject = o.project } + +type openWriterParams struct { + // Writer configuration + + // ctx is the context used by the writer routine to make all network calls + // and to manage the writer routine - see `Writer.ctx`. + // Required. + ctx context.Context + // chunkSize - see `Writer.ChunkSize`. + // Optional. + chunkSize int + // chunkRetryDeadline - see `Writer.ChunkRetryDeadline`. + // Optional. + chunkRetryDeadline time.Duration + + // Object/request properties + + // bucket - see `Writer.o.bucket`. + // Required. + bucket string + // attrs - see `Writer.ObjectAttrs`. + // Required. + attrs *ObjectAttrs + // conds - see `Writer.o.conds`. + // Optional. + conds *Conditions + // encryptionKey - see `Writer.o.encryptionKey` + // Optional. + encryptionKey []byte + // sendCRC32C - see `Writer.SendCRC32C`. + // Optional. + sendCRC32C bool + + // Writer callbacks + + // donec - see `Writer.donec`. + // Required. + donec chan struct{} + // setError callback for reporting errors - see `Writer.error`. + // Required. + setError func(error) + // progress callback for reporting upload progress - see `Writer.progress`. + // Required. + progress func(int64) + // setObj callback for reporting the resulting object - see `Writer.obj`. + // Required. + setObj func(*ObjectAttrs) +} + +type newRangeReaderParams struct { + bucket string + conds *Conditions + encryptionKey []byte + gen int64 + length int64 + object string + offset int64 + readCompressed bool // Use accept-encoding: gzip. Only works for HTTP currently. +} + +type composeObjectRequest struct { + dstBucket string + dstObject destinationObject + srcs []sourceObject + predefinedACL string + sendCRC32C bool +} + +type sourceObject struct { + name string + bucket string + gen int64 + conds *Conditions + encryptionKey []byte +} + +type destinationObject struct { + name string + bucket string + conds *Conditions + attrs *ObjectAttrs // attrs to set on the destination object. + encryptionKey []byte + keyName string +} + +type rewriteObjectRequest struct { + srcObject sourceObject + dstObject destinationObject + predefinedACL string + token string + maxBytesRewrittenPerCall int64 +} + +type rewriteObjectResponse struct { + resource *ObjectAttrs + done bool + written int64 + size int64 + token string +} diff --git a/vendor/cloud.google.com/go/storage/copy.go b/vendor/cloud.google.com/go/storage/copy.go index 61983df5ada..a0b9a2683c7 100644 --- a/vendor/cloud.google.com/go/storage/copy.go +++ b/vendor/cloud.google.com/go/storage/copy.go @@ -20,7 +20,6 @@ import ( "fmt" "cloud.google.com/go/internal/trace" - raw "google.golang.org/api/storage/v1" ) // CopierFrom creates a Copier that can copy src to dst. @@ -70,6 +69,15 @@ type Copier struct { DestinationKMSKeyName string dst, src *ObjectHandle + + // The maximum number of bytes that will be rewritten per rewrite request. + // Most callers shouldn't need to specify this parameter - it is primarily + // in place to support testing. If specified the value must be an integral + // multiple of 1 MiB (1048576). Also, this only applies to requests where + // the source and destination span locations and/or storage classes. Finally, + // this value must not change across rewrite calls else you'll get an error + // that the `rewriteToken` is invalid. + maxBytesRewrittenPerCall int64 } // Run performs the copy. @@ -86,66 +94,59 @@ func (c *Copier) Run(ctx context.Context) (attrs *ObjectAttrs, err error) { if c.DestinationKMSKeyName != "" && c.dst.encryptionKey != nil { return nil, errors.New("storage: cannot use DestinationKMSKeyName with a customer-supplied encryption key") } + if c.dst.gen != defaultGen { + return nil, fmt.Errorf("storage: generation cannot be specified on copy destination, got %v", c.dst.gen) + } // Convert destination attributes to raw form, omitting the bucket. // If the bucket is included but name or content-type aren't, the service // returns a 400 with "Required" as the only message. Omitting the bucket // does not cause any problems. - rawObject := c.ObjectAttrs.toRawObject("") + req := &rewriteObjectRequest{ + srcObject: sourceObject{ + name: c.src.object, + bucket: c.src.bucket, + gen: c.src.gen, + conds: c.src.conds, + encryptionKey: c.src.encryptionKey, + }, + dstObject: destinationObject{ + name: c.dst.object, + bucket: c.dst.bucket, + conds: c.dst.conds, + attrs: &c.ObjectAttrs, + encryptionKey: c.dst.encryptionKey, + keyName: c.DestinationKMSKeyName, + }, + predefinedACL: c.PredefinedACL, + token: c.RewriteToken, + maxBytesRewrittenPerCall: c.maxBytesRewrittenPerCall, + } + + isIdempotent := c.dst.conds != nil && (c.dst.conds.GenerationMatch != 0 || c.dst.conds.DoesNotExist) + var userProject string + if c.dst.userProject != "" { + userProject = c.dst.userProject + } else if c.src.userProject != "" { + userProject = c.src.userProject + } + opts := makeStorageOpts(isIdempotent, c.dst.retry, userProject) + for { - res, err := c.callRewrite(ctx, rawObject) + res, err := c.dst.c.tc.RewriteObject(ctx, req, opts...) if err != nil { return nil, err } + c.RewriteToken = res.token + req.token = res.token if c.ProgressFunc != nil { - c.ProgressFunc(uint64(res.TotalBytesRewritten), uint64(res.ObjectSize)) + c.ProgressFunc(uint64(res.written), uint64(res.size)) } - if res.Done { // Finished successfully. - return newObject(res.Resource), nil + if res.done { // Finished successfully. + return res.resource, nil } } } -func (c *Copier) callRewrite(ctx context.Context, rawObj *raw.Object) (*raw.RewriteResponse, error) { - call := c.dst.c.raw.Objects.Rewrite(c.src.bucket, c.src.object, c.dst.bucket, c.dst.object, rawObj) - - call.Context(ctx).Projection("full") - if c.RewriteToken != "" { - call.RewriteToken(c.RewriteToken) - } - if c.DestinationKMSKeyName != "" { - call.DestinationKmsKeyName(c.DestinationKMSKeyName) - } - if c.PredefinedACL != "" { - call.DestinationPredefinedAcl(c.PredefinedACL) - } - if err := applyConds("Copy destination", c.dst.gen, c.dst.conds, call); err != nil { - return nil, err - } - if c.dst.userProject != "" { - call.UserProject(c.dst.userProject) - } else if c.src.userProject != "" { - call.UserProject(c.src.userProject) - } - if err := applySourceConds(c.src.gen, c.src.conds, call); err != nil { - return nil, err - } - if err := setEncryptionHeaders(call.Header(), c.dst.encryptionKey, false); err != nil { - return nil, err - } - if err := setEncryptionHeaders(call.Header(), c.src.encryptionKey, true); err != nil { - return nil, err - } - var res *raw.RewriteResponse - var err error - setClientHeader(call.Header()) - err = runWithRetry(ctx, func() error { res, err = call.Do(); return err }) - if err != nil { - return nil, err - } - c.RewriteToken = res.RewriteToken - return res, nil -} - // ComposerFrom creates a Composer that can compose srcs into dst. // You can immediately call Run on the returned Composer, or you can // configure it first. @@ -185,17 +186,13 @@ func (c *Composer) Run(ctx context.Context) (attrs *ObjectAttrs, err error) { if err := c.dst.validate(); err != nil { return nil, err } + if c.dst.gen != defaultGen { + return nil, fmt.Errorf("storage: generation cannot be specified on compose destination, got %v", c.dst.gen) + } if len(c.srcs) == 0 { return nil, errors.New("storage: at least one source object must be specified") } - req := &raw.ComposeRequest{} - // Compose requires a non-empty Destination, so we always set it, - // even if the caller-provided ObjectAttrs is the zero value. - req.Destination = c.ObjectAttrs.toRawObject(c.dst.bucket) - if c.SendCRC32C { - req.Destination.Crc32c = encodeUint32(c.ObjectAttrs.CRC32C) - } for _, src := range c.srcs { if err := src.validate(); err != nil { return nil, err @@ -206,33 +203,31 @@ func (c *Composer) Run(ctx context.Context) (attrs *ObjectAttrs, err error) { if src.encryptionKey != nil { return nil, fmt.Errorf("storage: compose source %s.%s must not have encryption key", src.bucket, src.object) } - srcObj := &raw.ComposeRequestSourceObjects{ - Name: src.object, - } - if err := applyConds("ComposeFrom source", src.gen, src.conds, composeSourceObj{srcObj}); err != nil { - return nil, err - } - req.SourceObjects = append(req.SourceObjects, srcObj) } - call := c.dst.c.raw.Objects.Compose(c.dst.bucket, c.dst.object, req).Context(ctx) - if err := applyConds("ComposeFrom destination", c.dst.gen, c.dst.conds, call); err != nil { - return nil, err - } - if c.dst.userProject != "" { - call.UserProject(c.dst.userProject) + req := &composeObjectRequest{ + dstBucket: c.dst.bucket, + predefinedACL: c.PredefinedACL, + sendCRC32C: c.SendCRC32C, } - if c.PredefinedACL != "" { - call.DestinationPredefinedAcl(c.PredefinedACL) - } - if err := setEncryptionHeaders(call.Header(), c.dst.encryptionKey, false); err != nil { - return nil, err + req.dstObject = destinationObject{ + name: c.dst.object, + bucket: c.dst.bucket, + conds: c.dst.conds, + attrs: &c.ObjectAttrs, + encryptionKey: c.dst.encryptionKey, } - var obj *raw.Object - setClientHeader(call.Header()) - err = runWithRetry(ctx, func() error { obj, err = call.Do(); return err }) - if err != nil { - return nil, err + for _, src := range c.srcs { + s := sourceObject{ + name: src.object, + bucket: src.bucket, + gen: src.gen, + conds: src.conds, + } + req.srcs = append(req.srcs, s) } - return newObject(obj), nil + + isIdempotent := c.dst.conds != nil && (c.dst.conds.GenerationMatch != 0 || c.dst.conds.DoesNotExist) + opts := makeStorageOpts(isIdempotent, c.dst.retry, c.dst.userProject) + return c.dst.c.tc.ComposeObject(ctx, req, opts...) } diff --git a/vendor/cloud.google.com/go/storage/doc.go b/vendor/cloud.google.com/go/storage/doc.go index 614ea11a590..8bf3098431e 100644 --- a/vendor/cloud.google.com/go/storage/doc.go +++ b/vendor/cloud.google.com/go/storage/doc.go @@ -19,156 +19,186 @@ Google Cloud Storage stores data in named objects, which are grouped into bucket More information about Google Cloud Storage is available at https://cloud.google.com/storage/docs. -See https://godoc.org/cloud.google.com/go for authentication, timeouts, +See https://pkg.go.dev/cloud.google.com/go for authentication, timeouts, connection pooling and similar aspects of this package. -All of the methods of this package use exponential backoff to retry calls that fail -with certain errors, as described in -https://cloud.google.com/storage/docs/exponential-backoff. Retrying continues -indefinitely unless the controlling context is canceled or the client is closed. See -context.WithTimeout and context.WithCancel. +# Creating a Client +To start working with this package, create a [Client]: -Creating a Client - -To start working with this package, create a client: - - ctx := context.Background() - client, err := storage.NewClient(ctx) - if err != nil { - // TODO: Handle error. - } + ctx := context.Background() + client, err := storage.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } -The client will use your default application credentials. +The client will use your default application credentials. Clients should be +reused instead of created as needed. The methods of [Client] are safe for +concurrent use by multiple goroutines. If you only wish to access public data, you can create an unauthenticated client with - client, err := storage.NewClient(ctx, option.WithoutAuthentication()) + client, err := storage.NewClient(ctx, option.WithoutAuthentication()) + +To use an emulator with this library, you can set the STORAGE_EMULATOR_HOST +environment variable to the address at which your emulator is running. This will +send requests to that address instead of to Cloud Storage. You can then create +and use a client as usual: + + // Set STORAGE_EMULATOR_HOST environment variable. + err := os.Setenv("STORAGE_EMULATOR_HOST", "localhost:9000") + if err != nil { + // TODO: Handle error. + } + + // Create client as usual. + client, err := storage.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + // This request is now directed to http://localhost:9000/storage/v1/b + // instead of https://storage.googleapis.com/storage/v1/b + if err := client.Bucket("my-bucket").Create(ctx, projectID, nil); err != nil { + // TODO: Handle error. + } + +Please note that there is no official emulator for Cloud Storage. -Buckets +# Buckets A Google Cloud Storage bucket is a collection of objects. To work with a bucket, make a bucket handle: - bkt := client.Bucket(bucketName) + bkt := client.Bucket(bucketName) A handle is a reference to a bucket. You can have a handle even if the bucket doesn't exist yet. To create a bucket in Google Cloud Storage, -call Create on the handle: +call [BucketHandle.Create]: - if err := bkt.Create(ctx, projectID, nil); err != nil { - // TODO: Handle error. - } + if err := bkt.Create(ctx, projectID, nil); err != nil { + // TODO: Handle error. + } Note that although buckets are associated with projects, bucket names are global across all projects. Each bucket has associated metadata, represented in this package by -BucketAttrs. The third argument to BucketHandle.Create allows you to set -the initial BucketAttrs of a bucket. To retrieve a bucket's attributes, use -Attrs: +[BucketAttrs]. The third argument to [BucketHandle.Create] allows you to set +the initial [BucketAttrs] of a bucket. To retrieve a bucket's attributes, use +[BucketHandle.Attrs]: - attrs, err := bkt.Attrs(ctx) - if err != nil { - // TODO: Handle error. - } - fmt.Printf("bucket %s, created at %s, is located in %s with storage class %s\n", - attrs.Name, attrs.Created, attrs.Location, attrs.StorageClass) + attrs, err := bkt.Attrs(ctx) + if err != nil { + // TODO: Handle error. + } + fmt.Printf("bucket %s, created at %s, is located in %s with storage class %s\n", + attrs.Name, attrs.Created, attrs.Location, attrs.StorageClass) -Objects +# Objects An object holds arbitrary data as a sequence of bytes, like a file. You refer to objects using a handle, just as with buckets, but unlike buckets you don't explicitly create an object. Instead, the first time you write -to an object it will be created. You can use the standard Go io.Reader -and io.Writer interfaces to read and write object data: - - obj := bkt.Object("data") - // Write something to obj. - // w implements io.Writer. - w := obj.NewWriter(ctx) - // Write some text to obj. This will either create the object or overwrite whatever is there already. - if _, err := fmt.Fprintf(w, "This object contains text.\n"); err != nil { - // TODO: Handle error. - } - // Close, just like writing a file. - if err := w.Close(); err != nil { - // TODO: Handle error. - } - - // Read it back. - r, err := obj.NewReader(ctx) - if err != nil { - // TODO: Handle error. - } - defer r.Close() - if _, err := io.Copy(os.Stdout, r); err != nil { - // TODO: Handle error. - } - // Prints "This object contains text." - -Objects also have attributes, which you can fetch with Attrs: - - objAttrs, err := obj.Attrs(ctx) - if err != nil { - // TODO: Handle error. - } - fmt.Printf("object %s has size %d and can be read using %s\n", - objAttrs.Name, objAttrs.Size, objAttrs.MediaLink) - -Listing objects - -Listing objects in a bucket is done with the Bucket.Objects method: - - query := &storage.Query{Prefix: ""} - - var names []string - it := bkt.Objects(ctx, query) - for { - attrs, err := it.Next() - if err == iterator.Done { - break - } - if err != nil { - log.Fatal(err) - } - names = append(names, attrs.Name) - } +to an object it will be created. You can use the standard Go [io.Reader] +and [io.Writer] interfaces to read and write object data: + + obj := bkt.Object("data") + // Write something to obj. + // w implements io.Writer. + w := obj.NewWriter(ctx) + // Write some text to obj. This will either create the object or overwrite whatever is there already. + if _, err := fmt.Fprintf(w, "This object contains text.\n"); err != nil { + // TODO: Handle error. + } + // Close, just like writing a file. + if err := w.Close(); err != nil { + // TODO: Handle error. + } + + // Read it back. + r, err := obj.NewReader(ctx) + if err != nil { + // TODO: Handle error. + } + defer r.Close() + if _, err := io.Copy(os.Stdout, r); err != nil { + // TODO: Handle error. + } + // Prints "This object contains text." + +Objects also have attributes, which you can fetch with [ObjectHandle.Attrs]: + + objAttrs, err := obj.Attrs(ctx) + if err != nil { + // TODO: Handle error. + } + fmt.Printf("object %s has size %d and can be read using %s\n", + objAttrs.Name, objAttrs.Size, objAttrs.MediaLink) + +# Listing objects + +Listing objects in a bucket is done with the [BucketHandle.Objects] method: + + query := &storage.Query{Prefix: ""} + + var names []string + it := bkt.Objects(ctx, query) + for { + attrs, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + log.Fatal(err) + } + names = append(names, attrs.Name) + } + +Objects are listed lexicographically by name. To filter objects +lexicographically, [Query.StartOffset] and/or [Query.EndOffset] can be used: + + query := &storage.Query{ + Prefix: "", + StartOffset: "bar/", // Only list objects lexicographically >= "bar/" + EndOffset: "foo/", // Only list objects lexicographically < "foo/" + } + + // ... as before If only a subset of object attributes is needed when listing, specifying this -subset using Query.SetAttrSelection may speed up the listing process: +subset using [Query.SetAttrSelection] may speed up the listing process: - query := &storage.Query{Prefix: ""} - query.SetAttrSelection([]string{"Name"}) + query := &storage.Query{Prefix: ""} + query.SetAttrSelection([]string{"Name"}) - // ... as before + // ... as before -ACLs +# ACLs Both objects and buckets have ACLs (Access Control Lists). An ACL is a list of ACLRules, each of which specifies the role of a user, group or project. ACLs are suitable for fine-grained control, but you may prefer using IAM to control -access at the project level (see -https://cloud.google.com/storage/docs/access-control/iam). +access at the project level (see [Cloud Storage IAM docs]. -To list the ACLs of a bucket or object, obtain an ACLHandle and call its List method: +To list the ACLs of a bucket or object, obtain an [ACLHandle] and call [ACLHandle.List]: - acls, err := obj.ACL().List(ctx) - if err != nil { - // TODO: Handle error. - } - for _, rule := range acls { - fmt.Printf("%s has role %s\n", rule.Entity, rule.Role) - } + acls, err := obj.ACL().List(ctx) + if err != nil { + // TODO: Handle error. + } + for _, rule := range acls { + fmt.Printf("%s has role %s\n", rule.Entity, rule.Role) + } You can also set and delete ACLs. -Conditions +# Conditions Every object has a generation and a metageneration. The generation changes whenever the content changes, and the metageneration changes whenever the -metadata changes. Conditions let you check these values before an operation; +metadata changes. [Conditions] let you check these values before an operation; the operation only executes if the conditions match. You can use conditions to prevent race conditions in read-modify-write operations. @@ -176,43 +206,123 @@ For example, say you've read an object's metadata into objAttrs. Now you want to write to that object, but only if its contents haven't changed since you read it. Here is how to express that: - w = obj.If(storage.Conditions{GenerationMatch: objAttrs.Generation}).NewWriter(ctx) - // Proceed with writing as above. + w = obj.If(storage.Conditions{GenerationMatch: objAttrs.Generation}).NewWriter(ctx) + // Proceed with writing as above. -Signed URLs +# Signed URLs You can obtain a URL that lets anyone read or write an object for a limited time. -You don't need to create a client to do this. See the documentation of -SignedURL for details. +Signing a URL requires credentials authorized to sign a URL. To use the same +authentication that was used when instantiating the Storage client, use +[BucketHandle.SignedURL]. - url, err := storage.SignedURL(bucketName, "shared-object", opts) - if err != nil { - // TODO: Handle error. - } - fmt.Println(url) + url, err := client.Bucket(bucketName).SignedURL(objectName, opts) + if err != nil { + // TODO: Handle error. + } + fmt.Println(url) -Post Policy V4 Signed Request +You can also sign a URL without creating a client. See the documentation of +[SignedURL] for details. + + url, err := storage.SignedURL(bucketName, "shared-object", opts) + if err != nil { + // TODO: Handle error. + } + fmt.Println(url) + +# Post Policy V4 Signed Request A type of signed request that allows uploads through HTML forms directly to Cloud Storage with temporary permission. Conditions can be applied to restrict how the HTML form is used and exercised by a user. -For more information, please see https://cloud.google.com/storage/docs/xml-api/post-object as well -as the documentation of GenerateSignedPostPolicyV4. - - pv4, err := storage.GenerateSignedPostPolicyV4(bucketName, objectName, opts) - if err != nil { - // TODO: Handle error. - } - fmt.Printf("URL: %s\nFields; %v\n", pv4.URL, pv4.Fields) - -Errors - -Errors returned by this client are often of the type [`googleapi.Error`](https://godoc.org/google.golang.org/api/googleapi#Error). -These errors can be introspected for more information by type asserting to the richer `googleapi.Error` type. For example: +For more information, please see the [XML POST Object docs] as well +as the documentation of [BucketHandle.GenerateSignedPostPolicyV4]. - if e, ok := err.(*googleapi.Error); ok { + pv4, err := client.Bucket(bucketName).GenerateSignedPostPolicyV4(objectName, opts) + if err != nil { + // TODO: Handle error. + } + fmt.Printf("URL: %s\nFields; %v\n", pv4.URL, pv4.Fields) + +# Credential requirements for signing + +If the GoogleAccessID and PrivateKey option fields are not provided, they will +be automatically detected by [BucketHandle.SignedURL] and +[BucketHandle.GenerateSignedPostPolicyV4] if any of the following are true: + - you are authenticated to the Storage Client with a service account's + downloaded private key, either directly in code or by setting the + GOOGLE_APPLICATION_CREDENTIALS environment variable (see [Other Environments]), + - your application is running on Google Compute Engine (GCE), or + - you are logged into [gcloud using application default credentials] + with [impersonation enabled]. + +Detecting GoogleAccessID may not be possible if you are authenticated using a +token source or using [option.WithHTTPClient]. In this case, you can provide a +service account email for GoogleAccessID and the client will attempt to sign +the URL or Post Policy using that service account. + +To generate the signature, you must have: + - iam.serviceAccounts.signBlob permissions on the GoogleAccessID service + account, and + - the [IAM Service Account Credentials API] enabled (unless authenticating + with a downloaded private key). + +# Errors + +Errors returned by this client are often of the type [googleapi.Error]. +These errors can be introspected for more information by using [errors.As] +with the richer [googleapi.Error] type. For example: + + var e *googleapi.Error + if ok := errors.As(err, &e); ok { if e.Code == 409 { ... } } + +# Retrying failed requests + +Methods in this package may retry calls that fail with transient errors. +Retrying continues indefinitely unless the controlling context is canceled, the +client is closed, or a non-transient error is received. To stop retries from +continuing, use context timeouts or cancellation. + +The retry strategy in this library follows best practices for Cloud Storage. By +default, operations are retried only if they are idempotent, and exponential +backoff with jitter is employed. In addition, errors are only retried if they +are defined as transient by the service. See the [Cloud Storage retry docs] +for more information. + +Users can configure non-default retry behavior for a single library call (using +[BucketHandle.Retryer] and [ObjectHandle.Retryer]) or for all calls made by a +client (using [Client.SetRetry]). For example: + + o := client.Bucket(bucket).Object(object).Retryer( + // Use WithBackoff to change the timing of the exponential backoff. + storage.WithBackoff(gax.Backoff{ + Initial: 2 * time.Second, + }), + // Use WithPolicy to configure the idempotency policy. RetryAlways will + // retry the operation even if it is non-idempotent. + storage.WithPolicy(storage.RetryAlways), + ) + + // Use a context timeout to set an overall deadline on the call, including all + // potential retries. + ctx, cancel := context.WithTimeout(ctx, 5*time.Second) + defer cancel() + + // Delete an object using the specified strategy and timeout. + if err := o.Delete(ctx); err != nil { + // Handle err. + } + +[Cloud Storage IAM docs]: https://cloud.google.com/storage/docs/access-control/iam +[XML POST Object docs]: https://cloud.google.com/storage/docs/xml-api/post-object +[Cloud Storage retry docs]: https://cloud.google.com/storage/docs/retry-strategy +[Other Environments]: https://cloud.google.com/storage/docs/authentication#libauth +[gcloud using application default credentials]: https://cloud.google.com/sdk/gcloud/reference/auth/application-default/login +[impersonation enabled]: https://cloud.google.com/sdk/gcloud/reference#--impersonate-service-account +[IAM Service Account Credentials API]: https://console.developers.google.com/apis/api/iamcredentials.googleapis.com/overview */ package storage // import "cloud.google.com/go/storage" diff --git a/vendor/cloud.google.com/go/storage/emulator_test.sh b/vendor/cloud.google.com/go/storage/emulator_test.sh new file mode 100644 index 00000000000..7bad7cf391c --- /dev/null +++ b/vendor/cloud.google.com/go/storage/emulator_test.sh @@ -0,0 +1,92 @@ +#!/bin/bash +# Copyright 2021 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License.. + +# Fail on any error +set -eo pipefail + +# Display commands being run +set -x + +# Only run on Go 1.17+ +min_minor_ver=17 + +v=`go version | { read _ _ v _; echo ${v#go}; }` +comps=(${v//./ }) +minor_ver=${comps[1]} + +if [ "$minor_ver" -lt "$min_minor_ver" ]; then + echo minor version $minor_ver, skipping + exit 0 +fi + +export STORAGE_EMULATOR_HOST="http://localhost:9000" +export STORAGE_EMULATOR_HOST_GRPC="localhost:8888" + +DEFAULT_IMAGE_NAME='gcr.io/cloud-devrel-public-resources/storage-testbench' +DEFAULT_IMAGE_TAG='latest' +DOCKER_IMAGE=${DEFAULT_IMAGE_NAME}:${DEFAULT_IMAGE_TAG} +CONTAINER_NAME=storage_testbench + +# Note: --net=host makes the container bind directly to the Docker host’s network, +# with no network isolation. If we were to use port-mapping instead, reset connection errors +# would be captured differently and cause unexpected test behaviour. +# The host networking driver works only on Linux hosts. +# See more about using host networking: https://docs.docker.com/network/host/ +DOCKER_NETWORK="--net=host" +# Note: We do not expect the RetryConformanceTest suite to pass on darwin due to +# differences in the network errors emitted by the system. +if [ `go env GOOS` == 'darwin' ]; then + DOCKER_NETWORK="-p 9000:9000 -p 8888:8888" +fi + +# Get the docker image for the testbench +docker pull $DOCKER_IMAGE + +# Start the testbench + +docker run --name $CONTAINER_NAME --rm -d $DOCKER_NETWORK $DOCKER_IMAGE +echo "Running the Cloud Storage testbench: $STORAGE_EMULATOR_HOST" +sleep 1 + +# Stop the testbench & cleanup environment variables +function cleanup() { + echo "Cleanup testbench" + docker stop $CONTAINER_NAME + unset STORAGE_EMULATOR_HOST; + unset STORAGE_EMULATOR_HOST_GRPC; +} +trap cleanup EXIT + +# Check that the server is running - retry several times to allow for start-up time +response=$(curl -w "%{http_code}\n" $STORAGE_EMULATOR_HOST --retry-connrefused --retry 5 -o /dev/null) + +if [[ $response != 200 ]] +then + echo "Testbench server did not start correctly" + exit 1 +fi + +# Start the gRPC server on port 8888. +echo "Starting the gRPC server on port 8888" +response=$(curl -w "%{http_code}\n" --retry 5 --retry-max-time 40 -o /dev/null "$STORAGE_EMULATOR_HOST/start_grpc?port=8888") + +if [[ $response != 200 ]] +then + echo "Testbench gRPC server did not start correctly" + exit 1 +fi + +# Run tests +go test -v -timeout 10m ./ -run="^Test(RetryConformance|.*Emulated)$" -short 2>&1 | tee -a sponge_log.log diff --git a/vendor/cloud.google.com/go/storage/go110.go b/vendor/cloud.google.com/go/storage/go110.go deleted file mode 100644 index c1273d59ade..00000000000 --- a/vendor/cloud.google.com/go/storage/go110.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2017 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// +build go1.10 - -package storage - -import ( - "net/url" - "strings" - - "google.golang.org/api/googleapi" -) - -func shouldRetry(err error) bool { - switch e := err.(type) { - case *googleapi.Error: - // Retry on 429 and 5xx, according to - // https://cloud.google.com/storage/docs/exponential-backoff. - return e.Code == 429 || (e.Code >= 500 && e.Code < 600) - case *url.Error: - // Retry socket-level errors ECONNREFUSED and ENETUNREACH (from syscall). - // Unfortunately the error type is unexported, so we resort to string - // matching. - retriable := []string{"connection refused", "connection reset"} - for _, s := range retriable { - if strings.Contains(e.Error(), s) { - return true - } - } - return false - case interface{ Temporary() bool }: - return e.Temporary() - default: - return false - } -} diff --git a/vendor/cloud.google.com/go/storage/grpc_client.go b/vendor/cloud.google.com/go/storage/grpc_client.go new file mode 100644 index 00000000000..4a44cee8b67 --- /dev/null +++ b/vendor/cloud.google.com/go/storage/grpc_client.go @@ -0,0 +1,1751 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package storage + +import ( + "context" + "encoding/base64" + "fmt" + "io" + "net/url" + "os" + + "cloud.google.com/go/internal/trace" + gapic "cloud.google.com/go/storage/internal/apiv2" + storagepb "cloud.google.com/go/storage/internal/apiv2/stubs" + "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/option/internaloption" + iampb "google.golang.org/genproto/googleapis/iam/v1" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/proto" + fieldmaskpb "google.golang.org/protobuf/types/known/fieldmaskpb" +) + +const ( + // defaultConnPoolSize is the default number of connections + // to initialize in the GAPIC gRPC connection pool. A larger + // connection pool may be necessary for jobs that require + // high throughput and/or leverage many concurrent streams. + // + // This is only used for the gRPC client. + defaultConnPoolSize = 4 + + // maxPerMessageWriteSize is the maximum amount of content that can be sent + // per WriteObjectRequest message. A buffer reaching this amount will + // precipitate a flush of the buffer. It is only used by the gRPC Writer + // implementation. + maxPerMessageWriteSize int = int(storagepb.ServiceConstants_MAX_WRITE_CHUNK_BYTES) + + // globalProjectAlias is the project ID alias used for global buckets. + // + // This is only used for the gRPC API. + globalProjectAlias = "_" + + // msgEntityNotSupported indicates ACL entites using project ID are not currently supported. + // + // This is only used for the gRPC API. + msgEntityNotSupported = "The gRPC API currently does not support ACL entities using project ID, use project numbers instead" +) + +// defaultGRPCOptions returns a set of the default client options +// for gRPC client initialization. +func defaultGRPCOptions() []option.ClientOption { + defaults := []option.ClientOption{ + option.WithGRPCConnectionPool(defaultConnPoolSize), + } + + // Set emulator options for gRPC if an emulator was specified. Note that in a + // hybrid client, STORAGE_EMULATOR_HOST will set the host to use for HTTP and + // STORAGE_EMULATOR_HOST_GRPC will set the host to use for gRPC (when using a + // local emulator, HTTP and gRPC must use different ports, so this is + // necessary). + // + // TODO: When the newHybridClient is not longer used, remove + // STORAGE_EMULATOR_HOST_GRPC and use STORAGE_EMULATOR_HOST for both the + // HTTP and gRPC based clients. + if host := os.Getenv("STORAGE_EMULATOR_HOST_GRPC"); host != "" { + // Strip the scheme from the emulator host. WithEndpoint does not take a + // scheme for gRPC. + host = stripScheme(host) + + defaults = append(defaults, + option.WithEndpoint(host), + option.WithGRPCDialOption(grpc.WithInsecure()), + option.WithoutAuthentication(), + ) + } else { + // Only enable DirectPath when the emulator is not being targeted. + defaults = append(defaults, internaloption.EnableDirectPath(true)) + } + + return defaults +} + +// grpcStorageClient is the gRPC API implementation of the transport-agnostic +// storageClient interface. +type grpcStorageClient struct { + raw *gapic.Client + settings *settings +} + +// newGRPCStorageClient initializes a new storageClient that uses the gRPC +// Storage API. +func newGRPCStorageClient(ctx context.Context, opts ...storageOption) (storageClient, error) { + s := initSettings(opts...) + s.clientOption = append(defaultGRPCOptions(), s.clientOption...) + + g, err := gapic.NewClient(ctx, s.clientOption...) + if err != nil { + return nil, err + } + + return &grpcStorageClient{ + raw: g, + settings: s, + }, nil +} + +func (c *grpcStorageClient) Close() error { + return c.raw.Close() +} + +// Top-level methods. + +func (c *grpcStorageClient) GetServiceAccount(ctx context.Context, project string, opts ...storageOption) (string, error) { + s := callSettings(c.settings, opts...) + req := &storagepb.GetServiceAccountRequest{ + Project: toProjectResource(project), + } + var resp *storagepb.ServiceAccount + err := run(ctx, func() error { + var err error + resp, err = c.raw.GetServiceAccount(ctx, req, s.gax...) + return err + }, s.retry, s.idempotent, setRetryHeaderGRPC(ctx)) + if err != nil { + return "", err + } + return resp.EmailAddress, err +} + +func (c *grpcStorageClient) CreateBucket(ctx context.Context, project, bucket string, attrs *BucketAttrs, opts ...storageOption) (*BucketAttrs, error) { + s := callSettings(c.settings, opts...) + b := attrs.toProtoBucket() + b.Name = bucket + // If there is lifecycle information but no location, explicitly set + // the location. This is a GCS quirk/bug. + if b.GetLocation() == "" && b.GetLifecycle() != nil { + b.Location = "US" + } + + req := &storagepb.CreateBucketRequest{ + Parent: toProjectResource(project), + Bucket: b, + BucketId: b.GetName(), + } + if attrs != nil { + req.PredefinedAcl = attrs.PredefinedACL + req.PredefinedDefaultObjectAcl = attrs.PredefinedDefaultObjectACL + } + + var battrs *BucketAttrs + err := run(ctx, func() error { + res, err := c.raw.CreateBucket(ctx, req, s.gax...) + + battrs = newBucketFromProto(res) + + return err + }, s.retry, s.idempotent, setRetryHeaderGRPC(ctx)) + + return battrs, err +} + +func (c *grpcStorageClient) ListBuckets(ctx context.Context, project string, opts ...storageOption) *BucketIterator { + s := callSettings(c.settings, opts...) + it := &BucketIterator{ + ctx: ctx, + projectID: project, + } + + var gitr *gapic.BucketIterator + fetch := func(pageSize int, pageToken string) (token string, err error) { + // Initialize GAPIC-based iterator when pageToken is empty, which + // indicates that this fetch call is attempting to get the first page. + // + // Note: Initializing the GAPIC-based iterator lazily is necessary to + // capture the BucketIterator.Prefix set by the user *after* the + // BucketIterator is returned to them from the veneer. + if pageToken == "" { + req := &storagepb.ListBucketsRequest{ + Parent: toProjectResource(it.projectID), + Prefix: it.Prefix, + } + gitr = c.raw.ListBuckets(it.ctx, req, s.gax...) + } + + var buckets []*storagepb.Bucket + var next string + err = run(it.ctx, func() error { + buckets, next, err = gitr.InternalFetch(pageSize, pageToken) + return err + }, s.retry, s.idempotent, setRetryHeaderGRPC(ctx)) + if err != nil { + return "", err + } + + for _, bkt := range buckets { + b := newBucketFromProto(bkt) + it.buckets = append(it.buckets, b) + } + + return next, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo( + fetch, + func() int { return len(it.buckets) }, + func() interface{} { b := it.buckets; it.buckets = nil; return b }) + + return it +} + +// Bucket methods. + +func (c *grpcStorageClient) DeleteBucket(ctx context.Context, bucket string, conds *BucketConditions, opts ...storageOption) error { + s := callSettings(c.settings, opts...) + req := &storagepb.DeleteBucketRequest{ + Name: bucketResourceName(globalProjectAlias, bucket), + } + if err := applyBucketCondsProto("grpcStorageClient.DeleteBucket", conds, req); err != nil { + return err + } + if s.userProject != "" { + ctx = setUserProjectMetadata(ctx, s.userProject) + } + + return run(ctx, func() error { + return c.raw.DeleteBucket(ctx, req, s.gax...) + }, s.retry, s.idempotent, setRetryHeaderGRPC(ctx)) +} + +func (c *grpcStorageClient) GetBucket(ctx context.Context, bucket string, conds *BucketConditions, opts ...storageOption) (*BucketAttrs, error) { + s := callSettings(c.settings, opts...) + req := &storagepb.GetBucketRequest{ + Name: bucketResourceName(globalProjectAlias, bucket), + ReadMask: &fieldmaskpb.FieldMask{Paths: []string{"*"}}, + } + if err := applyBucketCondsProto("grpcStorageClient.GetBucket", conds, req); err != nil { + return nil, err + } + if s.userProject != "" { + ctx = setUserProjectMetadata(ctx, s.userProject) + } + + var battrs *BucketAttrs + err := run(ctx, func() error { + res, err := c.raw.GetBucket(ctx, req, s.gax...) + + battrs = newBucketFromProto(res) + + return err + }, s.retry, s.idempotent, setRetryHeaderGRPC(ctx)) + + if s, ok := status.FromError(err); ok && s.Code() == codes.NotFound { + return nil, ErrBucketNotExist + } + + return battrs, err +} +func (c *grpcStorageClient) UpdateBucket(ctx context.Context, bucket string, uattrs *BucketAttrsToUpdate, conds *BucketConditions, opts ...storageOption) (*BucketAttrs, error) { + s := callSettings(c.settings, opts...) + b := uattrs.toProtoBucket() + b.Name = bucketResourceName(globalProjectAlias, bucket) + req := &storagepb.UpdateBucketRequest{ + Bucket: b, + PredefinedAcl: uattrs.PredefinedACL, + PredefinedDefaultObjectAcl: uattrs.PredefinedDefaultObjectACL, + } + if err := applyBucketCondsProto("grpcStorageClient.UpdateBucket", conds, req); err != nil { + return nil, err + } + if s.userProject != "" { + ctx = setUserProjectMetadata(ctx, s.userProject) + } + + var paths []string + fieldMask := &fieldmaskpb.FieldMask{ + Paths: paths, + } + if uattrs.CORS != nil { + fieldMask.Paths = append(fieldMask.Paths, "cors") + } + if uattrs.DefaultEventBasedHold != nil { + fieldMask.Paths = append(fieldMask.Paths, "default_event_based_hold") + } + if uattrs.RetentionPolicy != nil { + fieldMask.Paths = append(fieldMask.Paths, "retention_policy") + } + if uattrs.VersioningEnabled != nil { + fieldMask.Paths = append(fieldMask.Paths, "versioning") + } + if uattrs.RequesterPays != nil { + fieldMask.Paths = append(fieldMask.Paths, "billing") + } + if uattrs.BucketPolicyOnly != nil || uattrs.UniformBucketLevelAccess != nil || uattrs.PublicAccessPrevention != PublicAccessPreventionUnknown { + fieldMask.Paths = append(fieldMask.Paths, "iam_config") + } + if uattrs.Encryption != nil { + fieldMask.Paths = append(fieldMask.Paths, "encryption") + } + if uattrs.Lifecycle != nil { + fieldMask.Paths = append(fieldMask.Paths, "lifecycle") + } + if uattrs.Logging != nil { + fieldMask.Paths = append(fieldMask.Paths, "logging") + } + if uattrs.Website != nil { + fieldMask.Paths = append(fieldMask.Paths, "website") + } + if uattrs.PredefinedACL != "" { + // In cases where PredefinedACL is set, Acl is cleared. + fieldMask.Paths = append(fieldMask.Paths, "acl") + } + if uattrs.PredefinedDefaultObjectACL != "" { + // In cases where PredefinedDefaultObjectACL is set, DefaultObjectAcl is cleared. + fieldMask.Paths = append(fieldMask.Paths, "default_object_acl") + } + // Note: This API currently does not support entites using project ID. + // Use project numbers in ACL entities. Pending b/233617896. + if uattrs.acl != nil { + // In cases where acl is set by UpdateBucketACL method. + fieldMask.Paths = append(fieldMask.Paths, "acl") + } + if uattrs.defaultObjectACL != nil { + // In cases where defaultObjectACL is set by UpdateBucketACL method. + fieldMask.Paths = append(fieldMask.Paths, "default_object_acl") + } + if uattrs.StorageClass != "" { + fieldMask.Paths = append(fieldMask.Paths, "storage_class") + } + if uattrs.RPO != RPOUnknown { + fieldMask.Paths = append(fieldMask.Paths, "rpo") + } + if uattrs.Autoclass != nil { + fieldMask.Paths = append(fieldMask.Paths, "autoclass") + } + // TODO(cathyo): Handle labels. Pending b/230510191. + req.UpdateMask = fieldMask + + var battrs *BucketAttrs + err := run(ctx, func() error { + res, err := c.raw.UpdateBucket(ctx, req, s.gax...) + battrs = newBucketFromProto(res) + return err + }, s.retry, s.idempotent, setRetryHeaderGRPC(ctx)) + + return battrs, err +} +func (c *grpcStorageClient) LockBucketRetentionPolicy(ctx context.Context, bucket string, conds *BucketConditions, opts ...storageOption) error { + s := callSettings(c.settings, opts...) + req := &storagepb.LockBucketRetentionPolicyRequest{ + Bucket: bucketResourceName(globalProjectAlias, bucket), + } + if err := applyBucketCondsProto("grpcStorageClient.LockBucketRetentionPolicy", conds, req); err != nil { + return err + } + + return run(ctx, func() error { + _, err := c.raw.LockBucketRetentionPolicy(ctx, req, s.gax...) + return err + }, s.retry, s.idempotent, setRetryHeaderGRPC(ctx)) + +} +func (c *grpcStorageClient) ListObjects(ctx context.Context, bucket string, q *Query, opts ...storageOption) *ObjectIterator { + s := callSettings(c.settings, opts...) + it := &ObjectIterator{ + ctx: ctx, + } + if q != nil { + it.query = *q + } + req := &storagepb.ListObjectsRequest{ + Parent: bucketResourceName(globalProjectAlias, bucket), + Prefix: it.query.Prefix, + Delimiter: it.query.Delimiter, + Versions: it.query.Versions, + LexicographicStart: it.query.StartOffset, + LexicographicEnd: it.query.EndOffset, + IncludeTrailingDelimiter: it.query.IncludeTrailingDelimiter, + ReadMask: q.toFieldMask(), // a nil Query still results in a "*" FieldMask + } + if s.userProject != "" { + ctx = setUserProjectMetadata(ctx, s.userProject) + } + gitr := c.raw.ListObjects(it.ctx, req, s.gax...) + fetch := func(pageSize int, pageToken string) (token string, err error) { + var objects []*storagepb.Object + err = run(it.ctx, func() error { + objects, token, err = gitr.InternalFetch(pageSize, pageToken) + return err + }, s.retry, s.idempotent, setRetryHeaderGRPC(ctx)) + if err != nil { + if st, ok := status.FromError(err); ok && st.Code() == codes.NotFound { + err = ErrBucketNotExist + } + return "", err + } + + for _, obj := range objects { + b := newObjectFromProto(obj) + it.items = append(it.items, b) + } + + // Response is always non-nil after a successful request. + res := gitr.Response.(*storagepb.ListObjectsResponse) + for _, prefix := range res.GetPrefixes() { + it.items = append(it.items, &ObjectAttrs{Prefix: prefix}) + } + + return token, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo( + fetch, + func() int { return len(it.items) }, + func() interface{} { b := it.items; it.items = nil; return b }) + + return it +} + +// Object metadata methods. + +func (c *grpcStorageClient) DeleteObject(ctx context.Context, bucket, object string, gen int64, conds *Conditions, opts ...storageOption) error { + s := callSettings(c.settings, opts...) + req := &storagepb.DeleteObjectRequest{ + Bucket: bucketResourceName(globalProjectAlias, bucket), + Object: object, + } + if err := applyCondsProto("grpcStorageClient.DeleteObject", gen, conds, req); err != nil { + return err + } + if s.userProject != "" { + ctx = setUserProjectMetadata(ctx, s.userProject) + } + err := run(ctx, func() error { + return c.raw.DeleteObject(ctx, req, s.gax...) + }, s.retry, s.idempotent, setRetryHeaderGRPC(ctx)) + if s, ok := status.FromError(err); ok && s.Code() == codes.NotFound { + return ErrObjectNotExist + } + return err +} + +func (c *grpcStorageClient) GetObject(ctx context.Context, bucket, object string, gen int64, encryptionKey []byte, conds *Conditions, opts ...storageOption) (*ObjectAttrs, error) { + s := callSettings(c.settings, opts...) + req := &storagepb.GetObjectRequest{ + Bucket: bucketResourceName(globalProjectAlias, bucket), + Object: object, + // ProjectionFull by default. + ReadMask: &fieldmaskpb.FieldMask{Paths: []string{"*"}}, + } + if err := applyCondsProto("grpcStorageClient.GetObject", gen, conds, req); err != nil { + return nil, err + } + if s.userProject != "" { + ctx = setUserProjectMetadata(ctx, s.userProject) + } + if encryptionKey != nil { + req.CommonObjectRequestParams = toProtoCommonObjectRequestParams(encryptionKey) + } + + var attrs *ObjectAttrs + err := run(ctx, func() error { + res, err := c.raw.GetObject(ctx, req, s.gax...) + attrs = newObjectFromProto(res) + + return err + }, s.retry, s.idempotent, setRetryHeaderGRPC(ctx)) + + if s, ok := status.FromError(err); ok && s.Code() == codes.NotFound { + return nil, ErrObjectNotExist + } + + return attrs, err +} + +func (c *grpcStorageClient) UpdateObject(ctx context.Context, bucket, object string, uattrs *ObjectAttrsToUpdate, gen int64, encryptionKey []byte, conds *Conditions, opts ...storageOption) (*ObjectAttrs, error) { + s := callSettings(c.settings, opts...) + o := uattrs.toProtoObject(bucketResourceName(globalProjectAlias, bucket), object) + req := &storagepb.UpdateObjectRequest{ + Object: o, + PredefinedAcl: uattrs.PredefinedACL, + } + if err := applyCondsProto("grpcStorageClient.UpdateObject", gen, conds, req); err != nil { + return nil, err + } + if s.userProject != "" { + ctx = setUserProjectMetadata(ctx, s.userProject) + } + if encryptionKey != nil { + req.CommonObjectRequestParams = toProtoCommonObjectRequestParams(encryptionKey) + } + + fieldMask := &fieldmaskpb.FieldMask{Paths: nil} + if uattrs.EventBasedHold != nil { + fieldMask.Paths = append(fieldMask.Paths, "event_based_hold") + } + if uattrs.TemporaryHold != nil { + fieldMask.Paths = append(fieldMask.Paths, "temporary_hold") + } + if uattrs.ContentType != nil { + fieldMask.Paths = append(fieldMask.Paths, "content_type") + } + if uattrs.ContentLanguage != nil { + fieldMask.Paths = append(fieldMask.Paths, "content_language") + } + if uattrs.ContentEncoding != nil { + fieldMask.Paths = append(fieldMask.Paths, "content_encoding") + } + if uattrs.ContentDisposition != nil { + fieldMask.Paths = append(fieldMask.Paths, "content_disposition") + } + if uattrs.CacheControl != nil { + fieldMask.Paths = append(fieldMask.Paths, "cache_control") + } + if !uattrs.CustomTime.IsZero() { + fieldMask.Paths = append(fieldMask.Paths, "custom_time") + } + // Note: This API currently does not support entites using project ID. + // Use project numbers in ACL entities. Pending b/233617896. + if uattrs.ACL != nil || len(uattrs.PredefinedACL) > 0 { + fieldMask.Paths = append(fieldMask.Paths, "acl") + } + // TODO(cathyo): Handle metadata. Pending b/230510191. + + req.UpdateMask = fieldMask + + var attrs *ObjectAttrs + err := run(ctx, func() error { + res, err := c.raw.UpdateObject(ctx, req, s.gax...) + attrs = newObjectFromProto(res) + return err + }, s.retry, s.idempotent, setRetryHeaderGRPC(ctx)) + if e, ok := status.FromError(err); ok && e.Code() == codes.NotFound { + return nil, ErrObjectNotExist + } + + return attrs, err +} + +// Default Object ACL methods. + +func (c *grpcStorageClient) DeleteDefaultObjectACL(ctx context.Context, bucket string, entity ACLEntity, opts ...storageOption) error { + // There is no separate API for PATCH in gRPC. + // Make a GET call first to retrieve BucketAttrs. + attrs, err := c.GetBucket(ctx, bucket, nil, opts...) + if err != nil { + return err + } + // Delete the entity and copy other remaining ACL entities. + // Note: This API currently does not support entites using project ID. + // Use project numbers in ACL entities. Pending b/233617896. + // Return error if entity is not found or a project ID is used. + invalidEntity := true + var acl []ACLRule + for _, a := range attrs.DefaultObjectACL { + if a.Entity != entity { + acl = append(acl, a) + } + if a.Entity == entity { + invalidEntity = false + } + } + if invalidEntity { + return fmt.Errorf("storage: entity %v was not found on bucket %v, got %v. %v", entity, bucket, attrs.DefaultObjectACL, msgEntityNotSupported) + } + uattrs := &BucketAttrsToUpdate{defaultObjectACL: acl} + // Call UpdateBucket with a MetagenerationMatch precondition set. + if _, err = c.UpdateBucket(ctx, bucket, uattrs, &BucketConditions{MetagenerationMatch: attrs.MetaGeneration}, opts...); err != nil { + return err + } + return nil +} + +func (c *grpcStorageClient) ListDefaultObjectACLs(ctx context.Context, bucket string, opts ...storageOption) ([]ACLRule, error) { + attrs, err := c.GetBucket(ctx, bucket, nil, opts...) + if err != nil { + return nil, err + } + return attrs.DefaultObjectACL, nil +} + +func (c *grpcStorageClient) UpdateDefaultObjectACL(ctx context.Context, bucket string, entity ACLEntity, role ACLRole, opts ...storageOption) error { + // There is no separate API for PATCH in gRPC. + // Make a GET call first to retrieve BucketAttrs. + attrs, err := c.GetBucket(ctx, bucket, nil, opts...) + if err != nil { + return err + } + // Note: This API currently does not support entites using project ID. + // Use project numbers in ACL entities. Pending b/233617896. + var acl []ACLRule + aclRule := ACLRule{Entity: entity, Role: role} + acl = append(attrs.DefaultObjectACL, aclRule) + uattrs := &BucketAttrsToUpdate{defaultObjectACL: acl} + // Call UpdateBucket with a MetagenerationMatch precondition set. + if _, err = c.UpdateBucket(ctx, bucket, uattrs, &BucketConditions{MetagenerationMatch: attrs.MetaGeneration}, opts...); err != nil { + return err + } + return nil +} + +// Bucket ACL methods. + +func (c *grpcStorageClient) DeleteBucketACL(ctx context.Context, bucket string, entity ACLEntity, opts ...storageOption) error { + // There is no separate API for PATCH in gRPC. + // Make a GET call first to retrieve BucketAttrs. + attrs, err := c.GetBucket(ctx, bucket, nil, opts...) + if err != nil { + return err + } + // Delete the entity and copy other remaining ACL entities. + // Note: This API currently does not support entites using project ID. + // Use project numbers in ACL entities. Pending b/233617896. + // Return error if entity is not found or a project ID is used. + invalidEntity := true + var acl []ACLRule + for _, a := range attrs.ACL { + if a.Entity != entity { + acl = append(acl, a) + } + if a.Entity == entity { + invalidEntity = false + } + } + if invalidEntity { + return fmt.Errorf("storage: entity %v was not found on bucket %v, got %v. %v", entity, bucket, attrs.ACL, msgEntityNotSupported) + } + uattrs := &BucketAttrsToUpdate{acl: acl} + // Call UpdateBucket with a MetagenerationMatch precondition set. + if _, err = c.UpdateBucket(ctx, bucket, uattrs, &BucketConditions{MetagenerationMatch: attrs.MetaGeneration}, opts...); err != nil { + return err + } + return nil +} + +func (c *grpcStorageClient) ListBucketACLs(ctx context.Context, bucket string, opts ...storageOption) ([]ACLRule, error) { + attrs, err := c.GetBucket(ctx, bucket, nil, opts...) + if err != nil { + return nil, err + } + return attrs.ACL, nil +} + +func (c *grpcStorageClient) UpdateBucketACL(ctx context.Context, bucket string, entity ACLEntity, role ACLRole, opts ...storageOption) error { + // There is no separate API for PATCH in gRPC. + // Make a GET call first to retrieve BucketAttrs. + attrs, err := c.GetBucket(ctx, bucket, nil, opts...) + if err != nil { + return err + } + // Note: This API currently does not support entites using project ID. + // Use project numbers in ACL entities. Pending b/233617896. + var acl []ACLRule + aclRule := ACLRule{Entity: entity, Role: role} + acl = append(attrs.ACL, aclRule) + uattrs := &BucketAttrsToUpdate{acl: acl} + // Call UpdateBucket with a MetagenerationMatch precondition set. + if _, err = c.UpdateBucket(ctx, bucket, uattrs, &BucketConditions{MetagenerationMatch: attrs.MetaGeneration}, opts...); err != nil { + return err + } + return nil +} + +// Object ACL methods. + +func (c *grpcStorageClient) DeleteObjectACL(ctx context.Context, bucket, object string, entity ACLEntity, opts ...storageOption) error { + // There is no separate API for PATCH in gRPC. + // Make a GET call first to retrieve ObjectAttrs. + attrs, err := c.GetObject(ctx, bucket, object, defaultGen, nil, nil, opts...) + if err != nil { + return err + } + // Delete the entity and copy other remaining ACL entities. + // Note: This API currently does not support entites using project ID. + // Use project numbers in ACL entities. Pending b/233617896. + // Return error if entity is not found or a project ID is used. + invalidEntity := true + var acl []ACLRule + for _, a := range attrs.ACL { + if a.Entity != entity { + acl = append(acl, a) + } + if a.Entity == entity { + invalidEntity = false + } + } + if invalidEntity { + return fmt.Errorf("storage: entity %v was not found on bucket %v, got %v. %v", entity, bucket, attrs.ACL, msgEntityNotSupported) + } + uattrs := &ObjectAttrsToUpdate{ACL: acl} + // Call UpdateObject with the specified metageneration. + if _, err = c.UpdateObject(ctx, bucket, object, uattrs, defaultGen, nil, &Conditions{MetagenerationMatch: attrs.Metageneration}, opts...); err != nil { + return err + } + return nil +} + +// ListObjectACLs retrieves object ACL entries. By default, it operates on the latest generation of this object. +// Selecting a specific generation of this object is not currently supported by the client. +func (c *grpcStorageClient) ListObjectACLs(ctx context.Context, bucket, object string, opts ...storageOption) ([]ACLRule, error) { + o, err := c.GetObject(ctx, bucket, object, defaultGen, nil, nil, opts...) + if err != nil { + return nil, err + } + return o.ACL, nil +} + +func (c *grpcStorageClient) UpdateObjectACL(ctx context.Context, bucket, object string, entity ACLEntity, role ACLRole, opts ...storageOption) error { + // There is no separate API for PATCH in gRPC. + // Make a GET call first to retrieve ObjectAttrs. + attrs, err := c.GetObject(ctx, bucket, object, defaultGen, nil, nil, opts...) + if err != nil { + return err + } + // Note: This API currently does not support entites using project ID. + // Use project numbers in ACL entities. Pending b/233617896. + var acl []ACLRule + aclRule := ACLRule{Entity: entity, Role: role} + acl = append(attrs.ACL, aclRule) + uattrs := &ObjectAttrsToUpdate{ACL: acl} + // Call UpdateObject with the specified metageneration. + if _, err = c.UpdateObject(ctx, bucket, object, uattrs, defaultGen, nil, &Conditions{MetagenerationMatch: attrs.Metageneration}, opts...); err != nil { + return err + } + return nil +} + +// Media operations. + +func (c *grpcStorageClient) ComposeObject(ctx context.Context, req *composeObjectRequest, opts ...storageOption) (*ObjectAttrs, error) { + s := callSettings(c.settings, opts...) + if s.userProject != "" { + ctx = setUserProjectMetadata(ctx, s.userProject) + } + + dstObjPb := req.dstObject.attrs.toProtoObject(req.dstBucket) + dstObjPb.Name = req.dstObject.name + if err := applyCondsProto("ComposeObject destination", defaultGen, req.dstObject.conds, dstObjPb); err != nil { + return nil, err + } + if req.sendCRC32C { + dstObjPb.Checksums.Crc32C = &req.dstObject.attrs.CRC32C + } + + srcs := []*storagepb.ComposeObjectRequest_SourceObject{} + for _, src := range req.srcs { + srcObjPb := &storagepb.ComposeObjectRequest_SourceObject{Name: src.name} + if err := applyCondsProto("ComposeObject source", src.gen, src.conds, srcObjPb); err != nil { + return nil, err + } + srcs = append(srcs, srcObjPb) + } + + rawReq := &storagepb.ComposeObjectRequest{ + Destination: dstObjPb, + SourceObjects: srcs, + } + if req.predefinedACL != "" { + rawReq.DestinationPredefinedAcl = req.predefinedACL + } + if req.dstObject.encryptionKey != nil { + rawReq.CommonObjectRequestParams = toProtoCommonObjectRequestParams(req.dstObject.encryptionKey) + } + + var obj *storagepb.Object + var err error + if err := run(ctx, func() error { + obj, err = c.raw.ComposeObject(ctx, rawReq, s.gax...) + return err + }, s.retry, s.idempotent, setRetryHeaderGRPC(ctx)); err != nil { + return nil, err + } + + return newObjectFromProto(obj), nil +} +func (c *grpcStorageClient) RewriteObject(ctx context.Context, req *rewriteObjectRequest, opts ...storageOption) (*rewriteObjectResponse, error) { + s := callSettings(c.settings, opts...) + obj := req.dstObject.attrs.toProtoObject("") + call := &storagepb.RewriteObjectRequest{ + SourceBucket: bucketResourceName(globalProjectAlias, req.srcObject.bucket), + SourceObject: req.srcObject.name, + RewriteToken: req.token, + DestinationBucket: bucketResourceName(globalProjectAlias, req.dstObject.bucket), + DestinationName: req.dstObject.name, + Destination: obj, + DestinationKmsKey: req.dstObject.keyName, + DestinationPredefinedAcl: req.predefinedACL, + CommonObjectRequestParams: toProtoCommonObjectRequestParams(req.dstObject.encryptionKey), + } + + // The userProject, whether source or destination project, is decided by the code calling the interface. + if s.userProject != "" { + ctx = setUserProjectMetadata(ctx, s.userProject) + } + if err := applyCondsProto("Copy destination", defaultGen, req.dstObject.conds, call); err != nil { + return nil, err + } + if err := applySourceCondsProto(req.srcObject.gen, req.srcObject.conds, call); err != nil { + return nil, err + } + + if len(req.dstObject.encryptionKey) > 0 { + call.CommonObjectRequestParams = toProtoCommonObjectRequestParams(req.dstObject.encryptionKey) + } + if len(req.srcObject.encryptionKey) > 0 { + srcParams := toProtoCommonObjectRequestParams(req.srcObject.encryptionKey) + call.CopySourceEncryptionAlgorithm = srcParams.GetEncryptionAlgorithm() + call.CopySourceEncryptionKeyBytes = srcParams.GetEncryptionKeyBytes() + call.CopySourceEncryptionKeySha256Bytes = srcParams.GetEncryptionKeySha256Bytes() + } + + call.MaxBytesRewrittenPerCall = req.maxBytesRewrittenPerCall + + var res *storagepb.RewriteResponse + var err error + + retryCall := func() error { res, err = c.raw.RewriteObject(ctx, call, s.gax...); return err } + + if err := run(ctx, retryCall, s.retry, s.idempotent, setRetryHeaderGRPC(ctx)); err != nil { + return nil, err + } + + r := &rewriteObjectResponse{ + done: res.GetDone(), + written: res.GetTotalBytesRewritten(), + size: res.GetObjectSize(), + token: res.GetRewriteToken(), + resource: newObjectFromProto(res.GetResource()), + } + + return r, nil +} + +func (c *grpcStorageClient) NewRangeReader(ctx context.Context, params *newRangeReaderParams, opts ...storageOption) (r *Reader, err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.grpcStorageClient.NewRangeReader") + defer func() { trace.EndSpan(ctx, err) }() + + s := callSettings(c.settings, opts...) + + if s.userProject != "" { + ctx = setUserProjectMetadata(ctx, s.userProject) + } + + // A negative length means "read to the end of the object", but the + // read_limit field it corresponds to uses zero to mean the same thing. Thus + // we coerce the length to 0 to read to the end of the object. + if params.length < 0 { + params.length = 0 + } + + b := bucketResourceName(globalProjectAlias, params.bucket) + req := &storagepb.ReadObjectRequest{ + Bucket: b, + Object: params.object, + CommonObjectRequestParams: toProtoCommonObjectRequestParams(params.encryptionKey), + } + // The default is a negative value, which means latest. + if params.gen >= 0 { + req.Generation = params.gen + } + + // Define a function that initiates a Read with offset and length, assuming + // we have already read seen bytes. + reopen := func(seen int64) (*readStreamResponse, context.CancelFunc, error) { + // If the context has already expired, return immediately without making + // we call. + if err := ctx.Err(); err != nil { + return nil, nil, err + } + + cc, cancel := context.WithCancel(ctx) + + start := params.offset + seen + // Only set a ReadLimit if length is greater than zero, because zero + // means read it all. + if params.length > 0 { + req.ReadLimit = params.length - seen + } + req.ReadOffset = start + + if err := applyCondsProto("gRPCReader.reopen", params.gen, params.conds, req); err != nil { + cancel() + return nil, nil, err + } + + var stream storagepb.Storage_ReadObjectClient + var msg *storagepb.ReadObjectResponse + var err error + + err = run(cc, func() error { + stream, err = c.raw.ReadObject(cc, req, s.gax...) + if err != nil { + return err + } + + msg, err = stream.Recv() + // These types of errors show up on the Recv call, rather than the + // initialization of the stream via ReadObject above. + if s, ok := status.FromError(err); ok && s.Code() == codes.NotFound { + return ErrObjectNotExist + } + + return err + }, s.retry, s.idempotent, setRetryHeaderGRPC(ctx)) + if err != nil { + // Close the stream context we just created to ensure we don't leak + // resources. + cancel() + return nil, nil, err + } + + return &readStreamResponse{stream, msg}, cancel, nil + } + + res, cancel, err := reopen(0) + if err != nil { + return nil, err + } + + // The first message was Recv'd on stream open, use it to populate the + // object metadata. + msg := res.response + obj := msg.GetMetadata() + // This is the size of the entire object, even if only a range was requested. + size := obj.GetSize() + + r = &Reader{ + Attrs: ReaderObjectAttrs{ + Size: size, + ContentType: obj.GetContentType(), + ContentEncoding: obj.GetContentEncoding(), + CacheControl: obj.GetCacheControl(), + LastModified: obj.GetUpdateTime().AsTime(), + Metageneration: obj.GetMetageneration(), + Generation: obj.GetGeneration(), + }, + reader: &gRPCReader{ + stream: res.stream, + reopen: reopen, + cancel: cancel, + size: size, + // Store the content from the first Recv in the + // client buffer for reading later. + leftovers: msg.GetChecksummedData().GetContent(), + settings: s, + }, + } + + cr := msg.GetContentRange() + if cr != nil { + r.Attrs.StartOffset = cr.GetStart() + r.remain = cr.GetEnd() - cr.GetStart() + 1 + } else { + r.remain = size + } + + // Only support checksums when reading an entire object, not a range. + if checksums := msg.GetObjectChecksums(); checksums != nil && checksums.Crc32C != nil && params.offset == 0 && params.length == 0 { + r.wantCRC = checksums.GetCrc32C() + r.checkCRC = true + } + + return r, nil +} + +func (c *grpcStorageClient) OpenWriter(params *openWriterParams, opts ...storageOption) (*io.PipeWriter, error) { + s := callSettings(c.settings, opts...) + + var offset int64 + errorf := params.setError + progress := params.progress + setObj := params.setObj + + pr, pw := io.Pipe() + gw := newGRPCWriter(c, params, pr) + gw.settings = s + if s.userProject != "" { + gw.ctx = setUserProjectMetadata(gw.ctx, s.userProject) + } + + // This function reads the data sent to the pipe and sends sets of messages + // on the gRPC client-stream as the buffer is filled. + go func() { + defer close(params.donec) + + // Loop until there is an error or the Object has been finalized. + for { + // Note: This blocks until either the buffer is full or EOF is read. + recvd, doneReading, err := gw.read() + if err != nil { + err = checkCanceled(err) + errorf(err) + pr.CloseWithError(err) + return + } + + // The chunk buffer is full, but there is no end in sight. This + // means that a resumable upload will need to be used to send + // multiple chunks, until we are done reading data. Start a + // resumable upload if it has not already been started. + // Otherwise, all data will be sent over a single gRPC stream. + if !doneReading && gw.upid == "" { + err = gw.startResumableUpload() + if err != nil { + err = checkCanceled(err) + errorf(err) + pr.CloseWithError(err) + return + } + } + + o, off, finalized, err := gw.uploadBuffer(recvd, offset, doneReading) + if err != nil { + err = checkCanceled(err) + errorf(err) + pr.CloseWithError(err) + return + } + // At this point, the current buffer has been uploaded. Capture the + // committed offset here in case the upload was not finalized and + // another chunk is to be uploaded. + offset = off + progress(offset) + + // When we are done reading data and the chunk has been finalized, + // we are done. + if doneReading && finalized { + // Build Object from server's response. + setObj(newObjectFromProto(o)) + return + } + } + }() + + return pw, nil +} + +// IAM methods. + +func (c *grpcStorageClient) GetIamPolicy(ctx context.Context, resource string, version int32, opts ...storageOption) (*iampb.Policy, error) { + // TODO: Need a way to set UserProject, potentially in X-Goog-User-Project system parameter. + s := callSettings(c.settings, opts...) + req := &iampb.GetIamPolicyRequest{ + Resource: bucketResourceName(globalProjectAlias, resource), + Options: &iampb.GetPolicyOptions{ + RequestedPolicyVersion: version, + }, + } + var rp *iampb.Policy + err := run(ctx, func() error { + var err error + rp, err = c.raw.GetIamPolicy(ctx, req, s.gax...) + return err + }, s.retry, s.idempotent, setRetryHeaderGRPC(ctx)) + + return rp, err +} + +func (c *grpcStorageClient) SetIamPolicy(ctx context.Context, resource string, policy *iampb.Policy, opts ...storageOption) error { + // TODO: Need a way to set UserProject, potentially in X-Goog-User-Project system parameter. + s := callSettings(c.settings, opts...) + + req := &iampb.SetIamPolicyRequest{ + Resource: bucketResourceName(globalProjectAlias, resource), + Policy: policy, + } + + return run(ctx, func() error { + _, err := c.raw.SetIamPolicy(ctx, req, s.gax...) + return err + }, s.retry, s.idempotent, setRetryHeaderGRPC(ctx)) +} + +func (c *grpcStorageClient) TestIamPermissions(ctx context.Context, resource string, permissions []string, opts ...storageOption) ([]string, error) { + // TODO: Need a way to set UserProject, potentially in X-Goog-User-Project system parameter. + s := callSettings(c.settings, opts...) + req := &iampb.TestIamPermissionsRequest{ + Resource: bucketResourceName(globalProjectAlias, resource), + Permissions: permissions, + } + var res *iampb.TestIamPermissionsResponse + err := run(ctx, func() error { + var err error + res, err = c.raw.TestIamPermissions(ctx, req, s.gax...) + return err + }, s.retry, s.idempotent, setRetryHeaderGRPC(ctx)) + if err != nil { + return nil, err + } + return res.Permissions, nil +} + +// HMAC Key methods. + +func (c *grpcStorageClient) GetHMACKey(ctx context.Context, project, accessID string, opts ...storageOption) (*HMACKey, error) { + s := callSettings(c.settings, opts...) + req := &storagepb.GetHmacKeyRequest{ + AccessId: accessID, + Project: toProjectResource(project), + } + if s.userProject != "" { + ctx = setUserProjectMetadata(ctx, s.userProject) + } + var metadata *storagepb.HmacKeyMetadata + err := run(ctx, func() error { + var err error + metadata, err = c.raw.GetHmacKey(ctx, req, s.gax...) + return err + }, s.retry, s.idempotent, setRetryHeaderGRPC(ctx)) + if err != nil { + return nil, err + } + return toHMACKeyFromProto(metadata), nil +} + +func (c *grpcStorageClient) ListHMACKeys(ctx context.Context, project, serviceAccountEmail string, showDeletedKeys bool, opts ...storageOption) *HMACKeysIterator { + s := callSettings(c.settings, opts...) + req := &storagepb.ListHmacKeysRequest{ + Project: toProjectResource(project), + ServiceAccountEmail: serviceAccountEmail, + ShowDeletedKeys: showDeletedKeys, + } + if s.userProject != "" { + ctx = setUserProjectMetadata(ctx, s.userProject) + } + it := &HMACKeysIterator{ + ctx: ctx, + projectID: project, + retry: s.retry, + } + gitr := c.raw.ListHmacKeys(it.ctx, req, s.gax...) + fetch := func(pageSize int, pageToken string) (token string, err error) { + var hmacKeys []*storagepb.HmacKeyMetadata + err = run(it.ctx, func() error { + hmacKeys, token, err = gitr.InternalFetch(pageSize, pageToken) + return err + }, s.retry, s.idempotent, setRetryHeaderGRPC(ctx)) + if err != nil { + return "", err + } + for _, hkmd := range hmacKeys { + hk := toHMACKeyFromProto(hkmd) + it.hmacKeys = append(it.hmacKeys, hk) + } + + return token, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo( + fetch, + func() int { return len(it.hmacKeys) - it.index }, + func() interface{} { + prev := it.hmacKeys + it.hmacKeys = it.hmacKeys[:0] + it.index = 0 + return prev + }) + return it +} + +func (c *grpcStorageClient) UpdateHMACKey(ctx context.Context, project, serviceAccountEmail, accessID string, attrs *HMACKeyAttrsToUpdate, opts ...storageOption) (*HMACKey, error) { + s := callSettings(c.settings, opts...) + hk := &storagepb.HmacKeyMetadata{ + AccessId: accessID, + Project: toProjectResource(project), + ServiceAccountEmail: serviceAccountEmail, + State: string(attrs.State), + Etag: attrs.Etag, + } + var paths []string + fieldMask := &fieldmaskpb.FieldMask{ + Paths: paths, + } + if attrs.State != "" { + fieldMask.Paths = append(fieldMask.Paths, "state") + } + req := &storagepb.UpdateHmacKeyRequest{ + HmacKey: hk, + UpdateMask: fieldMask, + } + if s.userProject != "" { + ctx = setUserProjectMetadata(ctx, s.userProject) + } + var metadata *storagepb.HmacKeyMetadata + err := run(ctx, func() error { + var err error + metadata, err = c.raw.UpdateHmacKey(ctx, req, s.gax...) + return err + }, s.retry, s.idempotent, setRetryHeaderGRPC(ctx)) + if err != nil { + return nil, err + } + return toHMACKeyFromProto(metadata), nil +} + +func (c *grpcStorageClient) CreateHMACKey(ctx context.Context, project, serviceAccountEmail string, opts ...storageOption) (*HMACKey, error) { + s := callSettings(c.settings, opts...) + req := &storagepb.CreateHmacKeyRequest{ + Project: toProjectResource(project), + ServiceAccountEmail: serviceAccountEmail, + } + if s.userProject != "" { + ctx = setUserProjectMetadata(ctx, s.userProject) + } + var res *storagepb.CreateHmacKeyResponse + err := run(ctx, func() error { + var err error + res, err = c.raw.CreateHmacKey(ctx, req, s.gax...) + return err + }, s.retry, s.idempotent, setRetryHeaderGRPC(ctx)) + if err != nil { + return nil, err + } + key := toHMACKeyFromProto(res.Metadata) + key.Secret = base64.StdEncoding.EncodeToString(res.SecretKeyBytes) + + return key, nil +} + +func (c *grpcStorageClient) DeleteHMACKey(ctx context.Context, project string, accessID string, opts ...storageOption) error { + s := callSettings(c.settings, opts...) + req := &storagepb.DeleteHmacKeyRequest{ + AccessId: accessID, + Project: toProjectResource(project), + } + if s.userProject != "" { + ctx = setUserProjectMetadata(ctx, s.userProject) + } + return run(ctx, func() error { + return c.raw.DeleteHmacKey(ctx, req, s.gax...) + }, s.retry, s.idempotent, setRetryHeaderGRPC(ctx)) +} + +// Notification methods. + +func (c *grpcStorageClient) ListNotifications(ctx context.Context, bucket string, opts ...storageOption) (n map[string]*Notification, err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.grpcStorageClient.ListNotifications") + defer func() { trace.EndSpan(ctx, err) }() + + s := callSettings(c.settings, opts...) + if s.userProject != "" { + ctx = setUserProjectMetadata(ctx, s.userProject) + } + req := &storagepb.ListNotificationsRequest{ + Parent: bucketResourceName(globalProjectAlias, bucket), + } + var notifications []*storagepb.Notification + err = run(ctx, func() error { + gitr := c.raw.ListNotifications(ctx, req, s.gax...) + for { + // PageSize is not set and fallbacks to the API default pageSize of 100. + items, nextPageToken, err := gitr.InternalFetch(int(req.GetPageSize()), req.GetPageToken()) + if err != nil { + return err + } + notifications = append(notifications, items...) + // If there are no more results, nextPageToken is empty and err is nil. + if nextPageToken == "" { + return err + } + req.PageToken = nextPageToken + } + }, s.retry, s.idempotent, setRetryHeaderGRPC(ctx)) + if err != nil { + return nil, err + } + + return notificationsToMapFromProto(notifications), nil +} + +func (c *grpcStorageClient) CreateNotification(ctx context.Context, bucket string, n *Notification, opts ...storageOption) (ret *Notification, err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.grpcStorageClient.CreateNotification") + defer func() { trace.EndSpan(ctx, err) }() + + s := callSettings(c.settings, opts...) + req := &storagepb.CreateNotificationRequest{ + Parent: bucketResourceName(globalProjectAlias, bucket), + Notification: toProtoNotification(n), + } + var pbn *storagepb.Notification + err = run(ctx, func() error { + var err error + pbn, err = c.raw.CreateNotification(ctx, req, s.gax...) + return err + }, s.retry, s.idempotent, setRetryHeaderGRPC(ctx)) + if err != nil { + return nil, err + } + return toNotificationFromProto(pbn), err +} + +func (c *grpcStorageClient) DeleteNotification(ctx context.Context, bucket string, id string, opts ...storageOption) (err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.grpcStorageClient.DeleteNotification") + defer func() { trace.EndSpan(ctx, err) }() + + s := callSettings(c.settings, opts...) + req := &storagepb.DeleteNotificationRequest{Name: id} + return run(ctx, func() error { + return c.raw.DeleteNotification(ctx, req, s.gax...) + }, s.retry, s.idempotent, setRetryHeaderGRPC(ctx)) +} + +// setUserProjectMetadata appends a project ID to the outgoing Context metadata +// via the x-goog-user-project system parameter defined at +// https://cloud.google.com/apis/docs/system-parameters. This is only for +// billing purposes, and is generally optional, except for requester-pays +// buckets. +func setUserProjectMetadata(ctx context.Context, project string) context.Context { + return metadata.AppendToOutgoingContext(ctx, "x-goog-user-project", project) +} + +type readStreamResponse struct { + stream storagepb.Storage_ReadObjectClient + response *storagepb.ReadObjectResponse +} + +type gRPCReader struct { + seen, size int64 + stream storagepb.Storage_ReadObjectClient + reopen func(seen int64) (*readStreamResponse, context.CancelFunc, error) + leftovers []byte + cancel context.CancelFunc + settings *settings +} + +// Read reads bytes into the user's buffer from an open gRPC stream. +func (r *gRPCReader) Read(p []byte) (int, error) { + // No stream to read from, either never initiliazed or Close was called. + // Note: There is a potential concurrency issue if multiple routines are + // using the same reader. One encounters an error and the stream is closed + // and then reopened while the other routine attempts to read from it. + if r.stream == nil { + return 0, fmt.Errorf("reader has been closed") + } + + // The entire object has been read by this reader, return EOF. + if r.size != 0 && r.size == r.seen { + return 0, io.EOF + } + + var n int + // Read leftovers and return what was available to conform to the Reader + // interface: https://pkg.go.dev/io#Reader. + if len(r.leftovers) > 0 { + n = copy(p, r.leftovers) + r.seen += int64(n) + r.leftovers = r.leftovers[n:] + return n, nil + } + + // Attempt to Recv the next message on the stream. + msg, err := r.recv() + if err != nil { + return 0, err + } + + // TODO: Determine if we need to capture incremental CRC32C for this + // chunk. The Object CRC32C checksum is captured when directed to read + // the entire Object. If directed to read a range, we may need to + // calculate the range's checksum for verification if the checksum is + // present in the response here. + // TODO: Figure out if we need to support decompressive transcoding + // https://cloud.google.com/storage/docs/transcoding. + content := msg.GetChecksummedData().GetContent() + n = copy(p[n:], content) + leftover := len(content) - n + if leftover > 0 { + // Wasn't able to copy all of the data in the message, store for + // future Read calls. + r.leftovers = content[n:] + } + r.seen += int64(n) + + return n, nil +} + +// Close cancels the read stream's context in order for it to be closed and +// collected. +func (r *gRPCReader) Close() error { + if r.cancel != nil { + r.cancel() + } + r.stream = nil + return nil +} + +// recv attempts to Recv the next message on the stream. In the event +// that a retryable error is encountered, the stream will be closed, reopened, +// and Recv again. This will attempt to Recv until one of the following is true: +// +// * Recv is successful +// * A non-retryable error is encountered +// * The Reader's context is canceled +// +// The last error received is the one that is returned, which could be from +// an attempt to reopen the stream. +func (r *gRPCReader) recv() (*storagepb.ReadObjectResponse, error) { + msg, err := r.stream.Recv() + var shouldRetry = ShouldRetry + if r.settings.retry != nil && r.settings.retry.shouldRetry != nil { + shouldRetry = r.settings.retry.shouldRetry + } + if err != nil && shouldRetry(err) { + // This will "close" the existing stream and immediately attempt to + // reopen the stream, but will backoff if further attempts are necessary. + // Reopening the stream Recvs the first message, so if retrying is + // successful, the next logical chunk will be returned. + msg, err = r.reopenStream() + } + + return msg, err +} + +// reopenStream "closes" the existing stream and attempts to reopen a stream and +// sets the Reader's stream and cancelStream properties in the process. +func (r *gRPCReader) reopenStream() (*storagepb.ReadObjectResponse, error) { + // Close existing stream and initialize new stream with updated offset. + r.Close() + + res, cancel, err := r.reopen(r.seen) + if err != nil { + return nil, err + } + r.stream = res.stream + r.cancel = cancel + return res.response, nil +} + +func newGRPCWriter(c *grpcStorageClient, params *openWriterParams, r io.Reader) *gRPCWriter { + size := params.chunkSize + if params.chunkSize == 0 { + // TODO: Should we actually use the minimum of 256 KB here when the user + // indicates they want minimal memory usage? We cannot do a zero-copy, + // bufferless upload like HTTP/JSON can. + // TODO: We need to determine if we can avoid starting a + // resumable upload when the user *plans* to send more than bufSize but + // with a bufferless upload. + size = maxPerMessageWriteSize + } + + return &gRPCWriter{ + buf: make([]byte, size), + c: c, + ctx: params.ctx, + reader: r, + bucket: params.bucket, + attrs: params.attrs, + conds: params.conds, + encryptionKey: params.encryptionKey, + sendCRC32C: params.sendCRC32C, + } +} + +// gRPCWriter is a wrapper around the the gRPC client-stream API that manages +// sending chunks of data provided by the user over the stream. +type gRPCWriter struct { + c *grpcStorageClient + buf []byte + reader io.Reader + + ctx context.Context + + bucket string + attrs *ObjectAttrs + conds *Conditions + encryptionKey []byte + settings *settings + + sendCRC32C bool + + // The gRPC client-stream used for sending buffers. + stream storagepb.Storage_WriteObjectClient + + // The Resumable Upload ID started by a gRPC-based Writer. + upid string +} + +// startResumableUpload initializes a Resumable Upload with gRPC and sets the +// upload ID on the Writer. +func (w *gRPCWriter) startResumableUpload() error { + spec, err := w.writeObjectSpec() + if err != nil { + return err + } + return run(w.ctx, func() error { + upres, err := w.c.raw.StartResumableWrite(w.ctx, &storagepb.StartResumableWriteRequest{ + WriteObjectSpec: spec, + CommonObjectRequestParams: toProtoCommonObjectRequestParams(w.encryptionKey), + }) + w.upid = upres.GetUploadId() + return err + }, w.settings.retry, w.settings.idempotent, setRetryHeaderGRPC(w.ctx)) +} + +// queryProgress is a helper that queries the status of the resumable upload +// associated with the given upload ID. +func (w *gRPCWriter) queryProgress() (int64, error) { + var persistedSize int64 + err := run(w.ctx, func() error { + q, err := w.c.raw.QueryWriteStatus(w.ctx, &storagepb.QueryWriteStatusRequest{ + UploadId: w.upid, + }) + persistedSize = q.GetPersistedSize() + return err + }, w.settings.retry, true, setRetryHeaderGRPC(w.ctx)) + + // q.GetCommittedSize() will return 0 if q is nil. + return persistedSize, err +} + +// uploadBuffer opens a Write stream and uploads the buffer at the given offset (if +// uploading a chunk for a resumable uploadBuffer), and will mark the write as +// finished if we are done receiving data from the user. The resulting write +// offset after uploading the buffer is returned, as well as a boolean +// indicating if the Object has been finalized. If it has been finalized, the +// final Object will be returned as well. Finalizing the upload is primarily +// important for Resumable Uploads. A simple or multi-part upload will always +// be finalized once the entire buffer has been written. +func (w *gRPCWriter) uploadBuffer(recvd int, start int64, doneReading bool) (*storagepb.Object, int64, bool, error) { + var err error + var finishWrite bool + var sent, limit int = 0, maxPerMessageWriteSize + var shouldRetry = ShouldRetry + if w.settings.retry != nil && w.settings.retry.shouldRetry != nil { + shouldRetry = w.settings.retry.shouldRetry + } + offset := start + toWrite := w.buf[:recvd] + for { + first := sent == 0 + // This indicates that this is the last message and the remaining + // data fits in one message. + belowLimit := recvd-sent <= limit + if belowLimit { + limit = recvd - sent + } + if belowLimit && doneReading { + finishWrite = true + } + + // Prepare chunk section for upload. + data := toWrite[sent : sent+limit] + req := &storagepb.WriteObjectRequest{ + Data: &storagepb.WriteObjectRequest_ChecksummedData{ + ChecksummedData: &storagepb.ChecksummedData{ + Content: data, + }, + }, + WriteOffset: offset, + FinishWrite: finishWrite, + } + + // Open a new stream and set the first_message field on the request. + // The first message on the WriteObject stream must either be the + // Object or the Resumable Upload ID. + if first { + ctx := gapic.InsertMetadata(w.ctx, metadata.Pairs("x-goog-request-params", "bucket="+url.QueryEscape(w.bucket))) + w.stream, err = w.c.raw.WriteObject(ctx) + if err != nil { + return nil, 0, false, err + } + + if w.upid != "" { + req.FirstMessage = &storagepb.WriteObjectRequest_UploadId{UploadId: w.upid} + } else { + spec, err := w.writeObjectSpec() + if err != nil { + return nil, 0, false, err + } + req.FirstMessage = &storagepb.WriteObjectRequest_WriteObjectSpec{ + WriteObjectSpec: spec, + } + req.CommonObjectRequestParams = toProtoCommonObjectRequestParams(w.encryptionKey) + } + + // TODO: Currently the checksums are only sent on the first message + // of the stream, but in the future, we must also support sending it + // on the *last* message of the stream (instead of the first). + if w.sendCRC32C { + req.ObjectChecksums = &storagepb.ObjectChecksums{ + Crc32C: proto.Uint32(w.attrs.CRC32C), + } + } + if len(w.attrs.MD5) != 0 { + if cs := req.GetObjectChecksums(); cs == nil { + req.ObjectChecksums = &storagepb.ObjectChecksums{ + Md5Hash: w.attrs.MD5, + } + } else { + cs.Md5Hash = w.attrs.MD5 + } + } + } + + err = w.stream.Send(req) + if err == io.EOF { + // err was io.EOF. The client-side of a stream only gets an EOF on Send + // when the backend closes the stream and wants to return an error + // status. Closing the stream receives the status as an error. + _, err = w.stream.CloseAndRecv() + + // Retriable errors mean we should start over and attempt to + // resend the entire buffer via a new stream. + // If not retriable, falling through will return the error received + // from closing the stream. + if shouldRetry(err) { + sent = 0 + finishWrite = false + // TODO: Add test case for failure modes of querying progress. + offset, err = w.determineOffset(start) + if err == nil { + continue + } + } + } + if err != nil { + return nil, 0, false, err + } + + // Update the immediate stream's sent total and the upload offset with + // the data sent. + sent += len(data) + offset += int64(len(data)) + + // Not done sending data, do not attempt to commit it yet, loop around + // and send more data. + if recvd-sent > 0 { + continue + } + + // Done sending data. Close the stream to "commit" the data sent. + resp, finalized, err := w.commit() + // Retriable errors mean we should start over and attempt to + // resend the entire buffer via a new stream. + // If not retriable, falling through will return the error received + // from closing the stream. + if shouldRetry(err) { + sent = 0 + finishWrite = false + offset, err = w.determineOffset(start) + if err == nil { + continue + } + } + if err != nil { + return nil, 0, false, err + } + + return resp.GetResource(), offset, finalized, nil + } +} + +// determineOffset either returns the offset given to it in the case of a simple +// upload, or queries the write status in the case a resumable upload is being +// used. +func (w *gRPCWriter) determineOffset(offset int64) (int64, error) { + // For a Resumable Upload, we must start from however much data + // was committed. + if w.upid != "" { + committed, err := w.queryProgress() + if err != nil { + return 0, err + } + offset = committed + } + return offset, nil +} + +// commit closes the stream to commit the data sent and potentially receive +// the finalized object if finished uploading. If the last request sent +// indicated that writing was finished, the Object will be finalized and +// returned. If not, then the Object will be nil, and the boolean returned will +// be false. +func (w *gRPCWriter) commit() (*storagepb.WriteObjectResponse, bool, error) { + finalized := true + resp, err := w.stream.CloseAndRecv() + if err == io.EOF { + // Closing a stream for a resumable upload finish_write = false results + // in an EOF which can be ignored, as we aren't done uploading yet. + finalized = false + err = nil + } + // Drop the stream reference as it has been closed. + w.stream = nil + + return resp, finalized, err +} + +// writeObjectSpec constructs a WriteObjectSpec proto using the Writer's +// ObjectAttrs and applies its Conditions. This is only used for gRPC. +func (w *gRPCWriter) writeObjectSpec() (*storagepb.WriteObjectSpec, error) { + // To avoid modifying the ObjectAttrs embeded in the calling writer, deref + // the ObjectAttrs pointer to make a copy, then assign the desired name to + // the attribute. + attrs := *w.attrs + + spec := &storagepb.WriteObjectSpec{ + Resource: attrs.toProtoObject(w.bucket), + } + // WriteObject doesn't support the generation condition, so use default. + if err := applyCondsProto("WriteObject", defaultGen, w.conds, spec); err != nil { + return nil, err + } + return spec, nil +} + +// read copies the data in the reader to the given buffer and reports how much +// data was read into the buffer and if there is no more data to read (EOF). +// Furthermore, if the attrs.ContentType is unset, the first bytes of content +// will be sniffed for a matching content type. +func (w *gRPCWriter) read() (int, bool, error) { + if w.attrs.ContentType == "" { + w.reader, w.attrs.ContentType = gax.DetermineContentType(w.reader) + } + // Set n to -1 to start the Read loop. + var n, recvd int = -1, 0 + var err error + for err == nil && n != 0 { + // The routine blocks here until data is received. + n, err = w.reader.Read(w.buf[recvd:]) + recvd += n + } + var done bool + if err == io.EOF { + done = true + err = nil + } + return recvd, done, err +} + +func checkCanceled(err error) error { + if status.Code(err) == codes.Canceled { + return context.Canceled + } + + return err +} diff --git a/vendor/cloud.google.com/go/storage/hmac.go b/vendor/cloud.google.com/go/storage/hmac.go index 7d8185f37b8..422a7c2335b 100644 --- a/vendor/cloud.google.com/go/storage/hmac.go +++ b/vendor/cloud.google.com/go/storage/hmac.go @@ -20,6 +20,7 @@ import ( "fmt" "time" + storagepb "cloud.google.com/go/storage/internal/apiv2/stubs" "google.golang.org/api/iterator" raw "google.golang.org/api/storage/v1" ) @@ -89,8 +90,8 @@ type HMACKey struct { type HMACKeyHandle struct { projectID string accessID string - - raw *raw.ProjectsHmacKeysService + retry *retryConfig + tc storageClient } // HMACKeyHandle creates a handle that will be used for HMACKey operations. @@ -100,7 +101,8 @@ func (c *Client) HMACKeyHandle(projectID, accessID string) *HMACKeyHandle { return &HMACKeyHandle{ projectID: projectID, accessID: accessID, - raw: raw.NewProjectsHmacKeysService(c.raw), + retry: c.retry, + tc: c.tc, } } @@ -112,32 +114,15 @@ func (c *Client) HMACKeyHandle(projectID, accessID string) *HMACKeyHandle { // // This method is EXPERIMENTAL and subject to change or removal without notice. func (hkh *HMACKeyHandle) Get(ctx context.Context, opts ...HMACKeyOption) (*HMACKey, error) { - call := hkh.raw.Get(hkh.projectID, hkh.accessID) - desc := new(hmacKeyDesc) for _, opt := range opts { opt.withHMACKeyDesc(desc) } - if desc.userProjectID != "" { - call = call.UserProject(desc.userProjectID) - } - setClientHeader(call.Header()) - - var metadata *raw.HmacKeyMetadata - var err error - err = runWithRetry(ctx, func() error { - metadata, err = call.Context(ctx).Do() - return err - }) - if err != nil { - return nil, err - } + o := makeStorageOpts(true, hkh.retry, desc.userProjectID) + hk, err := hkh.tc.GetHMACKey(ctx, hkh.projectID, hkh.accessID, o...) - hkPb := &raw.HmacKey{ - Metadata: metadata, - } - return pbHmacKeyToHMACKey(hkPb, false) + return hk, err } // Delete invokes an RPC to delete the key referenced by accessID, on Google Cloud Storage. @@ -146,49 +131,59 @@ func (hkh *HMACKeyHandle) Get(ctx context.Context, opts ...HMACKeyOption) (*HMAC // // This method is EXPERIMENTAL and subject to change or removal without notice. func (hkh *HMACKeyHandle) Delete(ctx context.Context, opts ...HMACKeyOption) error { - delCall := hkh.raw.Delete(hkh.projectID, hkh.accessID) desc := new(hmacKeyDesc) for _, opt := range opts { opt.withHMACKeyDesc(desc) } - if desc.userProjectID != "" { - delCall = delCall.UserProject(desc.userProjectID) - } - setClientHeader(delCall.Header()) - return runWithRetry(ctx, func() error { - return delCall.Context(ctx).Do() - }) + o := makeStorageOpts(true, hkh.retry, desc.userProjectID) + return hkh.tc.DeleteHMACKey(ctx, hkh.projectID, hkh.accessID, o...) } -func pbHmacKeyToHMACKey(pb *raw.HmacKey, updatedTimeCanBeNil bool) (*HMACKey, error) { - pbmd := pb.Metadata - if pbmd == nil { +func toHMACKeyFromRaw(hk *raw.HmacKey, updatedTimeCanBeNil bool) (*HMACKey, error) { + hkmd := hk.Metadata + if hkmd == nil { return nil, errors.New("field Metadata cannot be nil") } - createdTime, err := time.Parse(time.RFC3339, pbmd.TimeCreated) + createdTime, err := time.Parse(time.RFC3339, hkmd.TimeCreated) if err != nil { - return nil, fmt.Errorf("field CreatedTime: %v", err) + return nil, fmt.Errorf("field CreatedTime: %w", err) } - updatedTime, err := time.Parse(time.RFC3339, pbmd.Updated) + updatedTime, err := time.Parse(time.RFC3339, hkmd.Updated) if err != nil && !updatedTimeCanBeNil { - return nil, fmt.Errorf("field UpdatedTime: %v", err) + return nil, fmt.Errorf("field UpdatedTime: %w", err) } - hmk := &HMACKey{ - AccessID: pbmd.AccessId, - Secret: pb.Secret, - Etag: pbmd.Etag, - ID: pbmd.Id, - State: HMACState(pbmd.State), - ProjectID: pbmd.ProjectId, + hmKey := &HMACKey{ + AccessID: hkmd.AccessId, + Secret: hk.Secret, + Etag: hkmd.Etag, + ID: hkmd.Id, + State: HMACState(hkmd.State), + ProjectID: hkmd.ProjectId, CreatedTime: createdTime, UpdatedTime: updatedTime, - ServiceAccountEmail: pbmd.ServiceAccountEmail, + ServiceAccountEmail: hkmd.ServiceAccountEmail, } - return hmk, nil + return hmKey, nil +} + +func toHMACKeyFromProto(pbmd *storagepb.HmacKeyMetadata) *HMACKey { + if pbmd == nil { + return nil + } + + return &HMACKey{ + AccessID: pbmd.GetAccessId(), + ID: pbmd.GetId(), + State: HMACState(pbmd.GetState()), + ProjectID: pbmd.GetProject(), + CreatedTime: convertProtoTime(pbmd.GetCreateTime()), + UpdatedTime: convertProtoTime(pbmd.GetUpdateTime()), + ServiceAccountEmail: pbmd.GetServiceAccountEmail(), + } } // CreateHMACKey invokes an RPC for Google Cloud Storage to create a new HMACKey. @@ -202,29 +197,14 @@ func (c *Client) CreateHMACKey(ctx context.Context, projectID, serviceAccountEma return nil, errors.New("storage: expecting a non-blank service account email") } - svc := raw.NewProjectsHmacKeysService(c.raw) - call := svc.Create(projectID, serviceAccountEmail) desc := new(hmacKeyDesc) for _, opt := range opts { opt.withHMACKeyDesc(desc) } - if desc.userProjectID != "" { - call = call.UserProject(desc.userProjectID) - } - - setClientHeader(call.Header()) - - var hkPb *raw.HmacKey - var err error - err = runWithRetry(ctx, func() error { - hkPb, err = call.Context(ctx).Do() - return err - }) - if err != nil { - return nil, err - } - return pbHmacKeyToHMACKey(hkPb, true) + o := makeStorageOpts(false, c.retry, desc.userProjectID) + hk, err := c.tc.CreateHMACKey(ctx, projectID, serviceAccountEmail, o...) + return hk, err } // HMACKeyAttrsToUpdate defines the attributes of an HMACKey that will be updated. @@ -246,34 +226,15 @@ func (h *HMACKeyHandle) Update(ctx context.Context, au HMACKeyAttrsToUpdate, opt return nil, fmt.Errorf("storage: invalid state %q for update, must be either %q or %q", au.State, Active, Inactive) } - call := h.raw.Update(h.projectID, h.accessID, &raw.HmacKeyMetadata{ - Etag: au.Etag, - State: string(au.State), - }) - desc := new(hmacKeyDesc) for _, opt := range opts { opt.withHMACKeyDesc(desc) } - if desc.userProjectID != "" { - call = call.UserProject(desc.userProjectID) - } - setClientHeader(call.Header()) - var metadata *raw.HmacKeyMetadata - var err error - err = runWithRetry(ctx, func() error { - metadata, err = call.Context(ctx).Do() - return err - }) - - if err != nil { - return nil, err - } - hkPb := &raw.HmacKey{ - Metadata: metadata, - } - return pbHmacKeyToHMACKey(hkPb, false) + isIdempotent := len(au.Etag) > 0 + o := makeStorageOpts(isIdempotent, h.retry, desc.userProjectID) + hk, err := h.tc.UpdateHMACKey(ctx, h.projectID, desc.forServiceAccountEmail, h.accessID, &au, o...) + return hk, err } // An HMACKeysIterator is an iterator over HMACKeys. @@ -290,6 +251,7 @@ type HMACKeysIterator struct { nextFunc func() error index int desc hmacKeyDesc + retry *retryConfig } // ListHMACKeys returns an iterator for listing HMACKeys. @@ -298,26 +260,13 @@ type HMACKeysIterator struct { // // This method is EXPERIMENTAL and subject to change or removal without notice. func (c *Client) ListHMACKeys(ctx context.Context, projectID string, opts ...HMACKeyOption) *HMACKeysIterator { - it := &HMACKeysIterator{ - ctx: ctx, - raw: raw.NewProjectsHmacKeysService(c.raw), - projectID: projectID, - } - + desc := new(hmacKeyDesc) for _, opt := range opts { - opt.withHMACKeyDesc(&it.desc) + opt.withHMACKeyDesc(desc) } - it.pageInfo, it.nextFunc = iterator.NewPageInfo( - it.fetch, - func() int { return len(it.hmacKeys) - it.index }, - func() interface{} { - prev := it.hmacKeys - it.hmacKeys = it.hmacKeys[:0] - it.index = 0 - return prev - }) - return it + o := makeStorageOpts(true, c.retry, desc.userProjectID) + return c.tc.ListHMACKeys(ctx, projectID, desc.forServiceAccountEmail, desc.showDeletedKeys, o...) } // Next returns the next result. Its second return value is iterator.Done if @@ -346,6 +295,8 @@ func (it *HMACKeysIterator) Next() (*HMACKey, error) { func (it *HMACKeysIterator) PageInfo() *iterator.PageInfo { return it.pageInfo } func (it *HMACKeysIterator) fetch(pageSize int, pageToken string) (token string, err error) { + // TODO: Remove fetch method upon integration. This method is internalized into + // httpStorageClient.ListHMACKeys() as it is the only caller. call := it.raw.List(it.projectID) setClientHeader(call.Header()) if pageToken != "" { @@ -366,19 +317,19 @@ func (it *HMACKeysIterator) fetch(pageSize int, pageToken string) (token string, ctx := it.ctx var resp *raw.HmacKeysMetadata - err = runWithRetry(it.ctx, func() error { + err = run(it.ctx, func() error { resp, err = call.Context(ctx).Do() return err - }) + }, it.retry, true, setRetryHeaderHTTP(call)) if err != nil { return "", err } for _, metadata := range resp.Items { - hkPb := &raw.HmacKey{ + hk := &raw.HmacKey{ Metadata: metadata, } - hkey, err := pbHmacKeyToHMACKey(hkPb, true) + hkey, err := toHMACKeyFromRaw(hk, true) if err != nil { return "", err } diff --git a/vendor/cloud.google.com/go/storage/http_client.go b/vendor/cloud.google.com/go/storage/http_client.go new file mode 100644 index 00000000000..fae96043a92 --- /dev/null +++ b/vendor/cloud.google.com/go/storage/http_client.go @@ -0,0 +1,1351 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package storage + +import ( + "context" + "encoding/base64" + "errors" + "fmt" + "io" + "io/ioutil" + "net/http" + "net/url" + "os" + "reflect" + "strconv" + "strings" + "time" + + "cloud.google.com/go/internal/optional" + "cloud.google.com/go/internal/trace" + "golang.org/x/oauth2/google" + "google.golang.org/api/googleapi" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/option/internaloption" + raw "google.golang.org/api/storage/v1" + "google.golang.org/api/transport" + htransport "google.golang.org/api/transport/http" + iampb "google.golang.org/genproto/googleapis/iam/v1" +) + +// httpStorageClient is the HTTP-JSON API implementation of the transport-agnostic +// storageClient interface. +// +// This is an experimental API and not intended for public use. +type httpStorageClient struct { + creds *google.Credentials + hc *http.Client + readHost string + raw *raw.Service + scheme string + settings *settings +} + +// newHTTPStorageClient initializes a new storageClient that uses the HTTP-JSON +// Storage API. +// +// This is an experimental API and not intended for public use. +func newHTTPStorageClient(ctx context.Context, opts ...storageOption) (storageClient, error) { + s := initSettings(opts...) + o := s.clientOption + + var creds *google.Credentials + // In general, it is recommended to use raw.NewService instead of htransport.NewClient + // since raw.NewService configures the correct default endpoints when initializing the + // internal http client. However, in our case, "NewRangeReader" in reader.go needs to + // access the http client directly to make requests, so we create the client manually + // here so it can be re-used by both reader.go and raw.NewService. This means we need to + // manually configure the default endpoint options on the http client. Furthermore, we + // need to account for STORAGE_EMULATOR_HOST override when setting the default endpoints. + if host := os.Getenv("STORAGE_EMULATOR_HOST"); host == "" { + // Prepend default options to avoid overriding options passed by the user. + o = append([]option.ClientOption{option.WithScopes(ScopeFullControl, "https://www.googleapis.com/auth/cloud-platform"), option.WithUserAgent(userAgent)}, o...) + + o = append(o, internaloption.WithDefaultEndpoint("https://storage.googleapis.com/storage/v1/")) + o = append(o, internaloption.WithDefaultMTLSEndpoint("https://storage.mtls.googleapis.com/storage/v1/")) + + // Don't error out here. The user may have passed in their own HTTP + // client which does not auth with ADC or other common conventions. + c, err := transport.Creds(ctx, o...) + if err == nil { + creds = c + o = append(o, internaloption.WithCredentials(creds)) + } + } else { + var hostURL *url.URL + + if strings.Contains(host, "://") { + h, err := url.Parse(host) + if err != nil { + return nil, err + } + hostURL = h + } else { + // Add scheme for user if not supplied in STORAGE_EMULATOR_HOST + // URL is only parsed correctly if it has a scheme, so we build it ourselves + hostURL = &url.URL{Scheme: "http", Host: host} + } + + hostURL.Path = "storage/v1/" + endpoint := hostURL.String() + + // Append the emulator host as default endpoint for the user + o = append([]option.ClientOption{option.WithoutAuthentication()}, o...) + + o = append(o, internaloption.WithDefaultEndpoint(endpoint)) + o = append(o, internaloption.WithDefaultMTLSEndpoint(endpoint)) + } + s.clientOption = o + + // htransport selects the correct endpoint among WithEndpoint (user override), WithDefaultEndpoint, and WithDefaultMTLSEndpoint. + hc, ep, err := htransport.NewClient(ctx, s.clientOption...) + if err != nil { + return nil, fmt.Errorf("dialing: %w", err) + } + // RawService should be created with the chosen endpoint to take account of user override. + rawService, err := raw.NewService(ctx, option.WithEndpoint(ep), option.WithHTTPClient(hc)) + if err != nil { + return nil, fmt.Errorf("storage client: %w", err) + } + // Update readHost and scheme with the chosen endpoint. + u, err := url.Parse(ep) + if err != nil { + return nil, fmt.Errorf("supplied endpoint %q is not valid: %w", ep, err) + } + + return &httpStorageClient{ + creds: creds, + hc: hc, + readHost: u.Host, + raw: rawService, + scheme: u.Scheme, + settings: s, + }, nil +} + +func (c *httpStorageClient) Close() error { + c.hc.CloseIdleConnections() + return nil +} + +// Top-level methods. + +func (c *httpStorageClient) GetServiceAccount(ctx context.Context, project string, opts ...storageOption) (string, error) { + s := callSettings(c.settings, opts...) + call := c.raw.Projects.ServiceAccount.Get(project) + var res *raw.ServiceAccount + err := run(ctx, func() error { + var err error + res, err = call.Context(ctx).Do() + return err + }, s.retry, s.idempotent, setRetryHeaderHTTP(call)) + if err != nil { + return "", err + } + return res.EmailAddress, nil +} + +func (c *httpStorageClient) CreateBucket(ctx context.Context, project, bucket string, attrs *BucketAttrs, opts ...storageOption) (*BucketAttrs, error) { + s := callSettings(c.settings, opts...) + var bkt *raw.Bucket + if attrs != nil { + bkt = attrs.toRawBucket() + } else { + bkt = &raw.Bucket{} + } + bkt.Name = bucket + // If there is lifecycle information but no location, explicitly set + // the location. This is a GCS quirk/bug. + if bkt.Location == "" && bkt.Lifecycle != nil { + bkt.Location = "US" + } + req := c.raw.Buckets.Insert(project, bkt) + setClientHeader(req.Header()) + if attrs != nil && attrs.PredefinedACL != "" { + req.PredefinedAcl(attrs.PredefinedACL) + } + if attrs != nil && attrs.PredefinedDefaultObjectACL != "" { + req.PredefinedDefaultObjectAcl(attrs.PredefinedDefaultObjectACL) + } + var battrs *BucketAttrs + err := run(ctx, func() error { + b, err := req.Context(ctx).Do() + if err != nil { + return err + } + battrs, err = newBucket(b) + return err + }, s.retry, s.idempotent, setRetryHeaderHTTP(req)) + return battrs, err +} + +func (c *httpStorageClient) ListBuckets(ctx context.Context, project string, opts ...storageOption) *BucketIterator { + s := callSettings(c.settings, opts...) + it := &BucketIterator{ + ctx: ctx, + projectID: project, + } + + fetch := func(pageSize int, pageToken string) (token string, err error) { + req := c.raw.Buckets.List(it.projectID) + setClientHeader(req.Header()) + req.Projection("full") + req.Prefix(it.Prefix) + req.PageToken(pageToken) + if pageSize > 0 { + req.MaxResults(int64(pageSize)) + } + var resp *raw.Buckets + err = run(it.ctx, func() error { + resp, err = req.Context(it.ctx).Do() + return err + }, s.retry, s.idempotent, setRetryHeaderHTTP(req)) + if err != nil { + return "", err + } + for _, item := range resp.Items { + b, err := newBucket(item) + if err != nil { + return "", err + } + it.buckets = append(it.buckets, b) + } + return resp.NextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo( + fetch, + func() int { return len(it.buckets) }, + func() interface{} { b := it.buckets; it.buckets = nil; return b }) + + return it +} + +// Bucket methods. + +func (c *httpStorageClient) DeleteBucket(ctx context.Context, bucket string, conds *BucketConditions, opts ...storageOption) error { + s := callSettings(c.settings, opts...) + req := c.raw.Buckets.Delete(bucket) + setClientHeader(req.Header()) + if err := applyBucketConds("httpStorageClient.DeleteBucket", conds, req); err != nil { + return err + } + if s.userProject != "" { + req.UserProject(s.userProject) + } + + return run(ctx, func() error { return req.Context(ctx).Do() }, s.retry, s.idempotent, setRetryHeaderHTTP(req)) +} + +func (c *httpStorageClient) GetBucket(ctx context.Context, bucket string, conds *BucketConditions, opts ...storageOption) (*BucketAttrs, error) { + s := callSettings(c.settings, opts...) + req := c.raw.Buckets.Get(bucket).Projection("full") + setClientHeader(req.Header()) + err := applyBucketConds("httpStorageClient.GetBucket", conds, req) + if err != nil { + return nil, err + } + if s.userProject != "" { + req.UserProject(s.userProject) + } + + var resp *raw.Bucket + err = run(ctx, func() error { + resp, err = req.Context(ctx).Do() + return err + }, s.retry, s.idempotent, setRetryHeaderHTTP(req)) + + var e *googleapi.Error + if ok := errors.As(err, &e); ok && e.Code == http.StatusNotFound { + return nil, ErrBucketNotExist + } + if err != nil { + return nil, err + } + return newBucket(resp) +} +func (c *httpStorageClient) UpdateBucket(ctx context.Context, bucket string, uattrs *BucketAttrsToUpdate, conds *BucketConditions, opts ...storageOption) (*BucketAttrs, error) { + s := callSettings(c.settings, opts...) + rb := uattrs.toRawBucket() + req := c.raw.Buckets.Patch(bucket, rb).Projection("full") + setClientHeader(req.Header()) + err := applyBucketConds("httpStorageClient.UpdateBucket", conds, req) + if err != nil { + return nil, err + } + if s.userProject != "" { + req.UserProject(s.userProject) + } + if uattrs != nil && uattrs.PredefinedACL != "" { + req.PredefinedAcl(uattrs.PredefinedACL) + } + if uattrs != nil && uattrs.PredefinedDefaultObjectACL != "" { + req.PredefinedDefaultObjectAcl(uattrs.PredefinedDefaultObjectACL) + } + + var rawBucket *raw.Bucket + err = run(ctx, func() error { + rawBucket, err = req.Context(ctx).Do() + return err + }, s.retry, s.idempotent, setRetryHeaderHTTP(req)) + if err != nil { + return nil, err + } + return newBucket(rawBucket) +} + +func (c *httpStorageClient) LockBucketRetentionPolicy(ctx context.Context, bucket string, conds *BucketConditions, opts ...storageOption) error { + s := callSettings(c.settings, opts...) + + var metageneration int64 + if conds != nil { + metageneration = conds.MetagenerationMatch + } + req := c.raw.Buckets.LockRetentionPolicy(bucket, metageneration) + + return run(ctx, func() error { + _, err := req.Context(ctx).Do() + return err + }, s.retry, s.idempotent, setRetryHeaderHTTP(req)) +} +func (c *httpStorageClient) ListObjects(ctx context.Context, bucket string, q *Query, opts ...storageOption) *ObjectIterator { + s := callSettings(c.settings, opts...) + it := &ObjectIterator{ + ctx: ctx, + } + if q != nil { + it.query = *q + } + fetch := func(pageSize int, pageToken string) (string, error) { + req := c.raw.Objects.List(bucket) + setClientHeader(req.Header()) + projection := it.query.Projection + if projection == ProjectionDefault { + projection = ProjectionFull + } + req.Projection(projection.String()) + req.Delimiter(it.query.Delimiter) + req.Prefix(it.query.Prefix) + req.StartOffset(it.query.StartOffset) + req.EndOffset(it.query.EndOffset) + req.Versions(it.query.Versions) + req.IncludeTrailingDelimiter(it.query.IncludeTrailingDelimiter) + if selection := it.query.toFieldSelection(); selection != "" { + req.Fields("nextPageToken", googleapi.Field(selection)) + } + req.PageToken(pageToken) + if s.userProject != "" { + req.UserProject(s.userProject) + } + if pageSize > 0 { + req.MaxResults(int64(pageSize)) + } + var resp *raw.Objects + var err error + err = run(it.ctx, func() error { + resp, err = req.Context(it.ctx).Do() + return err + }, s.retry, s.idempotent, setRetryHeaderHTTP(req)) + if err != nil { + var e *googleapi.Error + if ok := errors.As(err, &e); ok && e.Code == http.StatusNotFound { + err = ErrBucketNotExist + } + return "", err + } + for _, item := range resp.Items { + it.items = append(it.items, newObject(item)) + } + for _, prefix := range resp.Prefixes { + it.items = append(it.items, &ObjectAttrs{Prefix: prefix}) + } + return resp.NextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo( + fetch, + func() int { return len(it.items) }, + func() interface{} { b := it.items; it.items = nil; return b }) + + return it +} + +// Object metadata methods. + +func (c *httpStorageClient) DeleteObject(ctx context.Context, bucket, object string, gen int64, conds *Conditions, opts ...storageOption) error { + s := callSettings(c.settings, opts...) + req := c.raw.Objects.Delete(bucket, object).Context(ctx) + if err := applyConds("Delete", gen, conds, req); err != nil { + return err + } + if s.userProject != "" { + req.UserProject(s.userProject) + } + err := run(ctx, func() error { return req.Context(ctx).Do() }, s.retry, s.idempotent, setRetryHeaderHTTP(req)) + var e *googleapi.Error + if ok := errors.As(err, &e); ok && e.Code == http.StatusNotFound { + return ErrObjectNotExist + } + return err +} + +func (c *httpStorageClient) GetObject(ctx context.Context, bucket, object string, gen int64, encryptionKey []byte, conds *Conditions, opts ...storageOption) (*ObjectAttrs, error) { + s := callSettings(c.settings, opts...) + req := c.raw.Objects.Get(bucket, object).Projection("full").Context(ctx) + if err := applyConds("Attrs", gen, conds, req); err != nil { + return nil, err + } + if s.userProject != "" { + req.UserProject(s.userProject) + } + if err := setEncryptionHeaders(req.Header(), encryptionKey, false); err != nil { + return nil, err + } + var obj *raw.Object + var err error + err = run(ctx, func() error { + obj, err = req.Context(ctx).Do() + return err + }, s.retry, s.idempotent, setRetryHeaderHTTP(req)) + var e *googleapi.Error + if ok := errors.As(err, &e); ok && e.Code == http.StatusNotFound { + return nil, ErrObjectNotExist + } + if err != nil { + return nil, err + } + return newObject(obj), nil +} + +func (c *httpStorageClient) UpdateObject(ctx context.Context, bucket, object string, uattrs *ObjectAttrsToUpdate, gen int64, encryptionKey []byte, conds *Conditions, opts ...storageOption) (*ObjectAttrs, error) { + s := callSettings(c.settings, opts...) + + var attrs ObjectAttrs + // Lists of fields to send, and set to null, in the JSON. + var forceSendFields, nullFields []string + if uattrs.ContentType != nil { + attrs.ContentType = optional.ToString(uattrs.ContentType) + // For ContentType, sending the empty string is a no-op. + // Instead we send a null. + if attrs.ContentType == "" { + nullFields = append(nullFields, "ContentType") + } else { + forceSendFields = append(forceSendFields, "ContentType") + } + } + if uattrs.ContentLanguage != nil { + attrs.ContentLanguage = optional.ToString(uattrs.ContentLanguage) + // For ContentLanguage it's an error to send the empty string. + // Instead we send a null. + if attrs.ContentLanguage == "" { + nullFields = append(nullFields, "ContentLanguage") + } else { + forceSendFields = append(forceSendFields, "ContentLanguage") + } + } + if uattrs.ContentEncoding != nil { + attrs.ContentEncoding = optional.ToString(uattrs.ContentEncoding) + forceSendFields = append(forceSendFields, "ContentEncoding") + } + if uattrs.ContentDisposition != nil { + attrs.ContentDisposition = optional.ToString(uattrs.ContentDisposition) + forceSendFields = append(forceSendFields, "ContentDisposition") + } + if uattrs.CacheControl != nil { + attrs.CacheControl = optional.ToString(uattrs.CacheControl) + forceSendFields = append(forceSendFields, "CacheControl") + } + if uattrs.EventBasedHold != nil { + attrs.EventBasedHold = optional.ToBool(uattrs.EventBasedHold) + forceSendFields = append(forceSendFields, "EventBasedHold") + } + if uattrs.TemporaryHold != nil { + attrs.TemporaryHold = optional.ToBool(uattrs.TemporaryHold) + forceSendFields = append(forceSendFields, "TemporaryHold") + } + if !uattrs.CustomTime.IsZero() { + attrs.CustomTime = uattrs.CustomTime + forceSendFields = append(forceSendFields, "CustomTime") + } + if uattrs.Metadata != nil { + attrs.Metadata = uattrs.Metadata + if len(attrs.Metadata) == 0 { + // Sending the empty map is a no-op. We send null instead. + nullFields = append(nullFields, "Metadata") + } else { + forceSendFields = append(forceSendFields, "Metadata") + } + } + if uattrs.ACL != nil { + attrs.ACL = uattrs.ACL + // It's an error to attempt to delete the ACL, so + // we don't append to nullFields here. + forceSendFields = append(forceSendFields, "Acl") + } + rawObj := attrs.toRawObject(bucket) + rawObj.ForceSendFields = forceSendFields + rawObj.NullFields = nullFields + call := c.raw.Objects.Patch(bucket, object, rawObj).Projection("full").Context(ctx) + if err := applyConds("Update", gen, conds, call); err != nil { + return nil, err + } + if s.userProject != "" { + call.UserProject(s.userProject) + } + if uattrs.PredefinedACL != "" { + call.PredefinedAcl(uattrs.PredefinedACL) + } + if err := setEncryptionHeaders(call.Header(), encryptionKey, false); err != nil { + return nil, err + } + var obj *raw.Object + var err error + err = run(ctx, func() error { obj, err = call.Do(); return err }, s.retry, s.idempotent, setRetryHeaderHTTP(call)) + var e *googleapi.Error + if errors.As(err, &e) && e.Code == http.StatusNotFound { + return nil, ErrObjectNotExist + } + if err != nil { + return nil, err + } + return newObject(obj), nil +} + +// Default Object ACL methods. + +func (c *httpStorageClient) DeleteDefaultObjectACL(ctx context.Context, bucket string, entity ACLEntity, opts ...storageOption) error { + s := callSettings(c.settings, opts...) + req := c.raw.DefaultObjectAccessControls.Delete(bucket, string(entity)) + configureACLCall(ctx, s.userProject, req) + return run(ctx, func() error { return req.Context(ctx).Do() }, s.retry, s.idempotent, setRetryHeaderHTTP(req)) +} + +func (c *httpStorageClient) ListDefaultObjectACLs(ctx context.Context, bucket string, opts ...storageOption) ([]ACLRule, error) { + s := callSettings(c.settings, opts...) + var acls *raw.ObjectAccessControls + var err error + req := c.raw.DefaultObjectAccessControls.List(bucket) + configureACLCall(ctx, s.userProject, req) + err = run(ctx, func() error { + acls, err = req.Do() + return err + }, s.retry, true, setRetryHeaderHTTP(req)) + if err != nil { + return nil, err + } + return toObjectACLRules(acls.Items), nil +} +func (c *httpStorageClient) UpdateDefaultObjectACL(ctx context.Context, bucket string, entity ACLEntity, role ACLRole, opts ...storageOption) error { + s := callSettings(c.settings, opts...) + type setRequest interface { + Do(opts ...googleapi.CallOption) (*raw.ObjectAccessControl, error) + Header() http.Header + } + acl := &raw.ObjectAccessControl{ + Bucket: bucket, + Entity: string(entity), + Role: string(role), + } + var req setRequest + var err error + req = c.raw.DefaultObjectAccessControls.Update(bucket, string(entity), acl) + configureACLCall(ctx, s.userProject, req) + return run(ctx, func() error { + _, err = req.Do() + return err + }, s.retry, s.idempotent, setRetryHeaderHTTP(req)) +} + +// Bucket ACL methods. + +func (c *httpStorageClient) DeleteBucketACL(ctx context.Context, bucket string, entity ACLEntity, opts ...storageOption) error { + s := callSettings(c.settings, opts...) + req := c.raw.BucketAccessControls.Delete(bucket, string(entity)) + configureACLCall(ctx, s.userProject, req) + return run(ctx, func() error { return req.Context(ctx).Do() }, s.retry, s.idempotent, setRetryHeaderHTTP(req)) +} + +func (c *httpStorageClient) ListBucketACLs(ctx context.Context, bucket string, opts ...storageOption) ([]ACLRule, error) { + s := callSettings(c.settings, opts...) + var acls *raw.BucketAccessControls + var err error + req := c.raw.BucketAccessControls.List(bucket) + configureACLCall(ctx, s.userProject, req) + err = run(ctx, func() error { + acls, err = req.Do() + return err + }, s.retry, true, setRetryHeaderHTTP(req)) + if err != nil { + return nil, err + } + return toBucketACLRules(acls.Items), nil +} + +func (c *httpStorageClient) UpdateBucketACL(ctx context.Context, bucket string, entity ACLEntity, role ACLRole, opts ...storageOption) error { + s := callSettings(c.settings, opts...) + acl := &raw.BucketAccessControl{ + Bucket: bucket, + Entity: string(entity), + Role: string(role), + } + req := c.raw.BucketAccessControls.Update(bucket, string(entity), acl) + configureACLCall(ctx, s.userProject, req) + var err error + return run(ctx, func() error { + _, err = req.Do() + return err + }, s.retry, s.idempotent, setRetryHeaderHTTP(req)) +} + +// configureACLCall sets the context, user project and headers on the apiary library call. +// This will panic if the call does not have the correct methods. +func configureACLCall(ctx context.Context, userProject string, call interface{ Header() http.Header }) { + vc := reflect.ValueOf(call) + vc.MethodByName("Context").Call([]reflect.Value{reflect.ValueOf(ctx)}) + if userProject != "" { + vc.MethodByName("UserProject").Call([]reflect.Value{reflect.ValueOf(userProject)}) + } + setClientHeader(call.Header()) +} + +// Object ACL methods. + +func (c *httpStorageClient) DeleteObjectACL(ctx context.Context, bucket, object string, entity ACLEntity, opts ...storageOption) error { + s := callSettings(c.settings, opts...) + req := c.raw.ObjectAccessControls.Delete(bucket, object, string(entity)) + configureACLCall(ctx, s.userProject, req) + return run(ctx, func() error { return req.Context(ctx).Do() }, s.retry, s.idempotent, setRetryHeaderHTTP(req)) +} + +// ListObjectACLs retrieves object ACL entries. By default, it operates on the latest generation of this object. +// Selecting a specific generation of this object is not currently supported by the client. +func (c *httpStorageClient) ListObjectACLs(ctx context.Context, bucket, object string, opts ...storageOption) ([]ACLRule, error) { + s := callSettings(c.settings, opts...) + var acls *raw.ObjectAccessControls + var err error + req := c.raw.ObjectAccessControls.List(bucket, object) + configureACLCall(ctx, s.userProject, req) + err = run(ctx, func() error { + acls, err = req.Do() + return err + }, s.retry, s.idempotent, setRetryHeaderHTTP(req)) + if err != nil { + return nil, err + } + return toObjectACLRules(acls.Items), nil +} + +func (c *httpStorageClient) UpdateObjectACL(ctx context.Context, bucket, object string, entity ACLEntity, role ACLRole, opts ...storageOption) error { + s := callSettings(c.settings, opts...) + type setRequest interface { + Do(opts ...googleapi.CallOption) (*raw.ObjectAccessControl, error) + Header() http.Header + } + + acl := &raw.ObjectAccessControl{ + Bucket: bucket, + Entity: string(entity), + Role: string(role), + } + var req setRequest + var err error + req = c.raw.ObjectAccessControls.Update(bucket, object, string(entity), acl) + configureACLCall(ctx, s.userProject, req) + return run(ctx, func() error { + _, err = req.Do() + return err + }, s.retry, s.idempotent, setRetryHeaderHTTP(req)) +} + +// Media operations. + +func (c *httpStorageClient) ComposeObject(ctx context.Context, req *composeObjectRequest, opts ...storageOption) (*ObjectAttrs, error) { + s := callSettings(c.settings, opts...) + rawReq := &raw.ComposeRequest{} + // Compose requires a non-empty Destination, so we always set it, + // even if the caller-provided ObjectAttrs is the zero value. + rawReq.Destination = req.dstObject.attrs.toRawObject(req.dstBucket) + if req.sendCRC32C { + rawReq.Destination.Crc32c = encodeUint32(req.dstObject.attrs.CRC32C) + } + for _, src := range req.srcs { + srcObj := &raw.ComposeRequestSourceObjects{ + Name: src.name, + } + if err := applyConds("ComposeFrom source", src.gen, src.conds, composeSourceObj{srcObj}); err != nil { + return nil, err + } + rawReq.SourceObjects = append(rawReq.SourceObjects, srcObj) + } + + call := c.raw.Objects.Compose(req.dstBucket, req.dstObject.name, rawReq).Context(ctx) + if err := applyConds("ComposeFrom destination", defaultGen, req.dstObject.conds, call); err != nil { + return nil, err + } + if s.userProject != "" { + call.UserProject(s.userProject) + } + if req.predefinedACL != "" { + call.DestinationPredefinedAcl(req.predefinedACL) + } + if err := setEncryptionHeaders(call.Header(), req.dstObject.encryptionKey, false); err != nil { + return nil, err + } + var obj *raw.Object + setClientHeader(call.Header()) + + var err error + retryCall := func() error { obj, err = call.Do(); return err } + + if err := run(ctx, retryCall, s.retry, s.idempotent, setRetryHeaderHTTP(call)); err != nil { + return nil, err + } + return newObject(obj), nil +} +func (c *httpStorageClient) RewriteObject(ctx context.Context, req *rewriteObjectRequest, opts ...storageOption) (*rewriteObjectResponse, error) { + s := callSettings(c.settings, opts...) + rawObject := req.dstObject.attrs.toRawObject("") + call := c.raw.Objects.Rewrite(req.srcObject.bucket, req.srcObject.name, req.dstObject.bucket, req.dstObject.name, rawObject) + + call.Context(ctx).Projection("full") + if req.token != "" { + call.RewriteToken(req.token) + } + if req.dstObject.keyName != "" { + call.DestinationKmsKeyName(req.dstObject.keyName) + } + if req.predefinedACL != "" { + call.DestinationPredefinedAcl(req.predefinedACL) + } + if err := applyConds("Copy destination", defaultGen, req.dstObject.conds, call); err != nil { + return nil, err + } + if err := applySourceConds(req.srcObject.gen, req.srcObject.conds, call); err != nil { + return nil, err + } + if s.userProject != "" { + call.UserProject(s.userProject) + } + // Set destination encryption headers. + if err := setEncryptionHeaders(call.Header(), req.dstObject.encryptionKey, false); err != nil { + return nil, err + } + // Set source encryption headers. + if err := setEncryptionHeaders(call.Header(), req.srcObject.encryptionKey, true); err != nil { + return nil, err + } + + if req.maxBytesRewrittenPerCall != 0 { + call.MaxBytesRewrittenPerCall(req.maxBytesRewrittenPerCall) + } + + var res *raw.RewriteResponse + var err error + setClientHeader(call.Header()) + + retryCall := func() error { res, err = call.Do(); return err } + + if err := run(ctx, retryCall, s.retry, s.idempotent, setRetryHeaderHTTP(call)); err != nil { + return nil, err + } + + r := &rewriteObjectResponse{ + done: res.Done, + written: res.TotalBytesRewritten, + size: res.ObjectSize, + token: res.RewriteToken, + resource: newObject(res.Resource), + } + + return r, nil +} + +func (c *httpStorageClient) NewRangeReader(ctx context.Context, params *newRangeReaderParams, opts ...storageOption) (r *Reader, err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.httpStorageClient.NewRangeReader") + defer func() { trace.EndSpan(ctx, err) }() + + s := callSettings(c.settings, opts...) + + u := &url.URL{ + Scheme: c.scheme, + Host: c.readHost, + Path: fmt.Sprintf("/%s/%s", params.bucket, params.object), + } + verb := "GET" + if params.length == 0 { + verb = "HEAD" + } + req, err := http.NewRequest(verb, u.String(), nil) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if s.userProject != "" { + req.Header.Set("X-Goog-User-Project", s.userProject) + } + if params.readCompressed { + req.Header.Set("Accept-Encoding", "gzip") + } + if err := setEncryptionHeaders(req.Header, params.encryptionKey, false); err != nil { + return nil, err + } + + // Define a function that initiates a Read with offset and length, assuming we + // have already read seen bytes. + reopen := func(seen int64) (*http.Response, error) { + // If the context has already expired, return immediately without making a + // call. + if err := ctx.Err(); err != nil { + return nil, err + } + start := params.offset + seen + if params.length < 0 && start < 0 { + req.Header.Set("Range", fmt.Sprintf("bytes=%d", start)) + } else if params.length < 0 && start > 0 { + req.Header.Set("Range", fmt.Sprintf("bytes=%d-", start)) + } else if params.length > 0 { + // The end character isn't affected by how many bytes we've seen. + req.Header.Set("Range", fmt.Sprintf("bytes=%d-%d", start, params.offset+params.length-1)) + } + // We wait to assign conditions here because the generation number can change in between reopen() runs. + if err := setConditionsHeaders(req.Header, params.conds); err != nil { + return nil, err + } + // If an object generation is specified, include generation as query string parameters. + if params.gen >= 0 { + req.URL.RawQuery = fmt.Sprintf("generation=%d", params.gen) + } + + var res *http.Response + err = run(ctx, func() error { + res, err = c.hc.Do(req) + if err != nil { + return err + } + if res.StatusCode == http.StatusNotFound { + res.Body.Close() + return ErrObjectNotExist + } + if res.StatusCode < 200 || res.StatusCode > 299 { + body, _ := ioutil.ReadAll(res.Body) + res.Body.Close() + return &googleapi.Error{ + Code: res.StatusCode, + Header: res.Header, + Body: string(body), + } + } + + partialContentNotSatisfied := + !decompressiveTranscoding(res) && + start > 0 && params.length != 0 && + res.StatusCode != http.StatusPartialContent + + if partialContentNotSatisfied { + res.Body.Close() + return errors.New("storage: partial request not satisfied") + } + + // With "Content-Encoding": "gzip" aka decompressive transcoding, GCS serves + // back the whole file regardless of the range count passed in as per: + // https://cloud.google.com/storage/docs/transcoding#range, + // thus we have to manually move the body forward by seen bytes. + if decompressiveTranscoding(res) && seen > 0 { + _, _ = io.CopyN(ioutil.Discard, res.Body, seen) + } + + // If a generation hasn't been specified, and this is the first response we get, let's record the + // generation. In future requests we'll use this generation as a precondition to avoid data races. + if params.gen < 0 && res.Header.Get("X-Goog-Generation") != "" { + gen64, err := strconv.ParseInt(res.Header.Get("X-Goog-Generation"), 10, 64) + if err != nil { + return err + } + params.gen = gen64 + } + return nil + }, s.retry, s.idempotent, setRetryHeaderHTTP(nil)) + if err != nil { + return nil, err + } + return res, nil + } + + res, err := reopen(0) + if err != nil { + return nil, err + } + var ( + size int64 // total size of object, even if a range was requested. + checkCRC bool + crc uint32 + startOffset int64 // non-zero if range request. + ) + if res.StatusCode == http.StatusPartialContent { + cr := strings.TrimSpace(res.Header.Get("Content-Range")) + if !strings.HasPrefix(cr, "bytes ") || !strings.Contains(cr, "/") { + return nil, fmt.Errorf("storage: invalid Content-Range %q", cr) + } + // Content range is formatted -/. We take + // the total size. + size, err = strconv.ParseInt(cr[strings.LastIndex(cr, "/")+1:], 10, 64) + if err != nil { + return nil, fmt.Errorf("storage: invalid Content-Range %q", cr) + } + + dashIndex := strings.Index(cr, "-") + if dashIndex >= 0 { + startOffset, err = strconv.ParseInt(cr[len("bytes="):dashIndex], 10, 64) + if err != nil { + return nil, fmt.Errorf("storage: invalid Content-Range %q: %w", cr, err) + } + } + } else { + size = res.ContentLength + // Check the CRC iff all of the following hold: + // - We asked for content (length != 0). + // - We got all the content (status != PartialContent). + // - The server sent a CRC header. + // - The Go http stack did not uncompress the file. + // - We were not served compressed data that was uncompressed on download. + // The problem with the last two cases is that the CRC will not match -- GCS + // computes it on the compressed contents, but we compute it on the + // uncompressed contents. + if params.length != 0 && !res.Uncompressed && !uncompressedByServer(res) { + crc, checkCRC = parseCRC32c(res) + } + } + + remain := res.ContentLength + body := res.Body + if params.length == 0 { + remain = 0 + body.Close() + body = emptyBody + } + var metaGen int64 + if res.Header.Get("X-Goog-Metageneration") != "" { + metaGen, err = strconv.ParseInt(res.Header.Get("X-Goog-Metageneration"), 10, 64) + if err != nil { + return nil, err + } + } + + var lm time.Time + if res.Header.Get("Last-Modified") != "" { + lm, err = http.ParseTime(res.Header.Get("Last-Modified")) + if err != nil { + return nil, err + } + } + + attrs := ReaderObjectAttrs{ + Size: size, + ContentType: res.Header.Get("Content-Type"), + ContentEncoding: res.Header.Get("Content-Encoding"), + CacheControl: res.Header.Get("Cache-Control"), + LastModified: lm, + StartOffset: startOffset, + Generation: params.gen, + Metageneration: metaGen, + } + return &Reader{ + Attrs: attrs, + size: size, + remain: remain, + wantCRC: crc, + checkCRC: checkCRC, + reader: &httpReader{ + reopen: reopen, + body: body, + }, + }, nil +} + +func (c *httpStorageClient) OpenWriter(params *openWriterParams, opts ...storageOption) (*io.PipeWriter, error) { + s := callSettings(c.settings, opts...) + errorf := params.setError + setObj := params.setObj + progress := params.progress + attrs := params.attrs + + mediaOpts := []googleapi.MediaOption{ + googleapi.ChunkSize(params.chunkSize), + } + if c := attrs.ContentType; c != "" { + mediaOpts = append(mediaOpts, googleapi.ContentType(c)) + } + if params.chunkRetryDeadline != 0 { + mediaOpts = append(mediaOpts, googleapi.ChunkRetryDeadline(params.chunkRetryDeadline)) + } + + pr, pw := io.Pipe() + + go func() { + defer close(params.donec) + + rawObj := attrs.toRawObject(params.bucket) + if params.sendCRC32C { + rawObj.Crc32c = encodeUint32(attrs.CRC32C) + } + if attrs.MD5 != nil { + rawObj.Md5Hash = base64.StdEncoding.EncodeToString(attrs.MD5) + } + call := c.raw.Objects.Insert(params.bucket, rawObj). + Media(pr, mediaOpts...). + Projection("full"). + Context(params.ctx). + Name(params.attrs.Name) + call.ProgressUpdater(func(n, _ int64) { progress(n) }) + + if attrs.KMSKeyName != "" { + call.KmsKeyName(attrs.KMSKeyName) + } + if attrs.PredefinedACL != "" { + call.PredefinedAcl(attrs.PredefinedACL) + } + if err := setEncryptionHeaders(call.Header(), params.encryptionKey, false); err != nil { + errorf(err) + pr.CloseWithError(err) + return + } + var resp *raw.Object + err := applyConds("NewWriter", defaultGen, params.conds, call) + if err == nil { + if s.userProject != "" { + call.UserProject(s.userProject) + } + // TODO(tritone): Remove this code when Uploads begin to support + // retry attempt header injection with "client header" injection. + setClientHeader(call.Header()) + + // The internals that perform call.Do automatically retry both the initial + // call to set up the upload as well as calls to upload individual chunks + // for a resumable upload (as long as the chunk size is non-zero). Hence + // there is no need to add retries here. + + // Retry only when the operation is idempotent or the retry policy is RetryAlways. + var useRetry bool + if (s.retry == nil || s.retry.policy == RetryIdempotent) && s.idempotent { + useRetry = true + } else if s.retry != nil && s.retry.policy == RetryAlways { + useRetry = true + } + if useRetry { + if s.retry != nil { + call.WithRetry(s.retry.backoff, s.retry.shouldRetry) + } else { + call.WithRetry(nil, nil) + } + } + resp, err = call.Do() + } + if err != nil { + errorf(err) + pr.CloseWithError(err) + return + } + setObj(newObject(resp)) + }() + + return pw, nil +} + +// IAM methods. + +func (c *httpStorageClient) GetIamPolicy(ctx context.Context, resource string, version int32, opts ...storageOption) (*iampb.Policy, error) { + s := callSettings(c.settings, opts...) + call := c.raw.Buckets.GetIamPolicy(resource).OptionsRequestedPolicyVersion(int64(version)) + setClientHeader(call.Header()) + if s.userProject != "" { + call.UserProject(s.userProject) + } + var rp *raw.Policy + err := run(ctx, func() error { + var err error + rp, err = call.Context(ctx).Do() + return err + }, s.retry, s.idempotent, setRetryHeaderHTTP(call)) + if err != nil { + return nil, err + } + return iamFromStoragePolicy(rp), nil +} + +func (c *httpStorageClient) SetIamPolicy(ctx context.Context, resource string, policy *iampb.Policy, opts ...storageOption) error { + s := callSettings(c.settings, opts...) + + rp := iamToStoragePolicy(policy) + call := c.raw.Buckets.SetIamPolicy(resource, rp) + setClientHeader(call.Header()) + if s.userProject != "" { + call.UserProject(s.userProject) + } + + return run(ctx, func() error { + _, err := call.Context(ctx).Do() + return err + }, s.retry, s.idempotent, setRetryHeaderHTTP(call)) +} + +func (c *httpStorageClient) TestIamPermissions(ctx context.Context, resource string, permissions []string, opts ...storageOption) ([]string, error) { + s := callSettings(c.settings, opts...) + call := c.raw.Buckets.TestIamPermissions(resource, permissions) + setClientHeader(call.Header()) + if s.userProject != "" { + call.UserProject(s.userProject) + } + var res *raw.TestIamPermissionsResponse + err := run(ctx, func() error { + var err error + res, err = call.Context(ctx).Do() + return err + }, s.retry, s.idempotent, setRetryHeaderHTTP(call)) + if err != nil { + return nil, err + } + return res.Permissions, nil +} + +// HMAC Key methods. + +func (c *httpStorageClient) GetHMACKey(ctx context.Context, project, accessID string, opts ...storageOption) (*HMACKey, error) { + s := callSettings(c.settings, opts...) + call := c.raw.Projects.HmacKeys.Get(project, accessID) + if s.userProject != "" { + call = call.UserProject(s.userProject) + } + + var metadata *raw.HmacKeyMetadata + var err error + if err := run(ctx, func() error { + metadata, err = call.Context(ctx).Do() + return err + }, s.retry, s.idempotent, setRetryHeaderHTTP(call)); err != nil { + return nil, err + } + hk := &raw.HmacKey{ + Metadata: metadata, + } + return toHMACKeyFromRaw(hk, false) +} + +func (c *httpStorageClient) ListHMACKeys(ctx context.Context, project, serviceAccountEmail string, showDeletedKeys bool, opts ...storageOption) *HMACKeysIterator { + s := callSettings(c.settings, opts...) + it := &HMACKeysIterator{ + ctx: ctx, + raw: c.raw.Projects.HmacKeys, + projectID: project, + retry: s.retry, + } + fetch := func(pageSize int, pageToken string) (token string, err error) { + call := c.raw.Projects.HmacKeys.List(project) + setClientHeader(call.Header()) + if pageToken != "" { + call = call.PageToken(pageToken) + } + if pageSize > 0 { + call = call.MaxResults(int64(pageSize)) + } + if showDeletedKeys { + call = call.ShowDeletedKeys(true) + } + if s.userProject != "" { + call = call.UserProject(s.userProject) + } + if serviceAccountEmail != "" { + call = call.ServiceAccountEmail(serviceAccountEmail) + } + + var resp *raw.HmacKeysMetadata + err = run(it.ctx, func() error { + resp, err = call.Context(it.ctx).Do() + return err + }, s.retry, s.idempotent, setRetryHeaderHTTP(call)) + if err != nil { + return "", err + } + + for _, metadata := range resp.Items { + hk := &raw.HmacKey{ + Metadata: metadata, + } + hkey, err := toHMACKeyFromRaw(hk, true) + if err != nil { + return "", err + } + it.hmacKeys = append(it.hmacKeys, hkey) + } + return resp.NextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo( + fetch, + func() int { return len(it.hmacKeys) - it.index }, + func() interface{} { + prev := it.hmacKeys + it.hmacKeys = it.hmacKeys[:0] + it.index = 0 + return prev + }) + return it +} + +func (c *httpStorageClient) UpdateHMACKey(ctx context.Context, project, serviceAccountEmail, accessID string, attrs *HMACKeyAttrsToUpdate, opts ...storageOption) (*HMACKey, error) { + s := callSettings(c.settings, opts...) + call := c.raw.Projects.HmacKeys.Update(project, accessID, &raw.HmacKeyMetadata{ + Etag: attrs.Etag, + State: string(attrs.State), + }) + if s.userProject != "" { + call = call.UserProject(s.userProject) + } + + var metadata *raw.HmacKeyMetadata + var err error + if err := run(ctx, func() error { + metadata, err = call.Context(ctx).Do() + return err + }, s.retry, s.idempotent, setRetryHeaderHTTP(call)); err != nil { + return nil, err + } + hk := &raw.HmacKey{ + Metadata: metadata, + } + return toHMACKeyFromRaw(hk, false) +} + +func (c *httpStorageClient) CreateHMACKey(ctx context.Context, project, serviceAccountEmail string, opts ...storageOption) (*HMACKey, error) { + s := callSettings(c.settings, opts...) + call := c.raw.Projects.HmacKeys.Create(project, serviceAccountEmail) + if s.userProject != "" { + call = call.UserProject(s.userProject) + } + + var hk *raw.HmacKey + if err := run(ctx, func() error { + h, err := call.Context(ctx).Do() + hk = h + return err + }, s.retry, s.idempotent, setRetryHeaderHTTP(call)); err != nil { + return nil, err + } + return toHMACKeyFromRaw(hk, true) +} + +func (c *httpStorageClient) DeleteHMACKey(ctx context.Context, project string, accessID string, opts ...storageOption) error { + s := callSettings(c.settings, opts...) + call := c.raw.Projects.HmacKeys.Delete(project, accessID) + if s.userProject != "" { + call = call.UserProject(s.userProject) + } + return run(ctx, func() error { + return call.Context(ctx).Do() + }, s.retry, s.idempotent, setRetryHeaderHTTP(call)) +} + +// Notification methods. + +// ListNotifications returns all the Notifications configured for this bucket, as a map indexed by notification ID. +// +// Note: This API does not support pagination. However, entity limits cap the number of notifications on a single bucket, +// so all results will be returned in the first response. See https://cloud.google.com/storage/quotas#buckets. +func (c *httpStorageClient) ListNotifications(ctx context.Context, bucket string, opts ...storageOption) (n map[string]*Notification, err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.httpStorageClient.ListNotifications") + defer func() { trace.EndSpan(ctx, err) }() + + s := callSettings(c.settings, opts...) + call := c.raw.Notifications.List(bucket) + if s.userProject != "" { + call.UserProject(s.userProject) + } + var res *raw.Notifications + err = run(ctx, func() error { + res, err = call.Context(ctx).Do() + return err + }, s.retry, true, setRetryHeaderHTTP(call)) + if err != nil { + return nil, err + } + return notificationsToMap(res.Items), nil +} + +func (c *httpStorageClient) CreateNotification(ctx context.Context, bucket string, n *Notification, opts ...storageOption) (ret *Notification, err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.httpStorageClient.CreateNotification") + defer func() { trace.EndSpan(ctx, err) }() + + s := callSettings(c.settings, opts...) + call := c.raw.Notifications.Insert(bucket, toRawNotification(n)) + if s.userProject != "" { + call.UserProject(s.userProject) + } + var rn *raw.Notification + err = run(ctx, func() error { + rn, err = call.Context(ctx).Do() + return err + }, s.retry, s.idempotent, setRetryHeaderHTTP(call)) + if err != nil { + return nil, err + } + return toNotification(rn), nil +} + +func (c *httpStorageClient) DeleteNotification(ctx context.Context, bucket string, id string, opts ...storageOption) (err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.httpStorageClient.DeleteNotification") + defer func() { trace.EndSpan(ctx, err) }() + + s := callSettings(c.settings, opts...) + call := c.raw.Notifications.Delete(bucket, id) + if s.userProject != "" { + call.UserProject(s.userProject) + } + return run(ctx, func() error { + return call.Context(ctx).Do() + }, s.retry, s.idempotent, setRetryHeaderHTTP(call)) +} + +type httpReader struct { + body io.ReadCloser + seen int64 + reopen func(seen int64) (*http.Response, error) +} + +func (r *httpReader) Read(p []byte) (int, error) { + n := 0 + for len(p[n:]) > 0 { + m, err := r.body.Read(p[n:]) + n += m + r.seen += int64(m) + if err == nil || err == io.EOF { + return n, err + } + // Read failed (likely due to connection issues), but we will try to reopen + // the pipe and continue. Send a ranged read request that takes into account + // the number of bytes we've already seen. + res, err := r.reopen(r.seen) + if err != nil { + // reopen already retries + return n, err + } + r.body.Close() + r.body = res.Body + } + return n, nil +} + +func (r *httpReader) Close() error { + return r.body.Close() +} diff --git a/vendor/cloud.google.com/go/storage/iam.go b/vendor/cloud.google.com/go/storage/iam.go index 5caefb059d5..408661718fc 100644 --- a/vendor/cloud.google.com/go/storage/iam.go +++ b/vendor/cloud.google.com/go/storage/iam.go @@ -27,15 +27,17 @@ import ( // IAM provides access to IAM access control for the bucket. func (b *BucketHandle) IAM() *iam.Handle { return iam.InternalNewHandleClient(&iamClient{ - raw: b.c.raw, userProject: b.userProject, + retry: b.retry, + client: b.c, }, b.name) } // iamClient implements the iam.client interface. type iamClient struct { - raw *raw.Service userProject string + retry *retryConfig + client *Client } func (c *iamClient) Get(ctx context.Context, resource string) (p *iampb.Policy, err error) { @@ -46,56 +48,25 @@ func (c *iamClient) GetWithVersion(ctx context.Context, resource string, request ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.IAM.Get") defer func() { trace.EndSpan(ctx, err) }() - call := c.raw.Buckets.GetIamPolicy(resource).OptionsRequestedPolicyVersion(int64(requestedPolicyVersion)) - setClientHeader(call.Header()) - if c.userProject != "" { - call.UserProject(c.userProject) - } - var rp *raw.Policy - err = runWithRetry(ctx, func() error { - rp, err = call.Context(ctx).Do() - return err - }) - if err != nil { - return nil, err - } - return iamFromStoragePolicy(rp), nil + o := makeStorageOpts(true, c.retry, c.userProject) + return c.client.tc.GetIamPolicy(ctx, resource, requestedPolicyVersion, o...) } func (c *iamClient) Set(ctx context.Context, resource string, p *iampb.Policy) (err error) { ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.IAM.Set") defer func() { trace.EndSpan(ctx, err) }() - rp := iamToStoragePolicy(p) - call := c.raw.Buckets.SetIamPolicy(resource, rp) - setClientHeader(call.Header()) - if c.userProject != "" { - call.UserProject(c.userProject) - } - return runWithRetry(ctx, func() error { - _, err := call.Context(ctx).Do() - return err - }) + isIdempotent := len(p.Etag) > 0 + o := makeStorageOpts(isIdempotent, c.retry, c.userProject) + return c.client.tc.SetIamPolicy(ctx, resource, p, o...) } func (c *iamClient) Test(ctx context.Context, resource string, perms []string) (permissions []string, err error) { ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.IAM.Test") defer func() { trace.EndSpan(ctx, err) }() - call := c.raw.Buckets.TestIamPermissions(resource, perms) - setClientHeader(call.Header()) - if c.userProject != "" { - call.UserProject(c.userProject) - } - var res *raw.TestIamPermissionsResponse - err = runWithRetry(ctx, func() error { - res, err = call.Context(ctx).Do() - return err - }) - if err != nil { - return nil, err - } - return res.Permissions, nil + o := makeStorageOpts(true, c.retry, c.userProject) + return c.client.tc.TestIamPermissions(ctx, resource, perms, o...) } func iamToStoragePolicy(ip *iampb.Policy) *raw.Policy { diff --git a/vendor/cloud.google.com/go/storage/internal/apiv2/doc.go b/vendor/cloud.google.com/go/storage/internal/apiv2/doc.go new file mode 100644 index 00000000000..56e97548126 --- /dev/null +++ b/vendor/cloud.google.com/go/storage/internal/apiv2/doc.go @@ -0,0 +1,174 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by protoc-gen-go_gapic. DO NOT EDIT. + +// Package storage is an auto-generated package for the +// Cloud Storage API. +// +// Lets you store and retrieve potentially-large, immutable data objects. +// +// NOTE: This package is in alpha. It is not stable, and is likely to change. +// +// # Example usage +// +// To get started with this package, create a client. +// +// ctx := context.Background() +// // This snippet has been automatically generated and should be regarded as a code template only. +// // It will require modifications to work: +// // - It may require correct/in-range values for request initialization. +// // - It may require specifying regional endpoints when creating the service client as shown in: +// // https://pkg.go.dev/cloud.google.com/go#hdr-Client_Options +// c, err := storage.NewClient(ctx) +// if err != nil { +// // TODO: Handle error. +// } +// defer c.Close() +// +// The client will use your default application credentials. Clients should be reused instead of created as needed. +// The methods of Client are safe for concurrent use by multiple goroutines. +// The returned client must be Closed when it is done being used. +// +// # Using the Client +// +// The following is an example of making an API call with the newly created client. +// +// ctx := context.Background() +// // This snippet has been automatically generated and should be regarded as a code template only. +// // It will require modifications to work: +// // - It may require correct/in-range values for request initialization. +// // - It may require specifying regional endpoints when creating the service client as shown in: +// // https://pkg.go.dev/cloud.google.com/go#hdr-Client_Options +// c, err := storage.NewClient(ctx) +// if err != nil { +// // TODO: Handle error. +// } +// defer c.Close() +// +// req := &storagepb.DeleteBucketRequest{ +// // TODO: Fill request struct fields. +// // See https://pkg.go.dev/cloud.google.com/go/storage/internal/apiv2/stubs#DeleteBucketRequest. +// } +// err = c.DeleteBucket(ctx, req) +// if err != nil { +// // TODO: Handle error. +// } +// +// # Use of Context +// +// The ctx passed to NewClient is used for authentication requests and +// for creating the underlying connection, but is not used for subsequent calls. +// Individual methods on the client use the ctx given to them. +// +// To close the open connection, use the Close() method. +// +// For information about setting deadlines, reusing contexts, and more +// please visit https://pkg.go.dev/cloud.google.com/go. +package storage // import "cloud.google.com/go/storage/internal/apiv2" + +import ( + "context" + "os" + "runtime" + "strconv" + "strings" + "unicode" + + "google.golang.org/api/option" + "google.golang.org/grpc/metadata" +) + +// For more information on implementing a client constructor hook, see +// https://github.com/googleapis/google-cloud-go/wiki/Customizing-constructors. +type clientHookParams struct{} +type clientHook func(context.Context, clientHookParams) ([]option.ClientOption, error) + +var versionClient string + +func getVersionClient() string { + if versionClient == "" { + return "UNKNOWN" + } + return versionClient +} + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +func checkDisableDeadlines() (bool, error) { + raw, ok := os.LookupEnv("GOOGLE_API_GO_EXPERIMENTAL_DISABLE_DEFAULT_DEADLINE") + if !ok { + return false, nil + } + + b, err := strconv.ParseBool(raw) + return b, err +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/cloud-platform.read-only", + "https://www.googleapis.com/auth/devstorage.full_control", + "https://www.googleapis.com/auth/devstorage.read_only", + "https://www.googleapis.com/auth/devstorage.read_write", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return !strings.ContainsRune("0123456789.", r) + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} diff --git a/vendor/cloud.google.com/go/storage/internal/apiv2/gapic_metadata.json b/vendor/cloud.google.com/go/storage/internal/apiv2/gapic_metadata.json new file mode 100644 index 00000000000..01103fa93bd --- /dev/null +++ b/vendor/cloud.google.com/go/storage/internal/apiv2/gapic_metadata.json @@ -0,0 +1,168 @@ +{ + "schema": "1.0", + "comment": "This file maps proto services/RPCs to the corresponding library clients/methods.", + "language": "go", + "protoPackage": "google.storage.v2", + "libraryPackage": "cloud.google.com/go/storage/internal/apiv2", + "services": { + "Storage": { + "clients": { + "grpc": { + "libraryClient": "Client", + "rpcs": { + "CancelResumableWrite": { + "methods": [ + "CancelResumableWrite" + ] + }, + "ComposeObject": { + "methods": [ + "ComposeObject" + ] + }, + "CreateBucket": { + "methods": [ + "CreateBucket" + ] + }, + "CreateHmacKey": { + "methods": [ + "CreateHmacKey" + ] + }, + "CreateNotification": { + "methods": [ + "CreateNotification" + ] + }, + "DeleteBucket": { + "methods": [ + "DeleteBucket" + ] + }, + "DeleteHmacKey": { + "methods": [ + "DeleteHmacKey" + ] + }, + "DeleteNotification": { + "methods": [ + "DeleteNotification" + ] + }, + "DeleteObject": { + "methods": [ + "DeleteObject" + ] + }, + "GetBucket": { + "methods": [ + "GetBucket" + ] + }, + "GetHmacKey": { + "methods": [ + "GetHmacKey" + ] + }, + "GetIamPolicy": { + "methods": [ + "GetIamPolicy" + ] + }, + "GetNotification": { + "methods": [ + "GetNotification" + ] + }, + "GetObject": { + "methods": [ + "GetObject" + ] + }, + "GetServiceAccount": { + "methods": [ + "GetServiceAccount" + ] + }, + "ListBuckets": { + "methods": [ + "ListBuckets" + ] + }, + "ListHmacKeys": { + "methods": [ + "ListHmacKeys" + ] + }, + "ListNotifications": { + "methods": [ + "ListNotifications" + ] + }, + "ListObjects": { + "methods": [ + "ListObjects" + ] + }, + "LockBucketRetentionPolicy": { + "methods": [ + "LockBucketRetentionPolicy" + ] + }, + "QueryWriteStatus": { + "methods": [ + "QueryWriteStatus" + ] + }, + "ReadObject": { + "methods": [ + "ReadObject" + ] + }, + "RewriteObject": { + "methods": [ + "RewriteObject" + ] + }, + "SetIamPolicy": { + "methods": [ + "SetIamPolicy" + ] + }, + "StartResumableWrite": { + "methods": [ + "StartResumableWrite" + ] + }, + "TestIamPermissions": { + "methods": [ + "TestIamPermissions" + ] + }, + "UpdateBucket": { + "methods": [ + "UpdateBucket" + ] + }, + "UpdateHmacKey": { + "methods": [ + "UpdateHmacKey" + ] + }, + "UpdateObject": { + "methods": [ + "UpdateObject" + ] + }, + "WriteObject": { + "methods": [ + "WriteObject" + ] + } + } + } + } + } + } +} diff --git a/vendor/cloud.google.com/go/storage/internal/apiv2/metadata.go b/vendor/cloud.google.com/go/storage/internal/apiv2/metadata.go new file mode 100644 index 00000000000..6ff86c4fb49 --- /dev/null +++ b/vendor/cloud.google.com/go/storage/internal/apiv2/metadata.go @@ -0,0 +1,26 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package storage + +import ( + "context" + + "google.golang.org/grpc/metadata" +) + +// InsertMetadata inserts the given gRPC metadata into the outgoing context. +func InsertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + return insertMetadata(ctx, mds...) +} diff --git a/vendor/cloud.google.com/go/storage/internal/apiv2/storage_client.go b/vendor/cloud.google.com/go/storage/internal/apiv2/storage_client.go new file mode 100644 index 00000000000..6e904ee5ce5 --- /dev/null +++ b/vendor/cloud.google.com/go/storage/internal/apiv2/storage_client.go @@ -0,0 +1,1605 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by protoc-gen-go_gapic. DO NOT EDIT. + +package storage + +import ( + "context" + "fmt" + "math" + "net/url" + "regexp" + "strings" + + storagepb "cloud.google.com/go/storage/internal/apiv2/stubs" + gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/option/internaloption" + gtransport "google.golang.org/api/transport/grpc" + iampb "google.golang.org/genproto/googleapis/iam/v1" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/proto" +) + +var newClientHook clientHook + +// CallOptions contains the retry settings for each method of Client. +type CallOptions struct { + DeleteBucket []gax.CallOption + GetBucket []gax.CallOption + CreateBucket []gax.CallOption + ListBuckets []gax.CallOption + LockBucketRetentionPolicy []gax.CallOption + GetIamPolicy []gax.CallOption + SetIamPolicy []gax.CallOption + TestIamPermissions []gax.CallOption + UpdateBucket []gax.CallOption + DeleteNotification []gax.CallOption + GetNotification []gax.CallOption + CreateNotification []gax.CallOption + ListNotifications []gax.CallOption + ComposeObject []gax.CallOption + DeleteObject []gax.CallOption + CancelResumableWrite []gax.CallOption + GetObject []gax.CallOption + ReadObject []gax.CallOption + UpdateObject []gax.CallOption + WriteObject []gax.CallOption + ListObjects []gax.CallOption + RewriteObject []gax.CallOption + StartResumableWrite []gax.CallOption + QueryWriteStatus []gax.CallOption + GetServiceAccount []gax.CallOption + CreateHmacKey []gax.CallOption + DeleteHmacKey []gax.CallOption + GetHmacKey []gax.CallOption + ListHmacKeys []gax.CallOption + UpdateHmacKey []gax.CallOption +} + +func defaultGRPCClientOptions() []option.ClientOption { + return []option.ClientOption{ + internaloption.WithDefaultEndpoint("storage.googleapis.com:443"), + internaloption.WithDefaultMTLSEndpoint("storage.mtls.googleapis.com:443"), + internaloption.WithDefaultAudience("https://storage.googleapis.com/"), + internaloption.WithDefaultScopes(DefaultAuthScopes()...), + internaloption.EnableJwtWithScope(), + option.WithGRPCDialOption(grpc.WithDefaultCallOptions( + grpc.MaxCallRecvMsgSize(math.MaxInt32))), + } +} + +func defaultCallOptions() *CallOptions { + return &CallOptions{ + DeleteBucket: []gax.CallOption{}, + GetBucket: []gax.CallOption{}, + CreateBucket: []gax.CallOption{}, + ListBuckets: []gax.CallOption{}, + LockBucketRetentionPolicy: []gax.CallOption{}, + GetIamPolicy: []gax.CallOption{}, + SetIamPolicy: []gax.CallOption{}, + TestIamPermissions: []gax.CallOption{}, + UpdateBucket: []gax.CallOption{}, + DeleteNotification: []gax.CallOption{}, + GetNotification: []gax.CallOption{}, + CreateNotification: []gax.CallOption{}, + ListNotifications: []gax.CallOption{}, + ComposeObject: []gax.CallOption{}, + DeleteObject: []gax.CallOption{}, + CancelResumableWrite: []gax.CallOption{}, + GetObject: []gax.CallOption{}, + ReadObject: []gax.CallOption{}, + UpdateObject: []gax.CallOption{}, + WriteObject: []gax.CallOption{}, + ListObjects: []gax.CallOption{}, + RewriteObject: []gax.CallOption{}, + StartResumableWrite: []gax.CallOption{}, + QueryWriteStatus: []gax.CallOption{}, + GetServiceAccount: []gax.CallOption{}, + CreateHmacKey: []gax.CallOption{}, + DeleteHmacKey: []gax.CallOption{}, + GetHmacKey: []gax.CallOption{}, + ListHmacKeys: []gax.CallOption{}, + UpdateHmacKey: []gax.CallOption{}, + } +} + +// internalClient is an interface that defines the methods available from Cloud Storage API. +type internalClient interface { + Close() error + setGoogleClientInfo(...string) + Connection() *grpc.ClientConn + DeleteBucket(context.Context, *storagepb.DeleteBucketRequest, ...gax.CallOption) error + GetBucket(context.Context, *storagepb.GetBucketRequest, ...gax.CallOption) (*storagepb.Bucket, error) + CreateBucket(context.Context, *storagepb.CreateBucketRequest, ...gax.CallOption) (*storagepb.Bucket, error) + ListBuckets(context.Context, *storagepb.ListBucketsRequest, ...gax.CallOption) *BucketIterator + LockBucketRetentionPolicy(context.Context, *storagepb.LockBucketRetentionPolicyRequest, ...gax.CallOption) (*storagepb.Bucket, error) + GetIamPolicy(context.Context, *iampb.GetIamPolicyRequest, ...gax.CallOption) (*iampb.Policy, error) + SetIamPolicy(context.Context, *iampb.SetIamPolicyRequest, ...gax.CallOption) (*iampb.Policy, error) + TestIamPermissions(context.Context, *iampb.TestIamPermissionsRequest, ...gax.CallOption) (*iampb.TestIamPermissionsResponse, error) + UpdateBucket(context.Context, *storagepb.UpdateBucketRequest, ...gax.CallOption) (*storagepb.Bucket, error) + DeleteNotification(context.Context, *storagepb.DeleteNotificationRequest, ...gax.CallOption) error + GetNotification(context.Context, *storagepb.GetNotificationRequest, ...gax.CallOption) (*storagepb.Notification, error) + CreateNotification(context.Context, *storagepb.CreateNotificationRequest, ...gax.CallOption) (*storagepb.Notification, error) + ListNotifications(context.Context, *storagepb.ListNotificationsRequest, ...gax.CallOption) *NotificationIterator + ComposeObject(context.Context, *storagepb.ComposeObjectRequest, ...gax.CallOption) (*storagepb.Object, error) + DeleteObject(context.Context, *storagepb.DeleteObjectRequest, ...gax.CallOption) error + CancelResumableWrite(context.Context, *storagepb.CancelResumableWriteRequest, ...gax.CallOption) (*storagepb.CancelResumableWriteResponse, error) + GetObject(context.Context, *storagepb.GetObjectRequest, ...gax.CallOption) (*storagepb.Object, error) + ReadObject(context.Context, *storagepb.ReadObjectRequest, ...gax.CallOption) (storagepb.Storage_ReadObjectClient, error) + UpdateObject(context.Context, *storagepb.UpdateObjectRequest, ...gax.CallOption) (*storagepb.Object, error) + WriteObject(context.Context, ...gax.CallOption) (storagepb.Storage_WriteObjectClient, error) + ListObjects(context.Context, *storagepb.ListObjectsRequest, ...gax.CallOption) *ObjectIterator + RewriteObject(context.Context, *storagepb.RewriteObjectRequest, ...gax.CallOption) (*storagepb.RewriteResponse, error) + StartResumableWrite(context.Context, *storagepb.StartResumableWriteRequest, ...gax.CallOption) (*storagepb.StartResumableWriteResponse, error) + QueryWriteStatus(context.Context, *storagepb.QueryWriteStatusRequest, ...gax.CallOption) (*storagepb.QueryWriteStatusResponse, error) + GetServiceAccount(context.Context, *storagepb.GetServiceAccountRequest, ...gax.CallOption) (*storagepb.ServiceAccount, error) + CreateHmacKey(context.Context, *storagepb.CreateHmacKeyRequest, ...gax.CallOption) (*storagepb.CreateHmacKeyResponse, error) + DeleteHmacKey(context.Context, *storagepb.DeleteHmacKeyRequest, ...gax.CallOption) error + GetHmacKey(context.Context, *storagepb.GetHmacKeyRequest, ...gax.CallOption) (*storagepb.HmacKeyMetadata, error) + ListHmacKeys(context.Context, *storagepb.ListHmacKeysRequest, ...gax.CallOption) *HmacKeyMetadataIterator + UpdateHmacKey(context.Context, *storagepb.UpdateHmacKeyRequest, ...gax.CallOption) (*storagepb.HmacKeyMetadata, error) +} + +// Client is a client for interacting with Cloud Storage API. +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +// +// API Overview and Naming SyntaxThe Cloud Storage gRPC API allows applications to read and write data through +// the abstractions of buckets and objects. For a description of these +// abstractions please see https://cloud.google.com/storage/docs (at https://cloud.google.com/storage/docs). +// +// Resources are named as follows: +// +// Projects are referred to as they are defined by the Resource Manager API, +// using strings like projects/123456 or projects/my-string-id. +// +// Buckets are named using string names of the form: +// projects/{project}/buckets/{bucket} +// For globally unique buckets, _ may be substituted for the project. +// +// Objects are uniquely identified by their name along with the name of the +// bucket they belong to, as separate strings in this API. For example: +// +// ReadObjectRequest { +// bucket: ‘projects/_/buckets/my-bucket’ +// object: ‘my-object’ +// } +// Note that object names can contain / characters, which are treated as +// any other character (no special directory semantics). +type Client struct { + // The internal transport-dependent client. + internalClient internalClient + + // The call options for this service. + CallOptions *CallOptions +} + +// Wrapper methods routed to the internal client. + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *Client) Close() error { + return c.internalClient.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *Client) setGoogleClientInfo(keyval ...string) { + c.internalClient.setGoogleClientInfo(keyval...) +} + +// Connection returns a connection to the API service. +// +// Deprecated: Connections are now pooled so this method does not always +// return the same resource. +func (c *Client) Connection() *grpc.ClientConn { + return c.internalClient.Connection() +} + +// DeleteBucket permanently deletes an empty bucket. +func (c *Client) DeleteBucket(ctx context.Context, req *storagepb.DeleteBucketRequest, opts ...gax.CallOption) error { + return c.internalClient.DeleteBucket(ctx, req, opts...) +} + +// GetBucket returns metadata for the specified bucket. +func (c *Client) GetBucket(ctx context.Context, req *storagepb.GetBucketRequest, opts ...gax.CallOption) (*storagepb.Bucket, error) { + return c.internalClient.GetBucket(ctx, req, opts...) +} + +// CreateBucket creates a new bucket. +func (c *Client) CreateBucket(ctx context.Context, req *storagepb.CreateBucketRequest, opts ...gax.CallOption) (*storagepb.Bucket, error) { + return c.internalClient.CreateBucket(ctx, req, opts...) +} + +// ListBuckets retrieves a list of buckets for a given project. +func (c *Client) ListBuckets(ctx context.Context, req *storagepb.ListBucketsRequest, opts ...gax.CallOption) *BucketIterator { + return c.internalClient.ListBuckets(ctx, req, opts...) +} + +// LockBucketRetentionPolicy locks retention policy on a bucket. +func (c *Client) LockBucketRetentionPolicy(ctx context.Context, req *storagepb.LockBucketRetentionPolicyRequest, opts ...gax.CallOption) (*storagepb.Bucket, error) { + return c.internalClient.LockBucketRetentionPolicy(ctx, req, opts...) +} + +// GetIamPolicy gets the IAM policy for a specified bucket or object. +func (c *Client) GetIamPolicy(ctx context.Context, req *iampb.GetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { + return c.internalClient.GetIamPolicy(ctx, req, opts...) +} + +// SetIamPolicy updates an IAM policy for the specified bucket or object. +func (c *Client) SetIamPolicy(ctx context.Context, req *iampb.SetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { + return c.internalClient.SetIamPolicy(ctx, req, opts...) +} + +// TestIamPermissions tests a set of permissions on the given bucket or object to see which, if +// any, are held by the caller. +func (c *Client) TestIamPermissions(ctx context.Context, req *iampb.TestIamPermissionsRequest, opts ...gax.CallOption) (*iampb.TestIamPermissionsResponse, error) { + return c.internalClient.TestIamPermissions(ctx, req, opts...) +} + +// UpdateBucket updates a bucket. Equivalent to JSON API’s storage.buckets.patch method. +func (c *Client) UpdateBucket(ctx context.Context, req *storagepb.UpdateBucketRequest, opts ...gax.CallOption) (*storagepb.Bucket, error) { + return c.internalClient.UpdateBucket(ctx, req, opts...) +} + +// DeleteNotification permanently deletes a notification subscription. +func (c *Client) DeleteNotification(ctx context.Context, req *storagepb.DeleteNotificationRequest, opts ...gax.CallOption) error { + return c.internalClient.DeleteNotification(ctx, req, opts...) +} + +// GetNotification view a notification config. +func (c *Client) GetNotification(ctx context.Context, req *storagepb.GetNotificationRequest, opts ...gax.CallOption) (*storagepb.Notification, error) { + return c.internalClient.GetNotification(ctx, req, opts...) +} + +// CreateNotification creates a notification subscription for a given bucket. +// These notifications, when triggered, publish messages to the specified +// Pub/Sub topics. +// See https://cloud.google.com/storage/docs/pubsub-notifications (at https://cloud.google.com/storage/docs/pubsub-notifications). +func (c *Client) CreateNotification(ctx context.Context, req *storagepb.CreateNotificationRequest, opts ...gax.CallOption) (*storagepb.Notification, error) { + return c.internalClient.CreateNotification(ctx, req, opts...) +} + +// ListNotifications retrieves a list of notification subscriptions for a given bucket. +func (c *Client) ListNotifications(ctx context.Context, req *storagepb.ListNotificationsRequest, opts ...gax.CallOption) *NotificationIterator { + return c.internalClient.ListNotifications(ctx, req, opts...) +} + +// ComposeObject concatenates a list of existing objects into a new object in the same +// bucket. +func (c *Client) ComposeObject(ctx context.Context, req *storagepb.ComposeObjectRequest, opts ...gax.CallOption) (*storagepb.Object, error) { + return c.internalClient.ComposeObject(ctx, req, opts...) +} + +// DeleteObject deletes an object and its metadata. Deletions are permanent if versioning +// is not enabled for the bucket, or if the generation parameter is used. +func (c *Client) DeleteObject(ctx context.Context, req *storagepb.DeleteObjectRequest, opts ...gax.CallOption) error { + return c.internalClient.DeleteObject(ctx, req, opts...) +} + +// CancelResumableWrite cancels an in-progress resumable upload. +func (c *Client) CancelResumableWrite(ctx context.Context, req *storagepb.CancelResumableWriteRequest, opts ...gax.CallOption) (*storagepb.CancelResumableWriteResponse, error) { + return c.internalClient.CancelResumableWrite(ctx, req, opts...) +} + +// GetObject retrieves an object’s metadata. +func (c *Client) GetObject(ctx context.Context, req *storagepb.GetObjectRequest, opts ...gax.CallOption) (*storagepb.Object, error) { + return c.internalClient.GetObject(ctx, req, opts...) +} + +// ReadObject reads an object’s data. +func (c *Client) ReadObject(ctx context.Context, req *storagepb.ReadObjectRequest, opts ...gax.CallOption) (storagepb.Storage_ReadObjectClient, error) { + return c.internalClient.ReadObject(ctx, req, opts...) +} + +// UpdateObject updates an object’s metadata. +// Equivalent to JSON API’s storage.objects.patch. +func (c *Client) UpdateObject(ctx context.Context, req *storagepb.UpdateObjectRequest, opts ...gax.CallOption) (*storagepb.Object, error) { + return c.internalClient.UpdateObject(ctx, req, opts...) +} + +// WriteObject stores a new object and metadata. +// +// An object can be written either in a single message stream or in a +// resumable sequence of message streams. To write using a single stream, +// the client should include in the first message of the stream an +// WriteObjectSpec describing the destination bucket, object, and any +// preconditions. Additionally, the final message must set ‘finish_write’ to +// true, or else it is an error. +// +// For a resumable write, the client should instead call +// StartResumableWrite(), populating a WriteObjectSpec into that request. +// They should then attach the returned upload_id to the first message of +// each following call to WriteObject. If the stream is closed before +// finishing the upload (either explicitly by the client or due to a network +// error or an error response from the server), the client should do as +// follows: +// +// Check the result Status of the stream, to determine if writing can be +// resumed on this stream or must be restarted from scratch (by calling +// StartResumableWrite()). The resumable errors are DEADLINE_EXCEEDED, +// INTERNAL, and UNAVAILABLE. For each case, the client should use binary +// exponential backoff before retrying. Additionally, writes can be +// resumed after RESOURCE_EXHAUSTED errors, but only after taking +// appropriate measures, which may include reducing aggregate send rate +// across clients and/or requesting a quota increase for your project. +// +// If the call to WriteObject returns ABORTED, that indicates +// concurrent attempts to update the resumable write, caused either by +// multiple racing clients or by a single client where the previous +// request was timed out on the client side but nonetheless reached the +// server. In this case the client should take steps to prevent further +// concurrent writes (e.g., increase the timeouts, stop using more than +// one process to perform the upload, etc.), and then should follow the +// steps below for resuming the upload. +// +// For resumable errors, the client should call QueryWriteStatus() and +// then continue writing from the returned persisted_size. This may be +// less than the amount of data the client previously sent. Note also that +// it is acceptable to send data starting at an offset earlier than the +// returned persisted_size; in this case, the service will skip data at +// offsets that were already persisted (without checking that it matches +// the previously written data), and write only the data starting from the +// persisted offset. This behavior can make client-side handling simpler +// in some cases. +// +// The service will not view the object as complete until the client has +// sent a WriteObjectRequest with finish_write set to true. Sending any +// requests on a stream after sending a request with finish_write set to +// true will cause an error. The client should check the response it +// receives to determine how much data the service was able to commit and +// whether the service views the object as complete. +// +// Attempting to resume an already finalized object will result in an OK +// status, with a WriteObjectResponse containing the finalized object’s +// metadata. +func (c *Client) WriteObject(ctx context.Context, opts ...gax.CallOption) (storagepb.Storage_WriteObjectClient, error) { + return c.internalClient.WriteObject(ctx, opts...) +} + +// ListObjects retrieves a list of objects matching the criteria. +func (c *Client) ListObjects(ctx context.Context, req *storagepb.ListObjectsRequest, opts ...gax.CallOption) *ObjectIterator { + return c.internalClient.ListObjects(ctx, req, opts...) +} + +// RewriteObject rewrites a source object to a destination object. Optionally overrides +// metadata. +func (c *Client) RewriteObject(ctx context.Context, req *storagepb.RewriteObjectRequest, opts ...gax.CallOption) (*storagepb.RewriteResponse, error) { + return c.internalClient.RewriteObject(ctx, req, opts...) +} + +// StartResumableWrite starts a resumable write. How long the write operation remains valid, and +// what happens when the write operation becomes invalid, are +// service-dependent. +func (c *Client) StartResumableWrite(ctx context.Context, req *storagepb.StartResumableWriteRequest, opts ...gax.CallOption) (*storagepb.StartResumableWriteResponse, error) { + return c.internalClient.StartResumableWrite(ctx, req, opts...) +} + +// QueryWriteStatus determines the persisted_size for an object that is being written, which +// can then be used as the write_offset for the next Write() call. +// +// If the object does not exist (i.e., the object has been deleted, or the +// first Write() has not yet reached the service), this method returns the +// error NOT_FOUND. +// +// The client may call QueryWriteStatus() at any time to determine how +// much data has been processed for this object. This is useful if the +// client is buffering data and needs to know which data can be safely +// evicted. For any sequence of QueryWriteStatus() calls for a given +// object name, the sequence of returned persisted_size values will be +// non-decreasing. +func (c *Client) QueryWriteStatus(ctx context.Context, req *storagepb.QueryWriteStatusRequest, opts ...gax.CallOption) (*storagepb.QueryWriteStatusResponse, error) { + return c.internalClient.QueryWriteStatus(ctx, req, opts...) +} + +// GetServiceAccount retrieves the name of a project’s Google Cloud Storage service account. +func (c *Client) GetServiceAccount(ctx context.Context, req *storagepb.GetServiceAccountRequest, opts ...gax.CallOption) (*storagepb.ServiceAccount, error) { + return c.internalClient.GetServiceAccount(ctx, req, opts...) +} + +// CreateHmacKey creates a new HMAC key for the given service account. +func (c *Client) CreateHmacKey(ctx context.Context, req *storagepb.CreateHmacKeyRequest, opts ...gax.CallOption) (*storagepb.CreateHmacKeyResponse, error) { + return c.internalClient.CreateHmacKey(ctx, req, opts...) +} + +// DeleteHmacKey deletes a given HMAC key. Key must be in an INACTIVE state. +func (c *Client) DeleteHmacKey(ctx context.Context, req *storagepb.DeleteHmacKeyRequest, opts ...gax.CallOption) error { + return c.internalClient.DeleteHmacKey(ctx, req, opts...) +} + +// GetHmacKey gets an existing HMAC key metadata for the given id. +func (c *Client) GetHmacKey(ctx context.Context, req *storagepb.GetHmacKeyRequest, opts ...gax.CallOption) (*storagepb.HmacKeyMetadata, error) { + return c.internalClient.GetHmacKey(ctx, req, opts...) +} + +// ListHmacKeys lists HMAC keys under a given project with the additional filters provided. +func (c *Client) ListHmacKeys(ctx context.Context, req *storagepb.ListHmacKeysRequest, opts ...gax.CallOption) *HmacKeyMetadataIterator { + return c.internalClient.ListHmacKeys(ctx, req, opts...) +} + +// UpdateHmacKey updates a given HMAC key state between ACTIVE and INACTIVE. +func (c *Client) UpdateHmacKey(ctx context.Context, req *storagepb.UpdateHmacKeyRequest, opts ...gax.CallOption) (*storagepb.HmacKeyMetadata, error) { + return c.internalClient.UpdateHmacKey(ctx, req, opts...) +} + +// gRPCClient is a client for interacting with Cloud Storage API over gRPC transport. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type gRPCClient struct { + // Connection pool of gRPC connections to the service. + connPool gtransport.ConnPool + + // flag to opt out of default deadlines via GOOGLE_API_GO_EXPERIMENTAL_DISABLE_DEFAULT_DEADLINE + disableDeadlines bool + + // Points back to the CallOptions field of the containing Client + CallOptions **CallOptions + + // The gRPC API client. + client storagepb.StorageClient + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewClient creates a new storage client based on gRPC. +// The returned client must be Closed when it is done being used to clean up its underlying connections. +// +// API Overview and Naming SyntaxThe Cloud Storage gRPC API allows applications to read and write data through +// the abstractions of buckets and objects. For a description of these +// abstractions please see https://cloud.google.com/storage/docs (at https://cloud.google.com/storage/docs). +// +// Resources are named as follows: +// +// Projects are referred to as they are defined by the Resource Manager API, +// using strings like projects/123456 or projects/my-string-id. +// +// Buckets are named using string names of the form: +// projects/{project}/buckets/{bucket} +// For globally unique buckets, _ may be substituted for the project. +// +// Objects are uniquely identified by their name along with the name of the +// bucket they belong to, as separate strings in this API. For example: +// +// ReadObjectRequest { +// bucket: ‘projects/_/buckets/my-bucket’ +// object: ‘my-object’ +// } +// Note that object names can contain / characters, which are treated as +// any other character (no special directory semantics). +func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + clientOpts := defaultGRPCClientOptions() + if newClientHook != nil { + hookOpts, err := newClientHook(ctx, clientHookParams{}) + if err != nil { + return nil, err + } + clientOpts = append(clientOpts, hookOpts...) + } + + disableDeadlines, err := checkDisableDeadlines() + if err != nil { + return nil, err + } + + connPool, err := gtransport.DialPool(ctx, append(clientOpts, opts...)...) + if err != nil { + return nil, err + } + client := Client{CallOptions: defaultCallOptions()} + + c := &gRPCClient{ + connPool: connPool, + disableDeadlines: disableDeadlines, + client: storagepb.NewStorageClient(connPool), + CallOptions: &client.CallOptions, + } + c.setGoogleClientInfo() + + client.internalClient = c + + return &client, nil +} + +// Connection returns a connection to the API service. +// +// Deprecated: Connections are now pooled so this method does not always +// return the same resource. +func (c *gRPCClient) Connection() *grpc.ClientConn { + return c.connPool.Conn() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *gRPCClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", getVersionClient(), "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *gRPCClient) Close() error { + return c.connPool.Close() +} + +func (c *gRPCClient) DeleteBucket(ctx context.Context, req *storagepb.DeleteBucketRequest, opts ...gax.CallOption) error { + routingHeaders := "" + routingHeadersMap := make(map[string]string) + if reg := regexp.MustCompile("(?P.*)"); reg.MatchString(req.GetName()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetName())[1])) > 0 { + routingHeadersMap["bucket"] = url.QueryEscape(reg.FindStringSubmatch(req.GetName())[1]) + } + for headerName, headerValue := range routingHeadersMap { + routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue) + } + routingHeaders = strings.TrimSuffix(routingHeaders, "&") + md := metadata.Pairs("x-goog-request-params", routingHeaders) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).DeleteBucket[0:len((*c.CallOptions).DeleteBucket):len((*c.CallOptions).DeleteBucket)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.client.DeleteBucket(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +func (c *gRPCClient) GetBucket(ctx context.Context, req *storagepb.GetBucketRequest, opts ...gax.CallOption) (*storagepb.Bucket, error) { + routingHeaders := "" + routingHeadersMap := make(map[string]string) + if reg := regexp.MustCompile("(?P.*)"); reg.MatchString(req.GetName()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetName())[1])) > 0 { + routingHeadersMap["bucket"] = url.QueryEscape(reg.FindStringSubmatch(req.GetName())[1]) + } + for headerName, headerValue := range routingHeadersMap { + routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue) + } + routingHeaders = strings.TrimSuffix(routingHeaders, "&") + md := metadata.Pairs("x-goog-request-params", routingHeaders) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).GetBucket[0:len((*c.CallOptions).GetBucket):len((*c.CallOptions).GetBucket)], opts...) + var resp *storagepb.Bucket + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.GetBucket(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *gRPCClient) CreateBucket(ctx context.Context, req *storagepb.CreateBucketRequest, opts ...gax.CallOption) (*storagepb.Bucket, error) { + routingHeaders := "" + routingHeadersMap := make(map[string]string) + if reg := regexp.MustCompile("(?P.*)"); reg.MatchString(req.GetParent()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetParent())[1])) > 0 { + routingHeadersMap["project"] = url.QueryEscape(reg.FindStringSubmatch(req.GetParent())[1]) + } + for headerName, headerValue := range routingHeadersMap { + routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue) + } + routingHeaders = strings.TrimSuffix(routingHeaders, "&") + md := metadata.Pairs("x-goog-request-params", routingHeaders) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).CreateBucket[0:len((*c.CallOptions).CreateBucket):len((*c.CallOptions).CreateBucket)], opts...) + var resp *storagepb.Bucket + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.CreateBucket(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *gRPCClient) ListBuckets(ctx context.Context, req *storagepb.ListBucketsRequest, opts ...gax.CallOption) *BucketIterator { + routingHeaders := "" + routingHeadersMap := make(map[string]string) + if reg := regexp.MustCompile("(?P.*)"); reg.MatchString(req.GetParent()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetParent())[1])) > 0 { + routingHeadersMap["project"] = url.QueryEscape(reg.FindStringSubmatch(req.GetParent())[1]) + } + for headerName, headerValue := range routingHeadersMap { + routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue) + } + routingHeaders = strings.TrimSuffix(routingHeaders, "&") + md := metadata.Pairs("x-goog-request-params", routingHeaders) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).ListBuckets[0:len((*c.CallOptions).ListBuckets):len((*c.CallOptions).ListBuckets)], opts...) + it := &BucketIterator{} + req = proto.Clone(req).(*storagepb.ListBucketsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*storagepb.Bucket, string, error) { + resp := &storagepb.ListBucketsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ListBuckets(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + + it.Response = resp + return resp.GetBuckets(), resp.GetNextPageToken(), nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +func (c *gRPCClient) LockBucketRetentionPolicy(ctx context.Context, req *storagepb.LockBucketRetentionPolicyRequest, opts ...gax.CallOption) (*storagepb.Bucket, error) { + routingHeaders := "" + routingHeadersMap := make(map[string]string) + if reg := regexp.MustCompile("(?P.*)"); reg.MatchString(req.GetBucket()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetBucket())[1])) > 0 { + routingHeadersMap["bucket"] = url.QueryEscape(reg.FindStringSubmatch(req.GetBucket())[1]) + } + for headerName, headerValue := range routingHeadersMap { + routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue) + } + routingHeaders = strings.TrimSuffix(routingHeaders, "&") + md := metadata.Pairs("x-goog-request-params", routingHeaders) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).LockBucketRetentionPolicy[0:len((*c.CallOptions).LockBucketRetentionPolicy):len((*c.CallOptions).LockBucketRetentionPolicy)], opts...) + var resp *storagepb.Bucket + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.LockBucketRetentionPolicy(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *gRPCClient) GetIamPolicy(ctx context.Context, req *iampb.GetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { + routingHeaders := "" + routingHeadersMap := make(map[string]string) + if reg := regexp.MustCompile("(?P.*)"); reg.MatchString(req.GetResource()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetResource())[1])) > 0 { + routingHeadersMap["bucket"] = url.QueryEscape(reg.FindStringSubmatch(req.GetResource())[1]) + } + if reg := regexp.MustCompile("(?Pprojects/[^/]+/buckets/[^/]+)/objects(?:/.*)?"); reg.MatchString(req.GetResource()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetResource())[1])) > 0 { + routingHeadersMap["bucket"] = url.QueryEscape(reg.FindStringSubmatch(req.GetResource())[1]) + } + for headerName, headerValue := range routingHeadersMap { + routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue) + } + routingHeaders = strings.TrimSuffix(routingHeaders, "&") + md := metadata.Pairs("x-goog-request-params", routingHeaders) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).GetIamPolicy[0:len((*c.CallOptions).GetIamPolicy):len((*c.CallOptions).GetIamPolicy)], opts...) + var resp *iampb.Policy + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.GetIamPolicy(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *gRPCClient) SetIamPolicy(ctx context.Context, req *iampb.SetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { + routingHeaders := "" + routingHeadersMap := make(map[string]string) + if reg := regexp.MustCompile("(?P.*)"); reg.MatchString(req.GetResource()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetResource())[1])) > 0 { + routingHeadersMap["bucket"] = url.QueryEscape(reg.FindStringSubmatch(req.GetResource())[1]) + } + if reg := regexp.MustCompile("(?Pprojects/[^/]+/buckets/[^/]+)/objects(?:/.*)?"); reg.MatchString(req.GetResource()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetResource())[1])) > 0 { + routingHeadersMap["bucket"] = url.QueryEscape(reg.FindStringSubmatch(req.GetResource())[1]) + } + for headerName, headerValue := range routingHeadersMap { + routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue) + } + routingHeaders = strings.TrimSuffix(routingHeaders, "&") + md := metadata.Pairs("x-goog-request-params", routingHeaders) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).SetIamPolicy[0:len((*c.CallOptions).SetIamPolicy):len((*c.CallOptions).SetIamPolicy)], opts...) + var resp *iampb.Policy + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.SetIamPolicy(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *gRPCClient) TestIamPermissions(ctx context.Context, req *iampb.TestIamPermissionsRequest, opts ...gax.CallOption) (*iampb.TestIamPermissionsResponse, error) { + routingHeaders := "" + routingHeadersMap := make(map[string]string) + if reg := regexp.MustCompile("(?P.*)"); reg.MatchString(req.GetResource()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetResource())[1])) > 0 { + routingHeadersMap["bucket"] = url.QueryEscape(reg.FindStringSubmatch(req.GetResource())[1]) + } + if reg := regexp.MustCompile("(?Pprojects/[^/]+/buckets/[^/]+)/objects(?:/.*)?"); reg.MatchString(req.GetResource()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetResource())[1])) > 0 { + routingHeadersMap["bucket"] = url.QueryEscape(reg.FindStringSubmatch(req.GetResource())[1]) + } + for headerName, headerValue := range routingHeadersMap { + routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue) + } + routingHeaders = strings.TrimSuffix(routingHeaders, "&") + md := metadata.Pairs("x-goog-request-params", routingHeaders) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).TestIamPermissions[0:len((*c.CallOptions).TestIamPermissions):len((*c.CallOptions).TestIamPermissions)], opts...) + var resp *iampb.TestIamPermissionsResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.TestIamPermissions(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *gRPCClient) UpdateBucket(ctx context.Context, req *storagepb.UpdateBucketRequest, opts ...gax.CallOption) (*storagepb.Bucket, error) { + routingHeaders := "" + routingHeadersMap := make(map[string]string) + if reg := regexp.MustCompile("(?P.*)"); reg.MatchString(req.GetBucket().GetName()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetBucket().GetName())[1])) > 0 { + routingHeadersMap["bucket"] = url.QueryEscape(reg.FindStringSubmatch(req.GetBucket().GetName())[1]) + } + for headerName, headerValue := range routingHeadersMap { + routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue) + } + routingHeaders = strings.TrimSuffix(routingHeaders, "&") + md := metadata.Pairs("x-goog-request-params", routingHeaders) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).UpdateBucket[0:len((*c.CallOptions).UpdateBucket):len((*c.CallOptions).UpdateBucket)], opts...) + var resp *storagepb.Bucket + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.UpdateBucket(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *gRPCClient) DeleteNotification(ctx context.Context, req *storagepb.DeleteNotificationRequest, opts ...gax.CallOption) error { + routingHeaders := "" + routingHeadersMap := make(map[string]string) + if reg := regexp.MustCompile("(?Pprojects/[^/]+/buckets/[^/]+)(?:/.*)?"); reg.MatchString(req.GetName()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetName())[1])) > 0 { + routingHeadersMap["bucket"] = url.QueryEscape(reg.FindStringSubmatch(req.GetName())[1]) + } + for headerName, headerValue := range routingHeadersMap { + routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue) + } + routingHeaders = strings.TrimSuffix(routingHeaders, "&") + md := metadata.Pairs("x-goog-request-params", routingHeaders) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).DeleteNotification[0:len((*c.CallOptions).DeleteNotification):len((*c.CallOptions).DeleteNotification)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.client.DeleteNotification(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +func (c *gRPCClient) GetNotification(ctx context.Context, req *storagepb.GetNotificationRequest, opts ...gax.CallOption) (*storagepb.Notification, error) { + routingHeaders := "" + routingHeadersMap := make(map[string]string) + if reg := regexp.MustCompile("(?Pprojects/[^/]+/buckets/[^/]+)(?:/.*)?"); reg.MatchString(req.GetName()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetName())[1])) > 0 { + routingHeadersMap["bucket"] = url.QueryEscape(reg.FindStringSubmatch(req.GetName())[1]) + } + for headerName, headerValue := range routingHeadersMap { + routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue) + } + routingHeaders = strings.TrimSuffix(routingHeaders, "&") + md := metadata.Pairs("x-goog-request-params", routingHeaders) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).GetNotification[0:len((*c.CallOptions).GetNotification):len((*c.CallOptions).GetNotification)], opts...) + var resp *storagepb.Notification + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.GetNotification(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *gRPCClient) CreateNotification(ctx context.Context, req *storagepb.CreateNotificationRequest, opts ...gax.CallOption) (*storagepb.Notification, error) { + routingHeaders := "" + routingHeadersMap := make(map[string]string) + if reg := regexp.MustCompile("(?P.*)"); reg.MatchString(req.GetParent()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetParent())[1])) > 0 { + routingHeadersMap["bucket"] = url.QueryEscape(reg.FindStringSubmatch(req.GetParent())[1]) + } + for headerName, headerValue := range routingHeadersMap { + routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue) + } + routingHeaders = strings.TrimSuffix(routingHeaders, "&") + md := metadata.Pairs("x-goog-request-params", routingHeaders) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).CreateNotification[0:len((*c.CallOptions).CreateNotification):len((*c.CallOptions).CreateNotification)], opts...) + var resp *storagepb.Notification + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.CreateNotification(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *gRPCClient) ListNotifications(ctx context.Context, req *storagepb.ListNotificationsRequest, opts ...gax.CallOption) *NotificationIterator { + routingHeaders := "" + routingHeadersMap := make(map[string]string) + if reg := regexp.MustCompile("(?P.*)"); reg.MatchString(req.GetParent()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetParent())[1])) > 0 { + routingHeadersMap["bucket"] = url.QueryEscape(reg.FindStringSubmatch(req.GetParent())[1]) + } + for headerName, headerValue := range routingHeadersMap { + routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue) + } + routingHeaders = strings.TrimSuffix(routingHeaders, "&") + md := metadata.Pairs("x-goog-request-params", routingHeaders) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).ListNotifications[0:len((*c.CallOptions).ListNotifications):len((*c.CallOptions).ListNotifications)], opts...) + it := &NotificationIterator{} + req = proto.Clone(req).(*storagepb.ListNotificationsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*storagepb.Notification, string, error) { + resp := &storagepb.ListNotificationsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ListNotifications(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + + it.Response = resp + return resp.GetNotifications(), resp.GetNextPageToken(), nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +func (c *gRPCClient) ComposeObject(ctx context.Context, req *storagepb.ComposeObjectRequest, opts ...gax.CallOption) (*storagepb.Object, error) { + routingHeaders := "" + routingHeadersMap := make(map[string]string) + if reg := regexp.MustCompile("(?P.*)"); reg.MatchString(req.GetDestination().GetBucket()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetDestination().GetBucket())[1])) > 0 { + routingHeadersMap["bucket"] = url.QueryEscape(reg.FindStringSubmatch(req.GetDestination().GetBucket())[1]) + } + for headerName, headerValue := range routingHeadersMap { + routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue) + } + routingHeaders = strings.TrimSuffix(routingHeaders, "&") + md := metadata.Pairs("x-goog-request-params", routingHeaders) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).ComposeObject[0:len((*c.CallOptions).ComposeObject):len((*c.CallOptions).ComposeObject)], opts...) + var resp *storagepb.Object + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ComposeObject(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *gRPCClient) DeleteObject(ctx context.Context, req *storagepb.DeleteObjectRequest, opts ...gax.CallOption) error { + routingHeaders := "" + routingHeadersMap := make(map[string]string) + if reg := regexp.MustCompile("(?P.*)"); reg.MatchString(req.GetBucket()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetBucket())[1])) > 0 { + routingHeadersMap["bucket"] = url.QueryEscape(reg.FindStringSubmatch(req.GetBucket())[1]) + } + for headerName, headerValue := range routingHeadersMap { + routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue) + } + routingHeaders = strings.TrimSuffix(routingHeaders, "&") + md := metadata.Pairs("x-goog-request-params", routingHeaders) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).DeleteObject[0:len((*c.CallOptions).DeleteObject):len((*c.CallOptions).DeleteObject)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.client.DeleteObject(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +func (c *gRPCClient) CancelResumableWrite(ctx context.Context, req *storagepb.CancelResumableWriteRequest, opts ...gax.CallOption) (*storagepb.CancelResumableWriteResponse, error) { + routingHeaders := "" + routingHeadersMap := make(map[string]string) + if reg := regexp.MustCompile("(?Pprojects/[^/]+/buckets/[^/]+)(?:/.*)?"); reg.MatchString(req.GetUploadId()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetUploadId())[1])) > 0 { + routingHeadersMap["bucket"] = url.QueryEscape(reg.FindStringSubmatch(req.GetUploadId())[1]) + } + for headerName, headerValue := range routingHeadersMap { + routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue) + } + routingHeaders = strings.TrimSuffix(routingHeaders, "&") + md := metadata.Pairs("x-goog-request-params", routingHeaders) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).CancelResumableWrite[0:len((*c.CallOptions).CancelResumableWrite):len((*c.CallOptions).CancelResumableWrite)], opts...) + var resp *storagepb.CancelResumableWriteResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.CancelResumableWrite(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *gRPCClient) GetObject(ctx context.Context, req *storagepb.GetObjectRequest, opts ...gax.CallOption) (*storagepb.Object, error) { + routingHeaders := "" + routingHeadersMap := make(map[string]string) + if reg := regexp.MustCompile("(?P.*)"); reg.MatchString(req.GetBucket()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetBucket())[1])) > 0 { + routingHeadersMap["bucket"] = url.QueryEscape(reg.FindStringSubmatch(req.GetBucket())[1]) + } + for headerName, headerValue := range routingHeadersMap { + routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue) + } + routingHeaders = strings.TrimSuffix(routingHeaders, "&") + md := metadata.Pairs("x-goog-request-params", routingHeaders) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).GetObject[0:len((*c.CallOptions).GetObject):len((*c.CallOptions).GetObject)], opts...) + var resp *storagepb.Object + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.GetObject(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *gRPCClient) ReadObject(ctx context.Context, req *storagepb.ReadObjectRequest, opts ...gax.CallOption) (storagepb.Storage_ReadObjectClient, error) { + routingHeaders := "" + routingHeadersMap := make(map[string]string) + if reg := regexp.MustCompile("(?P.*)"); reg.MatchString(req.GetBucket()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetBucket())[1])) > 0 { + routingHeadersMap["bucket"] = url.QueryEscape(reg.FindStringSubmatch(req.GetBucket())[1]) + } + for headerName, headerValue := range routingHeadersMap { + routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue) + } + routingHeaders = strings.TrimSuffix(routingHeaders, "&") + md := metadata.Pairs("x-goog-request-params", routingHeaders) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + var resp storagepb.Storage_ReadObjectClient + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ReadObject(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *gRPCClient) UpdateObject(ctx context.Context, req *storagepb.UpdateObjectRequest, opts ...gax.CallOption) (*storagepb.Object, error) { + routingHeaders := "" + routingHeadersMap := make(map[string]string) + if reg := regexp.MustCompile("(?P.*)"); reg.MatchString(req.GetObject().GetBucket()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetObject().GetBucket())[1])) > 0 { + routingHeadersMap["bucket"] = url.QueryEscape(reg.FindStringSubmatch(req.GetObject().GetBucket())[1]) + } + for headerName, headerValue := range routingHeadersMap { + routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue) + } + routingHeaders = strings.TrimSuffix(routingHeaders, "&") + md := metadata.Pairs("x-goog-request-params", routingHeaders) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).UpdateObject[0:len((*c.CallOptions).UpdateObject):len((*c.CallOptions).UpdateObject)], opts...) + var resp *storagepb.Object + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.UpdateObject(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *gRPCClient) WriteObject(ctx context.Context, opts ...gax.CallOption) (storagepb.Storage_WriteObjectClient, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + var resp storagepb.Storage_WriteObjectClient + opts = append((*c.CallOptions).WriteObject[0:len((*c.CallOptions).WriteObject):len((*c.CallOptions).WriteObject)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.WriteObject(ctx, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *gRPCClient) ListObjects(ctx context.Context, req *storagepb.ListObjectsRequest, opts ...gax.CallOption) *ObjectIterator { + routingHeaders := "" + routingHeadersMap := make(map[string]string) + if reg := regexp.MustCompile("(?P.*)"); reg.MatchString(req.GetParent()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetParent())[1])) > 0 { + routingHeadersMap["bucket"] = url.QueryEscape(reg.FindStringSubmatch(req.GetParent())[1]) + } + for headerName, headerValue := range routingHeadersMap { + routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue) + } + routingHeaders = strings.TrimSuffix(routingHeaders, "&") + md := metadata.Pairs("x-goog-request-params", routingHeaders) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).ListObjects[0:len((*c.CallOptions).ListObjects):len((*c.CallOptions).ListObjects)], opts...) + it := &ObjectIterator{} + req = proto.Clone(req).(*storagepb.ListObjectsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*storagepb.Object, string, error) { + resp := &storagepb.ListObjectsResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ListObjects(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + + it.Response = resp + return resp.GetObjects(), resp.GetNextPageToken(), nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +func (c *gRPCClient) RewriteObject(ctx context.Context, req *storagepb.RewriteObjectRequest, opts ...gax.CallOption) (*storagepb.RewriteResponse, error) { + routingHeaders := "" + routingHeadersMap := make(map[string]string) + if reg := regexp.MustCompile("(.*)"); reg.MatchString(req.GetSourceBucket()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetSourceBucket())[1])) > 0 { + routingHeadersMap["source_bucket"] = url.QueryEscape(reg.FindStringSubmatch(req.GetSourceBucket())[1]) + } + if reg := regexp.MustCompile("(?P.*)"); reg.MatchString(req.GetDestinationBucket()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetDestinationBucket())[1])) > 0 { + routingHeadersMap["bucket"] = url.QueryEscape(reg.FindStringSubmatch(req.GetDestinationBucket())[1]) + } + for headerName, headerValue := range routingHeadersMap { + routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue) + } + routingHeaders = strings.TrimSuffix(routingHeaders, "&") + md := metadata.Pairs("x-goog-request-params", routingHeaders) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).RewriteObject[0:len((*c.CallOptions).RewriteObject):len((*c.CallOptions).RewriteObject)], opts...) + var resp *storagepb.RewriteResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.RewriteObject(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *gRPCClient) StartResumableWrite(ctx context.Context, req *storagepb.StartResumableWriteRequest, opts ...gax.CallOption) (*storagepb.StartResumableWriteResponse, error) { + routingHeaders := "" + routingHeadersMap := make(map[string]string) + if reg := regexp.MustCompile("(?P.*)"); reg.MatchString(req.GetWriteObjectSpec().GetResource().GetBucket()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetWriteObjectSpec().GetResource().GetBucket())[1])) > 0 { + routingHeadersMap["bucket"] = url.QueryEscape(reg.FindStringSubmatch(req.GetWriteObjectSpec().GetResource().GetBucket())[1]) + } + for headerName, headerValue := range routingHeadersMap { + routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue) + } + routingHeaders = strings.TrimSuffix(routingHeaders, "&") + md := metadata.Pairs("x-goog-request-params", routingHeaders) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).StartResumableWrite[0:len((*c.CallOptions).StartResumableWrite):len((*c.CallOptions).StartResumableWrite)], opts...) + var resp *storagepb.StartResumableWriteResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.StartResumableWrite(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *gRPCClient) QueryWriteStatus(ctx context.Context, req *storagepb.QueryWriteStatusRequest, opts ...gax.CallOption) (*storagepb.QueryWriteStatusResponse, error) { + routingHeaders := "" + routingHeadersMap := make(map[string]string) + if reg := regexp.MustCompile("(?Pprojects/[^/]+/buckets/[^/]+)(?:/.*)?"); reg.MatchString(req.GetUploadId()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetUploadId())[1])) > 0 { + routingHeadersMap["bucket"] = url.QueryEscape(reg.FindStringSubmatch(req.GetUploadId())[1]) + } + for headerName, headerValue := range routingHeadersMap { + routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue) + } + routingHeaders = strings.TrimSuffix(routingHeaders, "&") + md := metadata.Pairs("x-goog-request-params", routingHeaders) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).QueryWriteStatus[0:len((*c.CallOptions).QueryWriteStatus):len((*c.CallOptions).QueryWriteStatus)], opts...) + var resp *storagepb.QueryWriteStatusResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.QueryWriteStatus(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *gRPCClient) GetServiceAccount(ctx context.Context, req *storagepb.GetServiceAccountRequest, opts ...gax.CallOption) (*storagepb.ServiceAccount, error) { + routingHeaders := "" + routingHeadersMap := make(map[string]string) + if reg := regexp.MustCompile("(.*)"); reg.MatchString(req.GetProject()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetProject())[1])) > 0 { + routingHeadersMap["project"] = url.QueryEscape(reg.FindStringSubmatch(req.GetProject())[1]) + } + for headerName, headerValue := range routingHeadersMap { + routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue) + } + routingHeaders = strings.TrimSuffix(routingHeaders, "&") + md := metadata.Pairs("x-goog-request-params", routingHeaders) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).GetServiceAccount[0:len((*c.CallOptions).GetServiceAccount):len((*c.CallOptions).GetServiceAccount)], opts...) + var resp *storagepb.ServiceAccount + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.GetServiceAccount(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *gRPCClient) CreateHmacKey(ctx context.Context, req *storagepb.CreateHmacKeyRequest, opts ...gax.CallOption) (*storagepb.CreateHmacKeyResponse, error) { + routingHeaders := "" + routingHeadersMap := make(map[string]string) + if reg := regexp.MustCompile("(.*)"); reg.MatchString(req.GetProject()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetProject())[1])) > 0 { + routingHeadersMap["project"] = url.QueryEscape(reg.FindStringSubmatch(req.GetProject())[1]) + } + for headerName, headerValue := range routingHeadersMap { + routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue) + } + routingHeaders = strings.TrimSuffix(routingHeaders, "&") + md := metadata.Pairs("x-goog-request-params", routingHeaders) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).CreateHmacKey[0:len((*c.CallOptions).CreateHmacKey):len((*c.CallOptions).CreateHmacKey)], opts...) + var resp *storagepb.CreateHmacKeyResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.CreateHmacKey(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *gRPCClient) DeleteHmacKey(ctx context.Context, req *storagepb.DeleteHmacKeyRequest, opts ...gax.CallOption) error { + routingHeaders := "" + routingHeadersMap := make(map[string]string) + if reg := regexp.MustCompile("(.*)"); reg.MatchString(req.GetProject()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetProject())[1])) > 0 { + routingHeadersMap["project"] = url.QueryEscape(reg.FindStringSubmatch(req.GetProject())[1]) + } + for headerName, headerValue := range routingHeadersMap { + routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue) + } + routingHeaders = strings.TrimSuffix(routingHeaders, "&") + md := metadata.Pairs("x-goog-request-params", routingHeaders) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).DeleteHmacKey[0:len((*c.CallOptions).DeleteHmacKey):len((*c.CallOptions).DeleteHmacKey)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.client.DeleteHmacKey(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +func (c *gRPCClient) GetHmacKey(ctx context.Context, req *storagepb.GetHmacKeyRequest, opts ...gax.CallOption) (*storagepb.HmacKeyMetadata, error) { + routingHeaders := "" + routingHeadersMap := make(map[string]string) + if reg := regexp.MustCompile("(.*)"); reg.MatchString(req.GetProject()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetProject())[1])) > 0 { + routingHeadersMap["project"] = url.QueryEscape(reg.FindStringSubmatch(req.GetProject())[1]) + } + for headerName, headerValue := range routingHeadersMap { + routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue) + } + routingHeaders = strings.TrimSuffix(routingHeaders, "&") + md := metadata.Pairs("x-goog-request-params", routingHeaders) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).GetHmacKey[0:len((*c.CallOptions).GetHmacKey):len((*c.CallOptions).GetHmacKey)], opts...) + var resp *storagepb.HmacKeyMetadata + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.GetHmacKey(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *gRPCClient) ListHmacKeys(ctx context.Context, req *storagepb.ListHmacKeysRequest, opts ...gax.CallOption) *HmacKeyMetadataIterator { + routingHeaders := "" + routingHeadersMap := make(map[string]string) + if reg := regexp.MustCompile("(.*)"); reg.MatchString(req.GetProject()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetProject())[1])) > 0 { + routingHeadersMap["project"] = url.QueryEscape(reg.FindStringSubmatch(req.GetProject())[1]) + } + for headerName, headerValue := range routingHeadersMap { + routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue) + } + routingHeaders = strings.TrimSuffix(routingHeaders, "&") + md := metadata.Pairs("x-goog-request-params", routingHeaders) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).ListHmacKeys[0:len((*c.CallOptions).ListHmacKeys):len((*c.CallOptions).ListHmacKeys)], opts...) + it := &HmacKeyMetadataIterator{} + req = proto.Clone(req).(*storagepb.ListHmacKeysRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*storagepb.HmacKeyMetadata, string, error) { + resp := &storagepb.ListHmacKeysResponse{} + if pageToken != "" { + req.PageToken = pageToken + } + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else if pageSize != 0 { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ListHmacKeys(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + + it.Response = resp + return resp.GetHmacKeys(), resp.GetNextPageToken(), nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetPageSize()) + it.pageInfo.Token = req.GetPageToken() + + return it +} + +func (c *gRPCClient) UpdateHmacKey(ctx context.Context, req *storagepb.UpdateHmacKeyRequest, opts ...gax.CallOption) (*storagepb.HmacKeyMetadata, error) { + routingHeaders := "" + routingHeadersMap := make(map[string]string) + if reg := regexp.MustCompile("(?P.*)"); reg.MatchString(req.GetHmacKey().GetProject()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetHmacKey().GetProject())[1])) > 0 { + routingHeadersMap["project"] = url.QueryEscape(reg.FindStringSubmatch(req.GetHmacKey().GetProject())[1]) + } + for headerName, headerValue := range routingHeadersMap { + routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue) + } + routingHeaders = strings.TrimSuffix(routingHeaders, "&") + md := metadata.Pairs("x-goog-request-params", routingHeaders) + + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append((*c.CallOptions).UpdateHmacKey[0:len((*c.CallOptions).UpdateHmacKey):len((*c.CallOptions).UpdateHmacKey)], opts...) + var resp *storagepb.HmacKeyMetadata + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.UpdateHmacKey(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// BucketIterator manages a stream of *storagepb.Bucket. +type BucketIterator struct { + items []*storagepb.Bucket + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*storagepb.Bucket, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *BucketIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *BucketIterator) Next() (*storagepb.Bucket, error) { + var item *storagepb.Bucket + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *BucketIterator) bufLen() int { + return len(it.items) +} + +func (it *BucketIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// HmacKeyMetadataIterator manages a stream of *storagepb.HmacKeyMetadata. +type HmacKeyMetadataIterator struct { + items []*storagepb.HmacKeyMetadata + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*storagepb.HmacKeyMetadata, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *HmacKeyMetadataIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *HmacKeyMetadataIterator) Next() (*storagepb.HmacKeyMetadata, error) { + var item *storagepb.HmacKeyMetadata + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *HmacKeyMetadataIterator) bufLen() int { + return len(it.items) +} + +func (it *HmacKeyMetadataIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// NotificationIterator manages a stream of *storagepb.Notification. +type NotificationIterator struct { + items []*storagepb.Notification + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*storagepb.Notification, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *NotificationIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *NotificationIterator) Next() (*storagepb.Notification, error) { + var item *storagepb.Notification + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *NotificationIterator) bufLen() int { + return len(it.items) +} + +func (it *NotificationIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// ObjectIterator manages a stream of *storagepb.Object. +type ObjectIterator struct { + items []*storagepb.Object + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*storagepb.Object, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *ObjectIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *ObjectIterator) Next() (*storagepb.Object, error) { + var item *storagepb.Object + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *ObjectIterator) bufLen() int { + return len(it.items) +} + +func (it *ObjectIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/vendor/cloud.google.com/go/storage/internal/apiv2/stubs/storage.pb.go b/vendor/cloud.google.com/go/storage/internal/apiv2/stubs/storage.pb.go new file mode 100644 index 00000000000..c36634b1a14 --- /dev/null +++ b/vendor/cloud.google.com/go/storage/internal/apiv2/stubs/storage.pb.go @@ -0,0 +1,10652 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.26.0 +// protoc v3.21.9 +// source: google/storage/v2/storage.proto + +package storage + +import ( + context "context" + reflect "reflect" + sync "sync" + + _ "google.golang.org/genproto/googleapis/api/annotations" + v1 "google.golang.org/genproto/googleapis/iam/v1" + date "google.golang.org/genproto/googleapis/type/date" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + emptypb "google.golang.org/protobuf/types/known/emptypb" + fieldmaskpb "google.golang.org/protobuf/types/known/fieldmaskpb" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// A collection of constant values meaningful to the Storage API. +type ServiceConstants_Values int32 + +const ( + // Unused. Proto3 requires first enum to be 0. + ServiceConstants_VALUES_UNSPECIFIED ServiceConstants_Values = 0 + // The maximum size chunk that can will be returned in a single + // ReadRequest. + // 2 MiB. + ServiceConstants_MAX_READ_CHUNK_BYTES ServiceConstants_Values = 2097152 + // The maximum size chunk that can be sent in a single WriteObjectRequest. + // 2 MiB. + ServiceConstants_MAX_WRITE_CHUNK_BYTES ServiceConstants_Values = 2097152 + // The maximum size of an object in MB - whether written in a single stream + // or composed from multiple other objects. + // 5 TiB. + ServiceConstants_MAX_OBJECT_SIZE_MB ServiceConstants_Values = 5242880 + // The maximum length field name that can be sent in a single + // custom metadata field. + // 1 KiB. + ServiceConstants_MAX_CUSTOM_METADATA_FIELD_NAME_BYTES ServiceConstants_Values = 1024 + // The maximum length field value that can be sent in a single + // custom_metadata field. + // 4 KiB. + ServiceConstants_MAX_CUSTOM_METADATA_FIELD_VALUE_BYTES ServiceConstants_Values = 4096 + // The maximum total bytes that can be populated into all field names and + // values of the custom_metadata for one object. + // 8 KiB. + ServiceConstants_MAX_CUSTOM_METADATA_TOTAL_SIZE_BYTES ServiceConstants_Values = 8192 + // The maximum total bytes that can be populated into all bucket metadata + // fields. + // 20 KiB. + ServiceConstants_MAX_BUCKET_METADATA_TOTAL_SIZE_BYTES ServiceConstants_Values = 20480 + // The maximum number of NotificationConfigs that can be registered + // for a given bucket. + ServiceConstants_MAX_NOTIFICATION_CONFIGS_PER_BUCKET ServiceConstants_Values = 100 + // The maximum number of LifecycleRules that can be registered for a given + // bucket. + ServiceConstants_MAX_LIFECYCLE_RULES_PER_BUCKET ServiceConstants_Values = 100 + // The maximum number of custom attributes per NotificationConfigs. + ServiceConstants_MAX_NOTIFICATION_CUSTOM_ATTRIBUTES ServiceConstants_Values = 5 + // The maximum length of a custom attribute key included in + // NotificationConfig. + ServiceConstants_MAX_NOTIFICATION_CUSTOM_ATTRIBUTE_KEY_LENGTH ServiceConstants_Values = 256 + // The maximum length of a custom attribute value included in a + // NotificationConfig. + ServiceConstants_MAX_NOTIFICATION_CUSTOM_ATTRIBUTE_VALUE_LENGTH ServiceConstants_Values = 1024 + // The maximum number of key/value entries per bucket label. + ServiceConstants_MAX_LABELS_ENTRIES_COUNT ServiceConstants_Values = 64 + // The maximum character length of the key or value in a bucket + // label map. + ServiceConstants_MAX_LABELS_KEY_VALUE_LENGTH ServiceConstants_Values = 63 + // The maximum byte size of the key or value in a bucket label + // map. + ServiceConstants_MAX_LABELS_KEY_VALUE_BYTES ServiceConstants_Values = 128 + // The maximum number of object IDs that can be included in a + // DeleteObjectsRequest. + ServiceConstants_MAX_OBJECT_IDS_PER_DELETE_OBJECTS_REQUEST ServiceConstants_Values = 1000 + // The maximum number of days for which a token returned by the + // GetListObjectsSplitPoints RPC is valid. + ServiceConstants_SPLIT_TOKEN_MAX_VALID_DAYS ServiceConstants_Values = 14 +) + +// Enum value maps for ServiceConstants_Values. +var ( + ServiceConstants_Values_name = map[int32]string{ + 0: "VALUES_UNSPECIFIED", + 2097152: "MAX_READ_CHUNK_BYTES", + // Duplicate value: 2097152: "MAX_WRITE_CHUNK_BYTES", + 5242880: "MAX_OBJECT_SIZE_MB", + 1024: "MAX_CUSTOM_METADATA_FIELD_NAME_BYTES", + 4096: "MAX_CUSTOM_METADATA_FIELD_VALUE_BYTES", + 8192: "MAX_CUSTOM_METADATA_TOTAL_SIZE_BYTES", + 20480: "MAX_BUCKET_METADATA_TOTAL_SIZE_BYTES", + 100: "MAX_NOTIFICATION_CONFIGS_PER_BUCKET", + // Duplicate value: 100: "MAX_LIFECYCLE_RULES_PER_BUCKET", + 5: "MAX_NOTIFICATION_CUSTOM_ATTRIBUTES", + 256: "MAX_NOTIFICATION_CUSTOM_ATTRIBUTE_KEY_LENGTH", + // Duplicate value: 1024: "MAX_NOTIFICATION_CUSTOM_ATTRIBUTE_VALUE_LENGTH", + 64: "MAX_LABELS_ENTRIES_COUNT", + 63: "MAX_LABELS_KEY_VALUE_LENGTH", + 128: "MAX_LABELS_KEY_VALUE_BYTES", + 1000: "MAX_OBJECT_IDS_PER_DELETE_OBJECTS_REQUEST", + 14: "SPLIT_TOKEN_MAX_VALID_DAYS", + } + ServiceConstants_Values_value = map[string]int32{ + "VALUES_UNSPECIFIED": 0, + "MAX_READ_CHUNK_BYTES": 2097152, + "MAX_WRITE_CHUNK_BYTES": 2097152, + "MAX_OBJECT_SIZE_MB": 5242880, + "MAX_CUSTOM_METADATA_FIELD_NAME_BYTES": 1024, + "MAX_CUSTOM_METADATA_FIELD_VALUE_BYTES": 4096, + "MAX_CUSTOM_METADATA_TOTAL_SIZE_BYTES": 8192, + "MAX_BUCKET_METADATA_TOTAL_SIZE_BYTES": 20480, + "MAX_NOTIFICATION_CONFIGS_PER_BUCKET": 100, + "MAX_LIFECYCLE_RULES_PER_BUCKET": 100, + "MAX_NOTIFICATION_CUSTOM_ATTRIBUTES": 5, + "MAX_NOTIFICATION_CUSTOM_ATTRIBUTE_KEY_LENGTH": 256, + "MAX_NOTIFICATION_CUSTOM_ATTRIBUTE_VALUE_LENGTH": 1024, + "MAX_LABELS_ENTRIES_COUNT": 64, + "MAX_LABELS_KEY_VALUE_LENGTH": 63, + "MAX_LABELS_KEY_VALUE_BYTES": 128, + "MAX_OBJECT_IDS_PER_DELETE_OBJECTS_REQUEST": 1000, + "SPLIT_TOKEN_MAX_VALID_DAYS": 14, + } +) + +func (x ServiceConstants_Values) Enum() *ServiceConstants_Values { + p := new(ServiceConstants_Values) + *p = x + return p +} + +func (x ServiceConstants_Values) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ServiceConstants_Values) Descriptor() protoreflect.EnumDescriptor { + return file_google_storage_v2_storage_proto_enumTypes[0].Descriptor() +} + +func (ServiceConstants_Values) Type() protoreflect.EnumType { + return &file_google_storage_v2_storage_proto_enumTypes[0] +} + +func (x ServiceConstants_Values) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ServiceConstants_Values.Descriptor instead. +func (ServiceConstants_Values) EnumDescriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{39, 0} +} + +// Request message for DeleteBucket. +type DeleteBucketRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Required. Name of a bucket to delete. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // If set, only deletes the bucket if its metageneration matches this value. + IfMetagenerationMatch *int64 `protobuf:"varint,2,opt,name=if_metageneration_match,json=ifMetagenerationMatch,proto3,oneof" json:"if_metageneration_match,omitempty"` + // If set, only deletes the bucket if its metageneration does not match this + // value. + IfMetagenerationNotMatch *int64 `protobuf:"varint,3,opt,name=if_metageneration_not_match,json=ifMetagenerationNotMatch,proto3,oneof" json:"if_metageneration_not_match,omitempty"` +} + +func (x *DeleteBucketRequest) Reset() { + *x = DeleteBucketRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteBucketRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteBucketRequest) ProtoMessage() {} + +func (x *DeleteBucketRequest) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteBucketRequest.ProtoReflect.Descriptor instead. +func (*DeleteBucketRequest) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{0} +} + +func (x *DeleteBucketRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *DeleteBucketRequest) GetIfMetagenerationMatch() int64 { + if x != nil && x.IfMetagenerationMatch != nil { + return *x.IfMetagenerationMatch + } + return 0 +} + +func (x *DeleteBucketRequest) GetIfMetagenerationNotMatch() int64 { + if x != nil && x.IfMetagenerationNotMatch != nil { + return *x.IfMetagenerationNotMatch + } + return 0 +} + +// Request message for GetBucket. +type GetBucketRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Required. Name of a bucket. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // If set, and if the bucket's current metageneration does not match the + // specified value, the request will return an error. + IfMetagenerationMatch *int64 `protobuf:"varint,2,opt,name=if_metageneration_match,json=ifMetagenerationMatch,proto3,oneof" json:"if_metageneration_match,omitempty"` + // If set, and if the bucket's current metageneration matches the specified + // value, the request will return an error. + IfMetagenerationNotMatch *int64 `protobuf:"varint,3,opt,name=if_metageneration_not_match,json=ifMetagenerationNotMatch,proto3,oneof" json:"if_metageneration_not_match,omitempty"` + // Mask specifying which fields to read. + // A "*" field may be used to indicate all fields. + // If no mask is specified, will default to all fields. + ReadMask *fieldmaskpb.FieldMask `protobuf:"bytes,5,opt,name=read_mask,json=readMask,proto3,oneof" json:"read_mask,omitempty"` +} + +func (x *GetBucketRequest) Reset() { + *x = GetBucketRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetBucketRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetBucketRequest) ProtoMessage() {} + +func (x *GetBucketRequest) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetBucketRequest.ProtoReflect.Descriptor instead. +func (*GetBucketRequest) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{1} +} + +func (x *GetBucketRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *GetBucketRequest) GetIfMetagenerationMatch() int64 { + if x != nil && x.IfMetagenerationMatch != nil { + return *x.IfMetagenerationMatch + } + return 0 +} + +func (x *GetBucketRequest) GetIfMetagenerationNotMatch() int64 { + if x != nil && x.IfMetagenerationNotMatch != nil { + return *x.IfMetagenerationNotMatch + } + return 0 +} + +func (x *GetBucketRequest) GetReadMask() *fieldmaskpb.FieldMask { + if x != nil { + return x.ReadMask + } + return nil +} + +// Request message for CreateBucket. +type CreateBucketRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Required. The project to which this bucket will belong. + Parent string `protobuf:"bytes,1,opt,name=parent,proto3" json:"parent,omitempty"` + // Properties of the new bucket being inserted. + // The project and name of the bucket are specified in the parent and + // bucket_id fields, respectively. Populating those fields in `bucket` will + // result in an error. + Bucket *Bucket `protobuf:"bytes,2,opt,name=bucket,proto3" json:"bucket,omitempty"` + // Required. The ID to use for this bucket, which will become the final component of + // the bucket's resource name. For example, the value `foo` might result in + // a bucket with the name `projects/123456/buckets/foo`. + BucketId string `protobuf:"bytes,3,opt,name=bucket_id,json=bucketId,proto3" json:"bucket_id,omitempty"` + // Apply a predefined set of access controls to this bucket. + // Valid values are "authenticatedRead", "private", "projectPrivate", + // "publicRead", or "publicReadWrite". + PredefinedAcl string `protobuf:"bytes,6,opt,name=predefined_acl,json=predefinedAcl,proto3" json:"predefined_acl,omitempty"` + // Apply a predefined set of default object access controls to this bucket. + // Valid values are "authenticatedRead", "bucketOwnerFullControl", + // "bucketOwnerRead", "private", "projectPrivate", or "publicRead". + PredefinedDefaultObjectAcl string `protobuf:"bytes,7,opt,name=predefined_default_object_acl,json=predefinedDefaultObjectAcl,proto3" json:"predefined_default_object_acl,omitempty"` +} + +func (x *CreateBucketRequest) Reset() { + *x = CreateBucketRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateBucketRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateBucketRequest) ProtoMessage() {} + +func (x *CreateBucketRequest) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateBucketRequest.ProtoReflect.Descriptor instead. +func (*CreateBucketRequest) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{2} +} + +func (x *CreateBucketRequest) GetParent() string { + if x != nil { + return x.Parent + } + return "" +} + +func (x *CreateBucketRequest) GetBucket() *Bucket { + if x != nil { + return x.Bucket + } + return nil +} + +func (x *CreateBucketRequest) GetBucketId() string { + if x != nil { + return x.BucketId + } + return "" +} + +func (x *CreateBucketRequest) GetPredefinedAcl() string { + if x != nil { + return x.PredefinedAcl + } + return "" +} + +func (x *CreateBucketRequest) GetPredefinedDefaultObjectAcl() string { + if x != nil { + return x.PredefinedDefaultObjectAcl + } + return "" +} + +// Request message for ListBuckets. +type ListBucketsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Required. The project whose buckets we are listing. + Parent string `protobuf:"bytes,1,opt,name=parent,proto3" json:"parent,omitempty"` + // Maximum number of buckets to return in a single response. The service will + // use this parameter or 1,000 items, whichever is smaller. If "acl" is + // present in the read_mask, the service will use this parameter of 200 items, + // whichever is smaller. + PageSize int32 `protobuf:"varint,2,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` + // A previously-returned page token representing part of the larger set of + // results to view. + PageToken string `protobuf:"bytes,3,opt,name=page_token,json=pageToken,proto3" json:"page_token,omitempty"` + // Filter results to buckets whose names begin with this prefix. + Prefix string `protobuf:"bytes,4,opt,name=prefix,proto3" json:"prefix,omitempty"` + // Mask specifying which fields to read from each result. + // If no mask is specified, will default to all fields except items.owner, + // items.acl, and items.default_object_acl. + // * may be used to mean "all fields". + ReadMask *fieldmaskpb.FieldMask `protobuf:"bytes,5,opt,name=read_mask,json=readMask,proto3,oneof" json:"read_mask,omitempty"` +} + +func (x *ListBucketsRequest) Reset() { + *x = ListBucketsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListBucketsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListBucketsRequest) ProtoMessage() {} + +func (x *ListBucketsRequest) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListBucketsRequest.ProtoReflect.Descriptor instead. +func (*ListBucketsRequest) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{3} +} + +func (x *ListBucketsRequest) GetParent() string { + if x != nil { + return x.Parent + } + return "" +} + +func (x *ListBucketsRequest) GetPageSize() int32 { + if x != nil { + return x.PageSize + } + return 0 +} + +func (x *ListBucketsRequest) GetPageToken() string { + if x != nil { + return x.PageToken + } + return "" +} + +func (x *ListBucketsRequest) GetPrefix() string { + if x != nil { + return x.Prefix + } + return "" +} + +func (x *ListBucketsRequest) GetReadMask() *fieldmaskpb.FieldMask { + if x != nil { + return x.ReadMask + } + return nil +} + +// The result of a call to Buckets.ListBuckets +type ListBucketsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The list of items. + Buckets []*Bucket `protobuf:"bytes,1,rep,name=buckets,proto3" json:"buckets,omitempty"` + // The continuation token, used to page through large result sets. Provide + // this value in a subsequent request to return the next page of results. + NextPageToken string `protobuf:"bytes,2,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"` +} + +func (x *ListBucketsResponse) Reset() { + *x = ListBucketsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListBucketsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListBucketsResponse) ProtoMessage() {} + +func (x *ListBucketsResponse) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListBucketsResponse.ProtoReflect.Descriptor instead. +func (*ListBucketsResponse) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{4} +} + +func (x *ListBucketsResponse) GetBuckets() []*Bucket { + if x != nil { + return x.Buckets + } + return nil +} + +func (x *ListBucketsResponse) GetNextPageToken() string { + if x != nil { + return x.NextPageToken + } + return "" +} + +// Request message for LockBucketRetentionPolicyRequest. +type LockBucketRetentionPolicyRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Required. Name of a bucket. + Bucket string `protobuf:"bytes,1,opt,name=bucket,proto3" json:"bucket,omitempty"` + // Required. Makes the operation conditional on whether bucket's current metageneration + // matches the given value. Must be positive. + IfMetagenerationMatch int64 `protobuf:"varint,2,opt,name=if_metageneration_match,json=ifMetagenerationMatch,proto3" json:"if_metageneration_match,omitempty"` +} + +func (x *LockBucketRetentionPolicyRequest) Reset() { + *x = LockBucketRetentionPolicyRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LockBucketRetentionPolicyRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LockBucketRetentionPolicyRequest) ProtoMessage() {} + +func (x *LockBucketRetentionPolicyRequest) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LockBucketRetentionPolicyRequest.ProtoReflect.Descriptor instead. +func (*LockBucketRetentionPolicyRequest) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{5} +} + +func (x *LockBucketRetentionPolicyRequest) GetBucket() string { + if x != nil { + return x.Bucket + } + return "" +} + +func (x *LockBucketRetentionPolicyRequest) GetIfMetagenerationMatch() int64 { + if x != nil { + return x.IfMetagenerationMatch + } + return 0 +} + +// Request for UpdateBucket method. +type UpdateBucketRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Required. The bucket to update. + // The bucket's `name` field will be used to identify the bucket. + Bucket *Bucket `protobuf:"bytes,1,opt,name=bucket,proto3" json:"bucket,omitempty"` + // If set, will only modify the bucket if its metageneration matches this + // value. + IfMetagenerationMatch *int64 `protobuf:"varint,2,opt,name=if_metageneration_match,json=ifMetagenerationMatch,proto3,oneof" json:"if_metageneration_match,omitempty"` + // If set, will only modify the bucket if its metageneration does not match + // this value. + IfMetagenerationNotMatch *int64 `protobuf:"varint,3,opt,name=if_metageneration_not_match,json=ifMetagenerationNotMatch,proto3,oneof" json:"if_metageneration_not_match,omitempty"` + // Apply a predefined set of access controls to this bucket. + // Valid values are "authenticatedRead", "private", "projectPrivate", + // "publicRead", or "publicReadWrite". + PredefinedAcl string `protobuf:"bytes,8,opt,name=predefined_acl,json=predefinedAcl,proto3" json:"predefined_acl,omitempty"` + // Apply a predefined set of default object access controls to this bucket. + // Valid values are "authenticatedRead", "bucketOwnerFullControl", + // "bucketOwnerRead", "private", "projectPrivate", or "publicRead". + PredefinedDefaultObjectAcl string `protobuf:"bytes,9,opt,name=predefined_default_object_acl,json=predefinedDefaultObjectAcl,proto3" json:"predefined_default_object_acl,omitempty"` + // Required. List of fields to be updated. + // + // To specify ALL fields, equivalent to the JSON API's "update" function, + // specify a single field with the value `*`. Note: not recommended. If a new + // field is introduced at a later time, an older client updating with the `*` + // may accidentally reset the new field's value. + // + // Not specifying any fields is an error. + // Not specifying a field while setting that field to a non-default value is + // an error. + UpdateMask *fieldmaskpb.FieldMask `protobuf:"bytes,6,opt,name=update_mask,json=updateMask,proto3" json:"update_mask,omitempty"` +} + +func (x *UpdateBucketRequest) Reset() { + *x = UpdateBucketRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateBucketRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateBucketRequest) ProtoMessage() {} + +func (x *UpdateBucketRequest) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateBucketRequest.ProtoReflect.Descriptor instead. +func (*UpdateBucketRequest) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{6} +} + +func (x *UpdateBucketRequest) GetBucket() *Bucket { + if x != nil { + return x.Bucket + } + return nil +} + +func (x *UpdateBucketRequest) GetIfMetagenerationMatch() int64 { + if x != nil && x.IfMetagenerationMatch != nil { + return *x.IfMetagenerationMatch + } + return 0 +} + +func (x *UpdateBucketRequest) GetIfMetagenerationNotMatch() int64 { + if x != nil && x.IfMetagenerationNotMatch != nil { + return *x.IfMetagenerationNotMatch + } + return 0 +} + +func (x *UpdateBucketRequest) GetPredefinedAcl() string { + if x != nil { + return x.PredefinedAcl + } + return "" +} + +func (x *UpdateBucketRequest) GetPredefinedDefaultObjectAcl() string { + if x != nil { + return x.PredefinedDefaultObjectAcl + } + return "" +} + +func (x *UpdateBucketRequest) GetUpdateMask() *fieldmaskpb.FieldMask { + if x != nil { + return x.UpdateMask + } + return nil +} + +// Request message for DeleteNotification. +type DeleteNotificationRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Required. The parent bucket of the notification. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` +} + +func (x *DeleteNotificationRequest) Reset() { + *x = DeleteNotificationRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteNotificationRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteNotificationRequest) ProtoMessage() {} + +func (x *DeleteNotificationRequest) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteNotificationRequest.ProtoReflect.Descriptor instead. +func (*DeleteNotificationRequest) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{7} +} + +func (x *DeleteNotificationRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +// Request message for GetNotification. +type GetNotificationRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Required. The parent bucket of the notification. + // Format: + // `projects/{project}/buckets/{bucket}/notificationConfigs/{notification}` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` +} + +func (x *GetNotificationRequest) Reset() { + *x = GetNotificationRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetNotificationRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetNotificationRequest) ProtoMessage() {} + +func (x *GetNotificationRequest) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetNotificationRequest.ProtoReflect.Descriptor instead. +func (*GetNotificationRequest) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{8} +} + +func (x *GetNotificationRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +// Request message for CreateNotification. +type CreateNotificationRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Required. The bucket to which this notification belongs. + Parent string `protobuf:"bytes,1,opt,name=parent,proto3" json:"parent,omitempty"` + // Required. Properties of the notification to be inserted. + Notification *Notification `protobuf:"bytes,2,opt,name=notification,proto3" json:"notification,omitempty"` +} + +func (x *CreateNotificationRequest) Reset() { + *x = CreateNotificationRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateNotificationRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateNotificationRequest) ProtoMessage() {} + +func (x *CreateNotificationRequest) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateNotificationRequest.ProtoReflect.Descriptor instead. +func (*CreateNotificationRequest) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{9} +} + +func (x *CreateNotificationRequest) GetParent() string { + if x != nil { + return x.Parent + } + return "" +} + +func (x *CreateNotificationRequest) GetNotification() *Notification { + if x != nil { + return x.Notification + } + return nil +} + +// Request message for ListNotifications. +type ListNotificationsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Required. Name of a Google Cloud Storage bucket. + Parent string `protobuf:"bytes,1,opt,name=parent,proto3" json:"parent,omitempty"` + // The maximum number of notifications to return. The service may return fewer + // than this value. + // The default value is 100. Specifying a value above 100 will result in a + // page_size of 100. + PageSize int32 `protobuf:"varint,2,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` + // A page token, received from a previous `ListNotifications` call. + // Provide this to retrieve the subsequent page. + // + // When paginating, all other parameters provided to `ListNotifications` must + // match the call that provided the page token. + PageToken string `protobuf:"bytes,3,opt,name=page_token,json=pageToken,proto3" json:"page_token,omitempty"` +} + +func (x *ListNotificationsRequest) Reset() { + *x = ListNotificationsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListNotificationsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListNotificationsRequest) ProtoMessage() {} + +func (x *ListNotificationsRequest) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListNotificationsRequest.ProtoReflect.Descriptor instead. +func (*ListNotificationsRequest) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{10} +} + +func (x *ListNotificationsRequest) GetParent() string { + if x != nil { + return x.Parent + } + return "" +} + +func (x *ListNotificationsRequest) GetPageSize() int32 { + if x != nil { + return x.PageSize + } + return 0 +} + +func (x *ListNotificationsRequest) GetPageToken() string { + if x != nil { + return x.PageToken + } + return "" +} + +// The result of a call to Notifications.ListNotifications +type ListNotificationsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The list of items. + Notifications []*Notification `protobuf:"bytes,1,rep,name=notifications,proto3" json:"notifications,omitempty"` + // A token, which can be sent as `page_token` to retrieve the next page. + // If this field is omitted, there are no subsequent pages. + NextPageToken string `protobuf:"bytes,2,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"` +} + +func (x *ListNotificationsResponse) Reset() { + *x = ListNotificationsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListNotificationsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListNotificationsResponse) ProtoMessage() {} + +func (x *ListNotificationsResponse) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListNotificationsResponse.ProtoReflect.Descriptor instead. +func (*ListNotificationsResponse) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{11} +} + +func (x *ListNotificationsResponse) GetNotifications() []*Notification { + if x != nil { + return x.Notifications + } + return nil +} + +func (x *ListNotificationsResponse) GetNextPageToken() string { + if x != nil { + return x.NextPageToken + } + return "" +} + +// Request message for ComposeObject. +type ComposeObjectRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Required. Properties of the resulting object. + Destination *Object `protobuf:"bytes,1,opt,name=destination,proto3" json:"destination,omitempty"` + // The list of source objects that will be concatenated into a single object. + SourceObjects []*ComposeObjectRequest_SourceObject `protobuf:"bytes,2,rep,name=source_objects,json=sourceObjects,proto3" json:"source_objects,omitempty"` + // Apply a predefined set of access controls to the destination object. + // Valid values are "authenticatedRead", "bucketOwnerFullControl", + // "bucketOwnerRead", "private", "projectPrivate", or "publicRead". + DestinationPredefinedAcl string `protobuf:"bytes,9,opt,name=destination_predefined_acl,json=destinationPredefinedAcl,proto3" json:"destination_predefined_acl,omitempty"` + // Makes the operation conditional on whether the object's current generation + // matches the given value. Setting to 0 makes the operation succeed only if + // there are no live versions of the object. + IfGenerationMatch *int64 `protobuf:"varint,4,opt,name=if_generation_match,json=ifGenerationMatch,proto3,oneof" json:"if_generation_match,omitempty"` + // Makes the operation conditional on whether the object's current + // metageneration matches the given value. + IfMetagenerationMatch *int64 `protobuf:"varint,5,opt,name=if_metageneration_match,json=ifMetagenerationMatch,proto3,oneof" json:"if_metageneration_match,omitempty"` + // Resource name of the Cloud KMS key, of the form + // `projects/my-project/locations/my-location/keyRings/my-kr/cryptoKeys/my-key`, + // that will be used to encrypt the object. Overrides the object + // metadata's `kms_key_name` value, if any. + KmsKey string `protobuf:"bytes,6,opt,name=kms_key,json=kmsKey,proto3" json:"kms_key,omitempty"` + // A set of parameters common to Storage API requests concerning an object. + CommonObjectRequestParams *CommonObjectRequestParams `protobuf:"bytes,7,opt,name=common_object_request_params,json=commonObjectRequestParams,proto3" json:"common_object_request_params,omitempty"` +} + +func (x *ComposeObjectRequest) Reset() { + *x = ComposeObjectRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ComposeObjectRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ComposeObjectRequest) ProtoMessage() {} + +func (x *ComposeObjectRequest) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ComposeObjectRequest.ProtoReflect.Descriptor instead. +func (*ComposeObjectRequest) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{12} +} + +func (x *ComposeObjectRequest) GetDestination() *Object { + if x != nil { + return x.Destination + } + return nil +} + +func (x *ComposeObjectRequest) GetSourceObjects() []*ComposeObjectRequest_SourceObject { + if x != nil { + return x.SourceObjects + } + return nil +} + +func (x *ComposeObjectRequest) GetDestinationPredefinedAcl() string { + if x != nil { + return x.DestinationPredefinedAcl + } + return "" +} + +func (x *ComposeObjectRequest) GetIfGenerationMatch() int64 { + if x != nil && x.IfGenerationMatch != nil { + return *x.IfGenerationMatch + } + return 0 +} + +func (x *ComposeObjectRequest) GetIfMetagenerationMatch() int64 { + if x != nil && x.IfMetagenerationMatch != nil { + return *x.IfMetagenerationMatch + } + return 0 +} + +func (x *ComposeObjectRequest) GetKmsKey() string { + if x != nil { + return x.KmsKey + } + return "" +} + +func (x *ComposeObjectRequest) GetCommonObjectRequestParams() *CommonObjectRequestParams { + if x != nil { + return x.CommonObjectRequestParams + } + return nil +} + +// Message for deleting an object. +// `bucket` and `object` **must** be set. +type DeleteObjectRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Required. Name of the bucket in which the object resides. + Bucket string `protobuf:"bytes,1,opt,name=bucket,proto3" json:"bucket,omitempty"` + // Required. The name of the object to delete (when not using a resumable write). + Object string `protobuf:"bytes,2,opt,name=object,proto3" json:"object,omitempty"` + // If present, permanently deletes a specific revision of this object (as + // opposed to the latest version, the default). + Generation int64 `protobuf:"varint,4,opt,name=generation,proto3" json:"generation,omitempty"` + // Makes the operation conditional on whether the object's current generation + // matches the given value. Setting to 0 makes the operation succeed only if + // there are no live versions of the object. + IfGenerationMatch *int64 `protobuf:"varint,5,opt,name=if_generation_match,json=ifGenerationMatch,proto3,oneof" json:"if_generation_match,omitempty"` + // Makes the operation conditional on whether the object's live generation + // does not match the given value. If no live object exists, the precondition + // fails. Setting to 0 makes the operation succeed only if there is a live + // version of the object. + IfGenerationNotMatch *int64 `protobuf:"varint,6,opt,name=if_generation_not_match,json=ifGenerationNotMatch,proto3,oneof" json:"if_generation_not_match,omitempty"` + // Makes the operation conditional on whether the object's current + // metageneration matches the given value. + IfMetagenerationMatch *int64 `protobuf:"varint,7,opt,name=if_metageneration_match,json=ifMetagenerationMatch,proto3,oneof" json:"if_metageneration_match,omitempty"` + // Makes the operation conditional on whether the object's current + // metageneration does not match the given value. + IfMetagenerationNotMatch *int64 `protobuf:"varint,8,opt,name=if_metageneration_not_match,json=ifMetagenerationNotMatch,proto3,oneof" json:"if_metageneration_not_match,omitempty"` + // A set of parameters common to Storage API requests concerning an object. + CommonObjectRequestParams *CommonObjectRequestParams `protobuf:"bytes,10,opt,name=common_object_request_params,json=commonObjectRequestParams,proto3" json:"common_object_request_params,omitempty"` +} + +func (x *DeleteObjectRequest) Reset() { + *x = DeleteObjectRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteObjectRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteObjectRequest) ProtoMessage() {} + +func (x *DeleteObjectRequest) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteObjectRequest.ProtoReflect.Descriptor instead. +func (*DeleteObjectRequest) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{13} +} + +func (x *DeleteObjectRequest) GetBucket() string { + if x != nil { + return x.Bucket + } + return "" +} + +func (x *DeleteObjectRequest) GetObject() string { + if x != nil { + return x.Object + } + return "" +} + +func (x *DeleteObjectRequest) GetGeneration() int64 { + if x != nil { + return x.Generation + } + return 0 +} + +func (x *DeleteObjectRequest) GetIfGenerationMatch() int64 { + if x != nil && x.IfGenerationMatch != nil { + return *x.IfGenerationMatch + } + return 0 +} + +func (x *DeleteObjectRequest) GetIfGenerationNotMatch() int64 { + if x != nil && x.IfGenerationNotMatch != nil { + return *x.IfGenerationNotMatch + } + return 0 +} + +func (x *DeleteObjectRequest) GetIfMetagenerationMatch() int64 { + if x != nil && x.IfMetagenerationMatch != nil { + return *x.IfMetagenerationMatch + } + return 0 +} + +func (x *DeleteObjectRequest) GetIfMetagenerationNotMatch() int64 { + if x != nil && x.IfMetagenerationNotMatch != nil { + return *x.IfMetagenerationNotMatch + } + return 0 +} + +func (x *DeleteObjectRequest) GetCommonObjectRequestParams() *CommonObjectRequestParams { + if x != nil { + return x.CommonObjectRequestParams + } + return nil +} + +// Message for canceling an in-progress resumable upload. +// `upload_id` **must** be set. +type CancelResumableWriteRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Required. The upload_id of the resumable upload to cancel. This should be copied + // from the `upload_id` field of `StartResumableWriteResponse`. + UploadId string `protobuf:"bytes,1,opt,name=upload_id,json=uploadId,proto3" json:"upload_id,omitempty"` +} + +func (x *CancelResumableWriteRequest) Reset() { + *x = CancelResumableWriteRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CancelResumableWriteRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CancelResumableWriteRequest) ProtoMessage() {} + +func (x *CancelResumableWriteRequest) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CancelResumableWriteRequest.ProtoReflect.Descriptor instead. +func (*CancelResumableWriteRequest) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{14} +} + +func (x *CancelResumableWriteRequest) GetUploadId() string { + if x != nil { + return x.UploadId + } + return "" +} + +// Empty response message for canceling an in-progress resumable upload, will be +// extended as needed. +type CancelResumableWriteResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *CancelResumableWriteResponse) Reset() { + *x = CancelResumableWriteResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CancelResumableWriteResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CancelResumableWriteResponse) ProtoMessage() {} + +func (x *CancelResumableWriteResponse) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CancelResumableWriteResponse.ProtoReflect.Descriptor instead. +func (*CancelResumableWriteResponse) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{15} +} + +// Request message for ReadObject. +type ReadObjectRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Required. The name of the bucket containing the object to read. + Bucket string `protobuf:"bytes,1,opt,name=bucket,proto3" json:"bucket,omitempty"` + // Required. The name of the object to read. + Object string `protobuf:"bytes,2,opt,name=object,proto3" json:"object,omitempty"` + // If present, selects a specific revision of this object (as opposed + // to the latest version, the default). + Generation int64 `protobuf:"varint,3,opt,name=generation,proto3" json:"generation,omitempty"` + // The offset for the first byte to return in the read, relative to the start + // of the object. + // + // A negative `read_offset` value will be interpreted as the number of bytes + // back from the end of the object to be returned. For example, if an object's + // length is 15 bytes, a ReadObjectRequest with `read_offset` = -5 and + // `read_limit` = 3 would return bytes 10 through 12 of the object. Requesting + // a negative offset with magnitude larger than the size of the object will + // return the entire object. + ReadOffset int64 `protobuf:"varint,4,opt,name=read_offset,json=readOffset,proto3" json:"read_offset,omitempty"` + // The maximum number of `data` bytes the server is allowed to return in the + // sum of all `Object` messages. A `read_limit` of zero indicates that there + // is no limit, and a negative `read_limit` will cause an error. + // + // If the stream returns fewer bytes than allowed by the `read_limit` and no + // error occurred, the stream includes all data from the `read_offset` to the + // end of the resource. + ReadLimit int64 `protobuf:"varint,5,opt,name=read_limit,json=readLimit,proto3" json:"read_limit,omitempty"` + // Makes the operation conditional on whether the object's current generation + // matches the given value. Setting to 0 makes the operation succeed only if + // there are no live versions of the object. + IfGenerationMatch *int64 `protobuf:"varint,6,opt,name=if_generation_match,json=ifGenerationMatch,proto3,oneof" json:"if_generation_match,omitempty"` + // Makes the operation conditional on whether the object's live generation + // does not match the given value. If no live object exists, the precondition + // fails. Setting to 0 makes the operation succeed only if there is a live + // version of the object. + IfGenerationNotMatch *int64 `protobuf:"varint,7,opt,name=if_generation_not_match,json=ifGenerationNotMatch,proto3,oneof" json:"if_generation_not_match,omitempty"` + // Makes the operation conditional on whether the object's current + // metageneration matches the given value. + IfMetagenerationMatch *int64 `protobuf:"varint,8,opt,name=if_metageneration_match,json=ifMetagenerationMatch,proto3,oneof" json:"if_metageneration_match,omitempty"` + // Makes the operation conditional on whether the object's current + // metageneration does not match the given value. + IfMetagenerationNotMatch *int64 `protobuf:"varint,9,opt,name=if_metageneration_not_match,json=ifMetagenerationNotMatch,proto3,oneof" json:"if_metageneration_not_match,omitempty"` + // A set of parameters common to Storage API requests concerning an object. + CommonObjectRequestParams *CommonObjectRequestParams `protobuf:"bytes,10,opt,name=common_object_request_params,json=commonObjectRequestParams,proto3" json:"common_object_request_params,omitempty"` + // Mask specifying which fields to read. + // The checksummed_data field and its children will always be present. + // If no mask is specified, will default to all fields except metadata.owner + // and metadata.acl. + // * may be used to mean "all fields". + ReadMask *fieldmaskpb.FieldMask `protobuf:"bytes,12,opt,name=read_mask,json=readMask,proto3,oneof" json:"read_mask,omitempty"` +} + +func (x *ReadObjectRequest) Reset() { + *x = ReadObjectRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ReadObjectRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReadObjectRequest) ProtoMessage() {} + +func (x *ReadObjectRequest) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[16] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReadObjectRequest.ProtoReflect.Descriptor instead. +func (*ReadObjectRequest) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{16} +} + +func (x *ReadObjectRequest) GetBucket() string { + if x != nil { + return x.Bucket + } + return "" +} + +func (x *ReadObjectRequest) GetObject() string { + if x != nil { + return x.Object + } + return "" +} + +func (x *ReadObjectRequest) GetGeneration() int64 { + if x != nil { + return x.Generation + } + return 0 +} + +func (x *ReadObjectRequest) GetReadOffset() int64 { + if x != nil { + return x.ReadOffset + } + return 0 +} + +func (x *ReadObjectRequest) GetReadLimit() int64 { + if x != nil { + return x.ReadLimit + } + return 0 +} + +func (x *ReadObjectRequest) GetIfGenerationMatch() int64 { + if x != nil && x.IfGenerationMatch != nil { + return *x.IfGenerationMatch + } + return 0 +} + +func (x *ReadObjectRequest) GetIfGenerationNotMatch() int64 { + if x != nil && x.IfGenerationNotMatch != nil { + return *x.IfGenerationNotMatch + } + return 0 +} + +func (x *ReadObjectRequest) GetIfMetagenerationMatch() int64 { + if x != nil && x.IfMetagenerationMatch != nil { + return *x.IfMetagenerationMatch + } + return 0 +} + +func (x *ReadObjectRequest) GetIfMetagenerationNotMatch() int64 { + if x != nil && x.IfMetagenerationNotMatch != nil { + return *x.IfMetagenerationNotMatch + } + return 0 +} + +func (x *ReadObjectRequest) GetCommonObjectRequestParams() *CommonObjectRequestParams { + if x != nil { + return x.CommonObjectRequestParams + } + return nil +} + +func (x *ReadObjectRequest) GetReadMask() *fieldmaskpb.FieldMask { + if x != nil { + return x.ReadMask + } + return nil +} + +// Request message for GetObject. +type GetObjectRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Required. Name of the bucket in which the object resides. + Bucket string `protobuf:"bytes,1,opt,name=bucket,proto3" json:"bucket,omitempty"` + // Required. Name of the object. + Object string `protobuf:"bytes,2,opt,name=object,proto3" json:"object,omitempty"` + // If present, selects a specific revision of this object (as opposed to the + // latest version, the default). + Generation int64 `protobuf:"varint,3,opt,name=generation,proto3" json:"generation,omitempty"` + // Makes the operation conditional on whether the object's current generation + // matches the given value. Setting to 0 makes the operation succeed only if + // there are no live versions of the object. + IfGenerationMatch *int64 `protobuf:"varint,4,opt,name=if_generation_match,json=ifGenerationMatch,proto3,oneof" json:"if_generation_match,omitempty"` + // Makes the operation conditional on whether the object's live generation + // does not match the given value. If no live object exists, the precondition + // fails. Setting to 0 makes the operation succeed only if there is a live + // version of the object. + IfGenerationNotMatch *int64 `protobuf:"varint,5,opt,name=if_generation_not_match,json=ifGenerationNotMatch,proto3,oneof" json:"if_generation_not_match,omitempty"` + // Makes the operation conditional on whether the object's current + // metageneration matches the given value. + IfMetagenerationMatch *int64 `protobuf:"varint,6,opt,name=if_metageneration_match,json=ifMetagenerationMatch,proto3,oneof" json:"if_metageneration_match,omitempty"` + // Makes the operation conditional on whether the object's current + // metageneration does not match the given value. + IfMetagenerationNotMatch *int64 `protobuf:"varint,7,opt,name=if_metageneration_not_match,json=ifMetagenerationNotMatch,proto3,oneof" json:"if_metageneration_not_match,omitempty"` + // A set of parameters common to Storage API requests concerning an object. + CommonObjectRequestParams *CommonObjectRequestParams `protobuf:"bytes,8,opt,name=common_object_request_params,json=commonObjectRequestParams,proto3" json:"common_object_request_params,omitempty"` + // Mask specifying which fields to read. + // If no mask is specified, will default to all fields except metadata.acl and + // metadata.owner. + // * may be used to mean "all fields". + ReadMask *fieldmaskpb.FieldMask `protobuf:"bytes,10,opt,name=read_mask,json=readMask,proto3,oneof" json:"read_mask,omitempty"` +} + +func (x *GetObjectRequest) Reset() { + *x = GetObjectRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetObjectRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetObjectRequest) ProtoMessage() {} + +func (x *GetObjectRequest) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[17] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetObjectRequest.ProtoReflect.Descriptor instead. +func (*GetObjectRequest) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{17} +} + +func (x *GetObjectRequest) GetBucket() string { + if x != nil { + return x.Bucket + } + return "" +} + +func (x *GetObjectRequest) GetObject() string { + if x != nil { + return x.Object + } + return "" +} + +func (x *GetObjectRequest) GetGeneration() int64 { + if x != nil { + return x.Generation + } + return 0 +} + +func (x *GetObjectRequest) GetIfGenerationMatch() int64 { + if x != nil && x.IfGenerationMatch != nil { + return *x.IfGenerationMatch + } + return 0 +} + +func (x *GetObjectRequest) GetIfGenerationNotMatch() int64 { + if x != nil && x.IfGenerationNotMatch != nil { + return *x.IfGenerationNotMatch + } + return 0 +} + +func (x *GetObjectRequest) GetIfMetagenerationMatch() int64 { + if x != nil && x.IfMetagenerationMatch != nil { + return *x.IfMetagenerationMatch + } + return 0 +} + +func (x *GetObjectRequest) GetIfMetagenerationNotMatch() int64 { + if x != nil && x.IfMetagenerationNotMatch != nil { + return *x.IfMetagenerationNotMatch + } + return 0 +} + +func (x *GetObjectRequest) GetCommonObjectRequestParams() *CommonObjectRequestParams { + if x != nil { + return x.CommonObjectRequestParams + } + return nil +} + +func (x *GetObjectRequest) GetReadMask() *fieldmaskpb.FieldMask { + if x != nil { + return x.ReadMask + } + return nil +} + +// Response message for ReadObject. +type ReadObjectResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // A portion of the data for the object. The service **may** leave `data` + // empty for any given `ReadResponse`. This enables the service to inform the + // client that the request is still live while it is running an operation to + // generate more data. + ChecksummedData *ChecksummedData `protobuf:"bytes,1,opt,name=checksummed_data,json=checksummedData,proto3" json:"checksummed_data,omitempty"` + // The checksums of the complete object. The client should compute one of + // these checksums over the downloaded object and compare it against the value + // provided here. + ObjectChecksums *ObjectChecksums `protobuf:"bytes,2,opt,name=object_checksums,json=objectChecksums,proto3" json:"object_checksums,omitempty"` + // If read_offset and or read_limit was specified on the + // ReadObjectRequest, ContentRange will be populated on the first + // ReadObjectResponse message of the read stream. + ContentRange *ContentRange `protobuf:"bytes,3,opt,name=content_range,json=contentRange,proto3" json:"content_range,omitempty"` + // Metadata of the object whose media is being returned. + // Only populated in the first response in the stream. + Metadata *Object `protobuf:"bytes,4,opt,name=metadata,proto3" json:"metadata,omitempty"` +} + +func (x *ReadObjectResponse) Reset() { + *x = ReadObjectResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ReadObjectResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReadObjectResponse) ProtoMessage() {} + +func (x *ReadObjectResponse) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[18] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReadObjectResponse.ProtoReflect.Descriptor instead. +func (*ReadObjectResponse) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{18} +} + +func (x *ReadObjectResponse) GetChecksummedData() *ChecksummedData { + if x != nil { + return x.ChecksummedData + } + return nil +} + +func (x *ReadObjectResponse) GetObjectChecksums() *ObjectChecksums { + if x != nil { + return x.ObjectChecksums + } + return nil +} + +func (x *ReadObjectResponse) GetContentRange() *ContentRange { + if x != nil { + return x.ContentRange + } + return nil +} + +func (x *ReadObjectResponse) GetMetadata() *Object { + if x != nil { + return x.Metadata + } + return nil +} + +// Describes an attempt to insert an object, possibly over multiple requests. +type WriteObjectSpec struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Required. Destination object, including its name and its metadata. + Resource *Object `protobuf:"bytes,1,opt,name=resource,proto3" json:"resource,omitempty"` + // Apply a predefined set of access controls to this object. + // Valid values are "authenticatedRead", "bucketOwnerFullControl", + // "bucketOwnerRead", "private", "projectPrivate", or "publicRead". + PredefinedAcl string `protobuf:"bytes,7,opt,name=predefined_acl,json=predefinedAcl,proto3" json:"predefined_acl,omitempty"` + // Makes the operation conditional on whether the object's current + // generation matches the given value. Setting to 0 makes the operation + // succeed only if there are no live versions of the object. + IfGenerationMatch *int64 `protobuf:"varint,3,opt,name=if_generation_match,json=ifGenerationMatch,proto3,oneof" json:"if_generation_match,omitempty"` + // Makes the operation conditional on whether the object's live + // generation does not match the given value. If no live object exists, the + // precondition fails. Setting to 0 makes the operation succeed only if + // there is a live version of the object. + IfGenerationNotMatch *int64 `protobuf:"varint,4,opt,name=if_generation_not_match,json=ifGenerationNotMatch,proto3,oneof" json:"if_generation_not_match,omitempty"` + // Makes the operation conditional on whether the object's current + // metageneration matches the given value. + IfMetagenerationMatch *int64 `protobuf:"varint,5,opt,name=if_metageneration_match,json=ifMetagenerationMatch,proto3,oneof" json:"if_metageneration_match,omitempty"` + // Makes the operation conditional on whether the object's current + // metageneration does not match the given value. + IfMetagenerationNotMatch *int64 `protobuf:"varint,6,opt,name=if_metageneration_not_match,json=ifMetagenerationNotMatch,proto3,oneof" json:"if_metageneration_not_match,omitempty"` + // The expected final object size being uploaded. + // If this value is set, closing the stream after writing fewer or more than + // `object_size` bytes will result in an OUT_OF_RANGE error. + // + // This situation is considered a client error, and if such an error occurs + // you must start the upload over from scratch, this time sending the correct + // number of bytes. + // + // The `object_size` value is ignored for one-shot (non-resumable) writes. + ObjectSize *int64 `protobuf:"varint,8,opt,name=object_size,json=objectSize,proto3,oneof" json:"object_size,omitempty"` +} + +func (x *WriteObjectSpec) Reset() { + *x = WriteObjectSpec{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *WriteObjectSpec) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WriteObjectSpec) ProtoMessage() {} + +func (x *WriteObjectSpec) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[19] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WriteObjectSpec.ProtoReflect.Descriptor instead. +func (*WriteObjectSpec) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{19} +} + +func (x *WriteObjectSpec) GetResource() *Object { + if x != nil { + return x.Resource + } + return nil +} + +func (x *WriteObjectSpec) GetPredefinedAcl() string { + if x != nil { + return x.PredefinedAcl + } + return "" +} + +func (x *WriteObjectSpec) GetIfGenerationMatch() int64 { + if x != nil && x.IfGenerationMatch != nil { + return *x.IfGenerationMatch + } + return 0 +} + +func (x *WriteObjectSpec) GetIfGenerationNotMatch() int64 { + if x != nil && x.IfGenerationNotMatch != nil { + return *x.IfGenerationNotMatch + } + return 0 +} + +func (x *WriteObjectSpec) GetIfMetagenerationMatch() int64 { + if x != nil && x.IfMetagenerationMatch != nil { + return *x.IfMetagenerationMatch + } + return 0 +} + +func (x *WriteObjectSpec) GetIfMetagenerationNotMatch() int64 { + if x != nil && x.IfMetagenerationNotMatch != nil { + return *x.IfMetagenerationNotMatch + } + return 0 +} + +func (x *WriteObjectSpec) GetObjectSize() int64 { + if x != nil && x.ObjectSize != nil { + return *x.ObjectSize + } + return 0 +} + +// Request message for WriteObject. +type WriteObjectRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The first message of each stream should set one of the following. + // + // Types that are assignable to FirstMessage: + // + // *WriteObjectRequest_UploadId + // *WriteObjectRequest_WriteObjectSpec + FirstMessage isWriteObjectRequest_FirstMessage `protobuf_oneof:"first_message"` + // Required. The offset from the beginning of the object at which the data should be + // written. + // + // In the first `WriteObjectRequest` of a `WriteObject()` action, it + // indicates the initial offset for the `Write()` call. The value **must** be + // equal to the `persisted_size` that a call to `QueryWriteStatus()` would + // return (0 if this is the first write to the object). + // + // On subsequent calls, this value **must** be no larger than the sum of the + // first `write_offset` and the sizes of all `data` chunks sent previously on + // this stream. + // + // An incorrect value will cause an error. + WriteOffset int64 `protobuf:"varint,3,opt,name=write_offset,json=writeOffset,proto3" json:"write_offset,omitempty"` + // A portion of the data for the object. + // + // Types that are assignable to Data: + // + // *WriteObjectRequest_ChecksummedData + Data isWriteObjectRequest_Data `protobuf_oneof:"data"` + // Checksums for the complete object. If the checksums computed by the service + // don't match the specifified checksums the call will fail. May only be + // provided in the first or last request (either with first_message, or + // finish_write set). + ObjectChecksums *ObjectChecksums `protobuf:"bytes,6,opt,name=object_checksums,json=objectChecksums,proto3" json:"object_checksums,omitempty"` + // If `true`, this indicates that the write is complete. Sending any + // `WriteObjectRequest`s subsequent to one in which `finish_write` is `true` + // will cause an error. + // For a non-resumable write (where the upload_id was not set in the first + // message), it is an error not to set this field in the final message of the + // stream. + FinishWrite bool `protobuf:"varint,7,opt,name=finish_write,json=finishWrite,proto3" json:"finish_write,omitempty"` + // A set of parameters common to Storage API requests concerning an object. + CommonObjectRequestParams *CommonObjectRequestParams `protobuf:"bytes,8,opt,name=common_object_request_params,json=commonObjectRequestParams,proto3" json:"common_object_request_params,omitempty"` +} + +func (x *WriteObjectRequest) Reset() { + *x = WriteObjectRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *WriteObjectRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WriteObjectRequest) ProtoMessage() {} + +func (x *WriteObjectRequest) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[20] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WriteObjectRequest.ProtoReflect.Descriptor instead. +func (*WriteObjectRequest) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{20} +} + +func (m *WriteObjectRequest) GetFirstMessage() isWriteObjectRequest_FirstMessage { + if m != nil { + return m.FirstMessage + } + return nil +} + +func (x *WriteObjectRequest) GetUploadId() string { + if x, ok := x.GetFirstMessage().(*WriteObjectRequest_UploadId); ok { + return x.UploadId + } + return "" +} + +func (x *WriteObjectRequest) GetWriteObjectSpec() *WriteObjectSpec { + if x, ok := x.GetFirstMessage().(*WriteObjectRequest_WriteObjectSpec); ok { + return x.WriteObjectSpec + } + return nil +} + +func (x *WriteObjectRequest) GetWriteOffset() int64 { + if x != nil { + return x.WriteOffset + } + return 0 +} + +func (m *WriteObjectRequest) GetData() isWriteObjectRequest_Data { + if m != nil { + return m.Data + } + return nil +} + +func (x *WriteObjectRequest) GetChecksummedData() *ChecksummedData { + if x, ok := x.GetData().(*WriteObjectRequest_ChecksummedData); ok { + return x.ChecksummedData + } + return nil +} + +func (x *WriteObjectRequest) GetObjectChecksums() *ObjectChecksums { + if x != nil { + return x.ObjectChecksums + } + return nil +} + +func (x *WriteObjectRequest) GetFinishWrite() bool { + if x != nil { + return x.FinishWrite + } + return false +} + +func (x *WriteObjectRequest) GetCommonObjectRequestParams() *CommonObjectRequestParams { + if x != nil { + return x.CommonObjectRequestParams + } + return nil +} + +type isWriteObjectRequest_FirstMessage interface { + isWriteObjectRequest_FirstMessage() +} + +type WriteObjectRequest_UploadId struct { + // For resumable uploads. This should be the `upload_id` returned from a + // call to `StartResumableWriteResponse`. + UploadId string `protobuf:"bytes,1,opt,name=upload_id,json=uploadId,proto3,oneof"` +} + +type WriteObjectRequest_WriteObjectSpec struct { + // For non-resumable uploads. Describes the overall upload, including the + // destination bucket and object name, preconditions, etc. + WriteObjectSpec *WriteObjectSpec `protobuf:"bytes,2,opt,name=write_object_spec,json=writeObjectSpec,proto3,oneof"` +} + +func (*WriteObjectRequest_UploadId) isWriteObjectRequest_FirstMessage() {} + +func (*WriteObjectRequest_WriteObjectSpec) isWriteObjectRequest_FirstMessage() {} + +type isWriteObjectRequest_Data interface { + isWriteObjectRequest_Data() +} + +type WriteObjectRequest_ChecksummedData struct { + // The data to insert. If a crc32c checksum is provided that doesn't match + // the checksum computed by the service, the request will fail. + ChecksummedData *ChecksummedData `protobuf:"bytes,4,opt,name=checksummed_data,json=checksummedData,proto3,oneof"` +} + +func (*WriteObjectRequest_ChecksummedData) isWriteObjectRequest_Data() {} + +// Response message for WriteObject. +type WriteObjectResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The response will set one of the following. + // + // Types that are assignable to WriteStatus: + // + // *WriteObjectResponse_PersistedSize + // *WriteObjectResponse_Resource + WriteStatus isWriteObjectResponse_WriteStatus `protobuf_oneof:"write_status"` +} + +func (x *WriteObjectResponse) Reset() { + *x = WriteObjectResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *WriteObjectResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WriteObjectResponse) ProtoMessage() {} + +func (x *WriteObjectResponse) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[21] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WriteObjectResponse.ProtoReflect.Descriptor instead. +func (*WriteObjectResponse) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{21} +} + +func (m *WriteObjectResponse) GetWriteStatus() isWriteObjectResponse_WriteStatus { + if m != nil { + return m.WriteStatus + } + return nil +} + +func (x *WriteObjectResponse) GetPersistedSize() int64 { + if x, ok := x.GetWriteStatus().(*WriteObjectResponse_PersistedSize); ok { + return x.PersistedSize + } + return 0 +} + +func (x *WriteObjectResponse) GetResource() *Object { + if x, ok := x.GetWriteStatus().(*WriteObjectResponse_Resource); ok { + return x.Resource + } + return nil +} + +type isWriteObjectResponse_WriteStatus interface { + isWriteObjectResponse_WriteStatus() +} + +type WriteObjectResponse_PersistedSize struct { + // The total number of bytes that have been processed for the given object + // from all `WriteObject` calls. Only set if the upload has not finalized. + PersistedSize int64 `protobuf:"varint,1,opt,name=persisted_size,json=persistedSize,proto3,oneof"` +} + +type WriteObjectResponse_Resource struct { + // A resource containing the metadata for the uploaded object. Only set if + // the upload has finalized. + Resource *Object `protobuf:"bytes,2,opt,name=resource,proto3,oneof"` +} + +func (*WriteObjectResponse_PersistedSize) isWriteObjectResponse_WriteStatus() {} + +func (*WriteObjectResponse_Resource) isWriteObjectResponse_WriteStatus() {} + +// Request message for ListObjects. +type ListObjectsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Required. Name of the bucket in which to look for objects. + Parent string `protobuf:"bytes,1,opt,name=parent,proto3" json:"parent,omitempty"` + // Maximum number of `items` plus `prefixes` to return + // in a single page of responses. As duplicate `prefixes` are + // omitted, fewer total results may be returned than requested. The service + // will use this parameter or 1,000 items, whichever is smaller. + PageSize int32 `protobuf:"varint,2,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` + // A previously-returned page token representing part of the larger set of + // results to view. + PageToken string `protobuf:"bytes,3,opt,name=page_token,json=pageToken,proto3" json:"page_token,omitempty"` + // If set, returns results in a directory-like mode. `items` will contain + // only objects whose names, aside from the `prefix`, do not + // contain `delimiter`. Objects whose names, aside from the + // `prefix`, contain `delimiter` will have their name, + // truncated after the `delimiter`, returned in + // `prefixes`. Duplicate `prefixes` are omitted. + Delimiter string `protobuf:"bytes,4,opt,name=delimiter,proto3" json:"delimiter,omitempty"` + // If true, objects that end in exactly one instance of `delimiter` + // will have their metadata included in `items` in addition to + // `prefixes`. + IncludeTrailingDelimiter bool `protobuf:"varint,5,opt,name=include_trailing_delimiter,json=includeTrailingDelimiter,proto3" json:"include_trailing_delimiter,omitempty"` + // Filter results to objects whose names begin with this prefix. + Prefix string `protobuf:"bytes,6,opt,name=prefix,proto3" json:"prefix,omitempty"` + // If `true`, lists all versions of an object as distinct results. + // For more information, see + // [Object + // Versioning](https://cloud.google.com/storage/docs/object-versioning). + Versions bool `protobuf:"varint,7,opt,name=versions,proto3" json:"versions,omitempty"` + // Mask specifying which fields to read from each result. + // If no mask is specified, will default to all fields except items.acl and + // items.owner. + // * may be used to mean "all fields". + ReadMask *fieldmaskpb.FieldMask `protobuf:"bytes,8,opt,name=read_mask,json=readMask,proto3,oneof" json:"read_mask,omitempty"` + // Filter results to objects whose names are lexicographically equal to or + // after lexicographic_start. If lexicographic_end is also set, the objects + // listed have names between lexicographic_start (inclusive) and + // lexicographic_end (exclusive). + LexicographicStart string `protobuf:"bytes,10,opt,name=lexicographic_start,json=lexicographicStart,proto3" json:"lexicographic_start,omitempty"` + // Filter results to objects whose names are lexicographically before + // lexicographic_end. If lexicographic_start is also set, the objects listed + // have names between lexicographic_start (inclusive) and lexicographic_end + // (exclusive). + LexicographicEnd string `protobuf:"bytes,11,opt,name=lexicographic_end,json=lexicographicEnd,proto3" json:"lexicographic_end,omitempty"` +} + +func (x *ListObjectsRequest) Reset() { + *x = ListObjectsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListObjectsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListObjectsRequest) ProtoMessage() {} + +func (x *ListObjectsRequest) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[22] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListObjectsRequest.ProtoReflect.Descriptor instead. +func (*ListObjectsRequest) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{22} +} + +func (x *ListObjectsRequest) GetParent() string { + if x != nil { + return x.Parent + } + return "" +} + +func (x *ListObjectsRequest) GetPageSize() int32 { + if x != nil { + return x.PageSize + } + return 0 +} + +func (x *ListObjectsRequest) GetPageToken() string { + if x != nil { + return x.PageToken + } + return "" +} + +func (x *ListObjectsRequest) GetDelimiter() string { + if x != nil { + return x.Delimiter + } + return "" +} + +func (x *ListObjectsRequest) GetIncludeTrailingDelimiter() bool { + if x != nil { + return x.IncludeTrailingDelimiter + } + return false +} + +func (x *ListObjectsRequest) GetPrefix() string { + if x != nil { + return x.Prefix + } + return "" +} + +func (x *ListObjectsRequest) GetVersions() bool { + if x != nil { + return x.Versions + } + return false +} + +func (x *ListObjectsRequest) GetReadMask() *fieldmaskpb.FieldMask { + if x != nil { + return x.ReadMask + } + return nil +} + +func (x *ListObjectsRequest) GetLexicographicStart() string { + if x != nil { + return x.LexicographicStart + } + return "" +} + +func (x *ListObjectsRequest) GetLexicographicEnd() string { + if x != nil { + return x.LexicographicEnd + } + return "" +} + +// Request object for `QueryWriteStatus`. +type QueryWriteStatusRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Required. The name of the resume token for the object whose write status is being + // requested. + UploadId string `protobuf:"bytes,1,opt,name=upload_id,json=uploadId,proto3" json:"upload_id,omitempty"` + // A set of parameters common to Storage API requests concerning an object. + CommonObjectRequestParams *CommonObjectRequestParams `protobuf:"bytes,2,opt,name=common_object_request_params,json=commonObjectRequestParams,proto3" json:"common_object_request_params,omitempty"` +} + +func (x *QueryWriteStatusRequest) Reset() { + *x = QueryWriteStatusRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *QueryWriteStatusRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QueryWriteStatusRequest) ProtoMessage() {} + +func (x *QueryWriteStatusRequest) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[23] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use QueryWriteStatusRequest.ProtoReflect.Descriptor instead. +func (*QueryWriteStatusRequest) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{23} +} + +func (x *QueryWriteStatusRequest) GetUploadId() string { + if x != nil { + return x.UploadId + } + return "" +} + +func (x *QueryWriteStatusRequest) GetCommonObjectRequestParams() *CommonObjectRequestParams { + if x != nil { + return x.CommonObjectRequestParams + } + return nil +} + +// Response object for `QueryWriteStatus`. +type QueryWriteStatusResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The response will set one of the following. + // + // Types that are assignable to WriteStatus: + // + // *QueryWriteStatusResponse_PersistedSize + // *QueryWriteStatusResponse_Resource + WriteStatus isQueryWriteStatusResponse_WriteStatus `protobuf_oneof:"write_status"` +} + +func (x *QueryWriteStatusResponse) Reset() { + *x = QueryWriteStatusResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *QueryWriteStatusResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QueryWriteStatusResponse) ProtoMessage() {} + +func (x *QueryWriteStatusResponse) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[24] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use QueryWriteStatusResponse.ProtoReflect.Descriptor instead. +func (*QueryWriteStatusResponse) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{24} +} + +func (m *QueryWriteStatusResponse) GetWriteStatus() isQueryWriteStatusResponse_WriteStatus { + if m != nil { + return m.WriteStatus + } + return nil +} + +func (x *QueryWriteStatusResponse) GetPersistedSize() int64 { + if x, ok := x.GetWriteStatus().(*QueryWriteStatusResponse_PersistedSize); ok { + return x.PersistedSize + } + return 0 +} + +func (x *QueryWriteStatusResponse) GetResource() *Object { + if x, ok := x.GetWriteStatus().(*QueryWriteStatusResponse_Resource); ok { + return x.Resource + } + return nil +} + +type isQueryWriteStatusResponse_WriteStatus interface { + isQueryWriteStatusResponse_WriteStatus() +} + +type QueryWriteStatusResponse_PersistedSize struct { + // The total number of bytes that have been processed for the given object + // from all `WriteObject` calls. This is the correct value for the + // 'write_offset' field to use when resuming the `WriteObject` operation. + // Only set if the upload has not finalized. + PersistedSize int64 `protobuf:"varint,1,opt,name=persisted_size,json=persistedSize,proto3,oneof"` +} + +type QueryWriteStatusResponse_Resource struct { + // A resource containing the metadata for the uploaded object. Only set if + // the upload has finalized. + Resource *Object `protobuf:"bytes,2,opt,name=resource,proto3,oneof"` +} + +func (*QueryWriteStatusResponse_PersistedSize) isQueryWriteStatusResponse_WriteStatus() {} + +func (*QueryWriteStatusResponse_Resource) isQueryWriteStatusResponse_WriteStatus() {} + +// Request message for RewriteObject. +// If the source object is encrypted using a Customer-Supplied Encryption Key +// the key information must be provided in the copy_source_encryption_algorithm, +// copy_source_encryption_key_bytes, and copy_source_encryption_key_sha256_bytes +// fields. If the destination object should be encrypted the keying information +// should be provided in the encryption_algorithm, encryption_key_bytes, and +// encryption_key_sha256_bytes fields of the +// common_object_request_params.customer_encryption field. +type RewriteObjectRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Required. Immutable. The name of the destination object. + // See the + // [Naming Guidelines](https://cloud.google.com/storage/docs/naming-objects). + // Example: `test.txt` + // The `name` field by itself does not uniquely identify a Cloud Storage + // object. A Cloud Storage object is uniquely identified by the tuple of + // (bucket, object, generation). + DestinationName string `protobuf:"bytes,24,opt,name=destination_name,json=destinationName,proto3" json:"destination_name,omitempty"` + // Required. Immutable. The name of the bucket containing the destination object. + DestinationBucket string `protobuf:"bytes,25,opt,name=destination_bucket,json=destinationBucket,proto3" json:"destination_bucket,omitempty"` + // The name of the Cloud KMS key that will be used to encrypt the destination + // object. The Cloud KMS key must be located in same location as the object. + // If the parameter is not specified, the request uses the destination + // bucket's default encryption key, if any, or else the Google-managed + // encryption key. + DestinationKmsKey string `protobuf:"bytes,27,opt,name=destination_kms_key,json=destinationKmsKey,proto3" json:"destination_kms_key,omitempty"` + // Properties of the destination, post-rewrite object. + // The `name`, `bucket` and `kms_key` fields must not be populated (these + // values are specified in the `destination_name`, `destination_bucket`, and + // `destination_kms_key` fields). + // If `destination` is present it will be used to construct the destination + // object's metadata; otherwise the destination object's metadata will be + // copied from the source object. + Destination *Object `protobuf:"bytes,1,opt,name=destination,proto3" json:"destination,omitempty"` + // Required. Name of the bucket in which to find the source object. + SourceBucket string `protobuf:"bytes,2,opt,name=source_bucket,json=sourceBucket,proto3" json:"source_bucket,omitempty"` + // Required. Name of the source object. + SourceObject string `protobuf:"bytes,3,opt,name=source_object,json=sourceObject,proto3" json:"source_object,omitempty"` + // If present, selects a specific revision of the source object (as opposed to + // the latest version, the default). + SourceGeneration int64 `protobuf:"varint,4,opt,name=source_generation,json=sourceGeneration,proto3" json:"source_generation,omitempty"` + // Include this field (from the previous rewrite response) on each rewrite + // request after the first one, until the rewrite response 'done' flag is + // true. Calls that provide a rewriteToken can omit all other request fields, + // but if included those fields must match the values provided in the first + // rewrite request. + RewriteToken string `protobuf:"bytes,5,opt,name=rewrite_token,json=rewriteToken,proto3" json:"rewrite_token,omitempty"` + // Apply a predefined set of access controls to the destination object. + // Valid values are "authenticatedRead", "bucketOwnerFullControl", + // "bucketOwnerRead", "private", "projectPrivate", or "publicRead". + DestinationPredefinedAcl string `protobuf:"bytes,28,opt,name=destination_predefined_acl,json=destinationPredefinedAcl,proto3" json:"destination_predefined_acl,omitempty"` + // Makes the operation conditional on whether the object's current generation + // matches the given value. Setting to 0 makes the operation succeed only if + // there are no live versions of the object. + IfGenerationMatch *int64 `protobuf:"varint,7,opt,name=if_generation_match,json=ifGenerationMatch,proto3,oneof" json:"if_generation_match,omitempty"` + // Makes the operation conditional on whether the object's live generation + // does not match the given value. If no live object exists, the precondition + // fails. Setting to 0 makes the operation succeed only if there is a live + // version of the object. + IfGenerationNotMatch *int64 `protobuf:"varint,8,opt,name=if_generation_not_match,json=ifGenerationNotMatch,proto3,oneof" json:"if_generation_not_match,omitempty"` + // Makes the operation conditional on whether the destination object's current + // metageneration matches the given value. + IfMetagenerationMatch *int64 `protobuf:"varint,9,opt,name=if_metageneration_match,json=ifMetagenerationMatch,proto3,oneof" json:"if_metageneration_match,omitempty"` + // Makes the operation conditional on whether the destination object's current + // metageneration does not match the given value. + IfMetagenerationNotMatch *int64 `protobuf:"varint,10,opt,name=if_metageneration_not_match,json=ifMetagenerationNotMatch,proto3,oneof" json:"if_metageneration_not_match,omitempty"` + // Makes the operation conditional on whether the source object's live + // generation matches the given value. + IfSourceGenerationMatch *int64 `protobuf:"varint,11,opt,name=if_source_generation_match,json=ifSourceGenerationMatch,proto3,oneof" json:"if_source_generation_match,omitempty"` + // Makes the operation conditional on whether the source object's live + // generation does not match the given value. + IfSourceGenerationNotMatch *int64 `protobuf:"varint,12,opt,name=if_source_generation_not_match,json=ifSourceGenerationNotMatch,proto3,oneof" json:"if_source_generation_not_match,omitempty"` + // Makes the operation conditional on whether the source object's current + // metageneration matches the given value. + IfSourceMetagenerationMatch *int64 `protobuf:"varint,13,opt,name=if_source_metageneration_match,json=ifSourceMetagenerationMatch,proto3,oneof" json:"if_source_metageneration_match,omitempty"` + // Makes the operation conditional on whether the source object's current + // metageneration does not match the given value. + IfSourceMetagenerationNotMatch *int64 `protobuf:"varint,14,opt,name=if_source_metageneration_not_match,json=ifSourceMetagenerationNotMatch,proto3,oneof" json:"if_source_metageneration_not_match,omitempty"` + // The maximum number of bytes that will be rewritten per rewrite request. + // Most callers + // shouldn't need to specify this parameter - it is primarily in place to + // support testing. If specified the value must be an integral multiple of + // 1 MiB (1048576). Also, this only applies to requests where the source and + // destination span locations and/or storage classes. Finally, this value must + // not change across rewrite calls else you'll get an error that the + // `rewriteToken` is invalid. + MaxBytesRewrittenPerCall int64 `protobuf:"varint,15,opt,name=max_bytes_rewritten_per_call,json=maxBytesRewrittenPerCall,proto3" json:"max_bytes_rewritten_per_call,omitempty"` + // The algorithm used to encrypt the source object, if any. Used if the source + // object was encrypted with a Customer-Supplied Encryption Key. + CopySourceEncryptionAlgorithm string `protobuf:"bytes,16,opt,name=copy_source_encryption_algorithm,json=copySourceEncryptionAlgorithm,proto3" json:"copy_source_encryption_algorithm,omitempty"` + // The raw bytes (not base64-encoded) AES-256 encryption key used to encrypt + // the source object, if it was encrypted with a Customer-Supplied Encryption + // Key. + CopySourceEncryptionKeyBytes []byte `protobuf:"bytes,21,opt,name=copy_source_encryption_key_bytes,json=copySourceEncryptionKeyBytes,proto3" json:"copy_source_encryption_key_bytes,omitempty"` + // The raw bytes (not base64-encoded) SHA256 hash of the encryption key used + // to encrypt the source object, if it was encrypted with a Customer-Supplied + // Encryption Key. + CopySourceEncryptionKeySha256Bytes []byte `protobuf:"bytes,22,opt,name=copy_source_encryption_key_sha256_bytes,json=copySourceEncryptionKeySha256Bytes,proto3" json:"copy_source_encryption_key_sha256_bytes,omitempty"` + // A set of parameters common to Storage API requests concerning an object. + CommonObjectRequestParams *CommonObjectRequestParams `protobuf:"bytes,19,opt,name=common_object_request_params,json=commonObjectRequestParams,proto3" json:"common_object_request_params,omitempty"` +} + +func (x *RewriteObjectRequest) Reset() { + *x = RewriteObjectRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RewriteObjectRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RewriteObjectRequest) ProtoMessage() {} + +func (x *RewriteObjectRequest) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[25] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RewriteObjectRequest.ProtoReflect.Descriptor instead. +func (*RewriteObjectRequest) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{25} +} + +func (x *RewriteObjectRequest) GetDestinationName() string { + if x != nil { + return x.DestinationName + } + return "" +} + +func (x *RewriteObjectRequest) GetDestinationBucket() string { + if x != nil { + return x.DestinationBucket + } + return "" +} + +func (x *RewriteObjectRequest) GetDestinationKmsKey() string { + if x != nil { + return x.DestinationKmsKey + } + return "" +} + +func (x *RewriteObjectRequest) GetDestination() *Object { + if x != nil { + return x.Destination + } + return nil +} + +func (x *RewriteObjectRequest) GetSourceBucket() string { + if x != nil { + return x.SourceBucket + } + return "" +} + +func (x *RewriteObjectRequest) GetSourceObject() string { + if x != nil { + return x.SourceObject + } + return "" +} + +func (x *RewriteObjectRequest) GetSourceGeneration() int64 { + if x != nil { + return x.SourceGeneration + } + return 0 +} + +func (x *RewriteObjectRequest) GetRewriteToken() string { + if x != nil { + return x.RewriteToken + } + return "" +} + +func (x *RewriteObjectRequest) GetDestinationPredefinedAcl() string { + if x != nil { + return x.DestinationPredefinedAcl + } + return "" +} + +func (x *RewriteObjectRequest) GetIfGenerationMatch() int64 { + if x != nil && x.IfGenerationMatch != nil { + return *x.IfGenerationMatch + } + return 0 +} + +func (x *RewriteObjectRequest) GetIfGenerationNotMatch() int64 { + if x != nil && x.IfGenerationNotMatch != nil { + return *x.IfGenerationNotMatch + } + return 0 +} + +func (x *RewriteObjectRequest) GetIfMetagenerationMatch() int64 { + if x != nil && x.IfMetagenerationMatch != nil { + return *x.IfMetagenerationMatch + } + return 0 +} + +func (x *RewriteObjectRequest) GetIfMetagenerationNotMatch() int64 { + if x != nil && x.IfMetagenerationNotMatch != nil { + return *x.IfMetagenerationNotMatch + } + return 0 +} + +func (x *RewriteObjectRequest) GetIfSourceGenerationMatch() int64 { + if x != nil && x.IfSourceGenerationMatch != nil { + return *x.IfSourceGenerationMatch + } + return 0 +} + +func (x *RewriteObjectRequest) GetIfSourceGenerationNotMatch() int64 { + if x != nil && x.IfSourceGenerationNotMatch != nil { + return *x.IfSourceGenerationNotMatch + } + return 0 +} + +func (x *RewriteObjectRequest) GetIfSourceMetagenerationMatch() int64 { + if x != nil && x.IfSourceMetagenerationMatch != nil { + return *x.IfSourceMetagenerationMatch + } + return 0 +} + +func (x *RewriteObjectRequest) GetIfSourceMetagenerationNotMatch() int64 { + if x != nil && x.IfSourceMetagenerationNotMatch != nil { + return *x.IfSourceMetagenerationNotMatch + } + return 0 +} + +func (x *RewriteObjectRequest) GetMaxBytesRewrittenPerCall() int64 { + if x != nil { + return x.MaxBytesRewrittenPerCall + } + return 0 +} + +func (x *RewriteObjectRequest) GetCopySourceEncryptionAlgorithm() string { + if x != nil { + return x.CopySourceEncryptionAlgorithm + } + return "" +} + +func (x *RewriteObjectRequest) GetCopySourceEncryptionKeyBytes() []byte { + if x != nil { + return x.CopySourceEncryptionKeyBytes + } + return nil +} + +func (x *RewriteObjectRequest) GetCopySourceEncryptionKeySha256Bytes() []byte { + if x != nil { + return x.CopySourceEncryptionKeySha256Bytes + } + return nil +} + +func (x *RewriteObjectRequest) GetCommonObjectRequestParams() *CommonObjectRequestParams { + if x != nil { + return x.CommonObjectRequestParams + } + return nil +} + +// A rewrite response. +type RewriteResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The total bytes written so far, which can be used to provide a waiting user + // with a progress indicator. This property is always present in the response. + TotalBytesRewritten int64 `protobuf:"varint,1,opt,name=total_bytes_rewritten,json=totalBytesRewritten,proto3" json:"total_bytes_rewritten,omitempty"` + // The total size of the object being copied in bytes. This property is always + // present in the response. + ObjectSize int64 `protobuf:"varint,2,opt,name=object_size,json=objectSize,proto3" json:"object_size,omitempty"` + // `true` if the copy is finished; otherwise, `false` if + // the copy is in progress. This property is always present in the response. + Done bool `protobuf:"varint,3,opt,name=done,proto3" json:"done,omitempty"` + // A token to use in subsequent requests to continue copying data. This token + // is present in the response only when there is more data to copy. + RewriteToken string `protobuf:"bytes,4,opt,name=rewrite_token,json=rewriteToken,proto3" json:"rewrite_token,omitempty"` + // A resource containing the metadata for the copied-to object. This property + // is present in the response only when copying completes. + Resource *Object `protobuf:"bytes,5,opt,name=resource,proto3" json:"resource,omitempty"` +} + +func (x *RewriteResponse) Reset() { + *x = RewriteResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RewriteResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RewriteResponse) ProtoMessage() {} + +func (x *RewriteResponse) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[26] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RewriteResponse.ProtoReflect.Descriptor instead. +func (*RewriteResponse) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{26} +} + +func (x *RewriteResponse) GetTotalBytesRewritten() int64 { + if x != nil { + return x.TotalBytesRewritten + } + return 0 +} + +func (x *RewriteResponse) GetObjectSize() int64 { + if x != nil { + return x.ObjectSize + } + return 0 +} + +func (x *RewriteResponse) GetDone() bool { + if x != nil { + return x.Done + } + return false +} + +func (x *RewriteResponse) GetRewriteToken() string { + if x != nil { + return x.RewriteToken + } + return "" +} + +func (x *RewriteResponse) GetResource() *Object { + if x != nil { + return x.Resource + } + return nil +} + +// Request message StartResumableWrite. +type StartResumableWriteRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Required. The destination bucket, object, and metadata, as well as any preconditions. + WriteObjectSpec *WriteObjectSpec `protobuf:"bytes,1,opt,name=write_object_spec,json=writeObjectSpec,proto3" json:"write_object_spec,omitempty"` + // A set of parameters common to Storage API requests concerning an object. + CommonObjectRequestParams *CommonObjectRequestParams `protobuf:"bytes,3,opt,name=common_object_request_params,json=commonObjectRequestParams,proto3" json:"common_object_request_params,omitempty"` +} + +func (x *StartResumableWriteRequest) Reset() { + *x = StartResumableWriteRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StartResumableWriteRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StartResumableWriteRequest) ProtoMessage() {} + +func (x *StartResumableWriteRequest) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[27] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StartResumableWriteRequest.ProtoReflect.Descriptor instead. +func (*StartResumableWriteRequest) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{27} +} + +func (x *StartResumableWriteRequest) GetWriteObjectSpec() *WriteObjectSpec { + if x != nil { + return x.WriteObjectSpec + } + return nil +} + +func (x *StartResumableWriteRequest) GetCommonObjectRequestParams() *CommonObjectRequestParams { + if x != nil { + return x.CommonObjectRequestParams + } + return nil +} + +// Response object for `StartResumableWrite`. +type StartResumableWriteResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The upload_id of the newly started resumable write operation. This + // value should be copied into the `WriteObjectRequest.upload_id` field. + UploadId string `protobuf:"bytes,1,opt,name=upload_id,json=uploadId,proto3" json:"upload_id,omitempty"` +} + +func (x *StartResumableWriteResponse) Reset() { + *x = StartResumableWriteResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StartResumableWriteResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StartResumableWriteResponse) ProtoMessage() {} + +func (x *StartResumableWriteResponse) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[28] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StartResumableWriteResponse.ProtoReflect.Descriptor instead. +func (*StartResumableWriteResponse) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{28} +} + +func (x *StartResumableWriteResponse) GetUploadId() string { + if x != nil { + return x.UploadId + } + return "" +} + +// Request message for UpdateObject. +type UpdateObjectRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Required. The object to update. + // The object's bucket and name fields are used to identify the object to + // update. If present, the object's generation field selects a specific + // revision of this object whose metadata should be updated. Otherwise, + // assumes the live version of the object. + Object *Object `protobuf:"bytes,1,opt,name=object,proto3" json:"object,omitempty"` + // Makes the operation conditional on whether the object's current generation + // matches the given value. Setting to 0 makes the operation succeed only if + // there are no live versions of the object. + IfGenerationMatch *int64 `protobuf:"varint,2,opt,name=if_generation_match,json=ifGenerationMatch,proto3,oneof" json:"if_generation_match,omitempty"` + // Makes the operation conditional on whether the object's live generation + // does not match the given value. If no live object exists, the precondition + // fails. Setting to 0 makes the operation succeed only if there is a live + // version of the object. + IfGenerationNotMatch *int64 `protobuf:"varint,3,opt,name=if_generation_not_match,json=ifGenerationNotMatch,proto3,oneof" json:"if_generation_not_match,omitempty"` + // Makes the operation conditional on whether the object's current + // metageneration matches the given value. + IfMetagenerationMatch *int64 `protobuf:"varint,4,opt,name=if_metageneration_match,json=ifMetagenerationMatch,proto3,oneof" json:"if_metageneration_match,omitempty"` + // Makes the operation conditional on whether the object's current + // metageneration does not match the given value. + IfMetagenerationNotMatch *int64 `protobuf:"varint,5,opt,name=if_metageneration_not_match,json=ifMetagenerationNotMatch,proto3,oneof" json:"if_metageneration_not_match,omitempty"` + // Apply a predefined set of access controls to this object. + // Valid values are "authenticatedRead", "bucketOwnerFullControl", + // "bucketOwnerRead", "private", "projectPrivate", or "publicRead". + PredefinedAcl string `protobuf:"bytes,10,opt,name=predefined_acl,json=predefinedAcl,proto3" json:"predefined_acl,omitempty"` + // Required. List of fields to be updated. + // + // To specify ALL fields, equivalent to the JSON API's "update" function, + // specify a single field with the value `*`. Note: not recommended. If a new + // field is introduced at a later time, an older client updating with the `*` + // may accidentally reset the new field's value. + // + // Not specifying any fields is an error. + // Not specifying a field while setting that field to a non-default value is + // an error. + UpdateMask *fieldmaskpb.FieldMask `protobuf:"bytes,7,opt,name=update_mask,json=updateMask,proto3" json:"update_mask,omitempty"` + // A set of parameters common to Storage API requests concerning an object. + CommonObjectRequestParams *CommonObjectRequestParams `protobuf:"bytes,8,opt,name=common_object_request_params,json=commonObjectRequestParams,proto3" json:"common_object_request_params,omitempty"` +} + +func (x *UpdateObjectRequest) Reset() { + *x = UpdateObjectRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateObjectRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateObjectRequest) ProtoMessage() {} + +func (x *UpdateObjectRequest) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[29] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateObjectRequest.ProtoReflect.Descriptor instead. +func (*UpdateObjectRequest) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{29} +} + +func (x *UpdateObjectRequest) GetObject() *Object { + if x != nil { + return x.Object + } + return nil +} + +func (x *UpdateObjectRequest) GetIfGenerationMatch() int64 { + if x != nil && x.IfGenerationMatch != nil { + return *x.IfGenerationMatch + } + return 0 +} + +func (x *UpdateObjectRequest) GetIfGenerationNotMatch() int64 { + if x != nil && x.IfGenerationNotMatch != nil { + return *x.IfGenerationNotMatch + } + return 0 +} + +func (x *UpdateObjectRequest) GetIfMetagenerationMatch() int64 { + if x != nil && x.IfMetagenerationMatch != nil { + return *x.IfMetagenerationMatch + } + return 0 +} + +func (x *UpdateObjectRequest) GetIfMetagenerationNotMatch() int64 { + if x != nil && x.IfMetagenerationNotMatch != nil { + return *x.IfMetagenerationNotMatch + } + return 0 +} + +func (x *UpdateObjectRequest) GetPredefinedAcl() string { + if x != nil { + return x.PredefinedAcl + } + return "" +} + +func (x *UpdateObjectRequest) GetUpdateMask() *fieldmaskpb.FieldMask { + if x != nil { + return x.UpdateMask + } + return nil +} + +func (x *UpdateObjectRequest) GetCommonObjectRequestParams() *CommonObjectRequestParams { + if x != nil { + return x.CommonObjectRequestParams + } + return nil +} + +// Request message for GetServiceAccount. +type GetServiceAccountRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Required. Project ID, in the format of "projects/". + // can be the project ID or project number. + Project string `protobuf:"bytes,1,opt,name=project,proto3" json:"project,omitempty"` +} + +func (x *GetServiceAccountRequest) Reset() { + *x = GetServiceAccountRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetServiceAccountRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetServiceAccountRequest) ProtoMessage() {} + +func (x *GetServiceAccountRequest) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[30] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetServiceAccountRequest.ProtoReflect.Descriptor instead. +func (*GetServiceAccountRequest) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{30} +} + +func (x *GetServiceAccountRequest) GetProject() string { + if x != nil { + return x.Project + } + return "" +} + +// Request message for CreateHmacKey. +type CreateHmacKeyRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Required. The project that the HMAC-owning service account lives in, in the format of + // "projects/". + // can be the project ID or project number. + Project string `protobuf:"bytes,1,opt,name=project,proto3" json:"project,omitempty"` + // Required. The service account to create the HMAC for. + ServiceAccountEmail string `protobuf:"bytes,2,opt,name=service_account_email,json=serviceAccountEmail,proto3" json:"service_account_email,omitempty"` +} + +func (x *CreateHmacKeyRequest) Reset() { + *x = CreateHmacKeyRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[31] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateHmacKeyRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateHmacKeyRequest) ProtoMessage() {} + +func (x *CreateHmacKeyRequest) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[31] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateHmacKeyRequest.ProtoReflect.Descriptor instead. +func (*CreateHmacKeyRequest) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{31} +} + +func (x *CreateHmacKeyRequest) GetProject() string { + if x != nil { + return x.Project + } + return "" +} + +func (x *CreateHmacKeyRequest) GetServiceAccountEmail() string { + if x != nil { + return x.ServiceAccountEmail + } + return "" +} + +// Create hmac response. The only time the secret for an HMAC will be returned. +type CreateHmacKeyResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Key metadata. + Metadata *HmacKeyMetadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` + // HMAC key secret material. + // In raw bytes format (not base64-encoded). + SecretKeyBytes []byte `protobuf:"bytes,3,opt,name=secret_key_bytes,json=secretKeyBytes,proto3" json:"secret_key_bytes,omitempty"` +} + +func (x *CreateHmacKeyResponse) Reset() { + *x = CreateHmacKeyResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[32] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateHmacKeyResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateHmacKeyResponse) ProtoMessage() {} + +func (x *CreateHmacKeyResponse) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[32] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateHmacKeyResponse.ProtoReflect.Descriptor instead. +func (*CreateHmacKeyResponse) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{32} +} + +func (x *CreateHmacKeyResponse) GetMetadata() *HmacKeyMetadata { + if x != nil { + return x.Metadata + } + return nil +} + +func (x *CreateHmacKeyResponse) GetSecretKeyBytes() []byte { + if x != nil { + return x.SecretKeyBytes + } + return nil +} + +// Request object to delete a given HMAC key. +type DeleteHmacKeyRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Required. The identifying key for the HMAC to delete. + AccessId string `protobuf:"bytes,1,opt,name=access_id,json=accessId,proto3" json:"access_id,omitempty"` + // Required. The project that owns the HMAC key, in the format of + // "projects/". + // can be the project ID or project number. + Project string `protobuf:"bytes,2,opt,name=project,proto3" json:"project,omitempty"` +} + +func (x *DeleteHmacKeyRequest) Reset() { + *x = DeleteHmacKeyRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[33] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteHmacKeyRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteHmacKeyRequest) ProtoMessage() {} + +func (x *DeleteHmacKeyRequest) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[33] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteHmacKeyRequest.ProtoReflect.Descriptor instead. +func (*DeleteHmacKeyRequest) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{33} +} + +func (x *DeleteHmacKeyRequest) GetAccessId() string { + if x != nil { + return x.AccessId + } + return "" +} + +func (x *DeleteHmacKeyRequest) GetProject() string { + if x != nil { + return x.Project + } + return "" +} + +// Request object to get metadata on a given HMAC key. +type GetHmacKeyRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Required. The identifying key for the HMAC to delete. + AccessId string `protobuf:"bytes,1,opt,name=access_id,json=accessId,proto3" json:"access_id,omitempty"` + // Required. The project the HMAC key lies in, in the format of + // "projects/". + // can be the project ID or project number. + Project string `protobuf:"bytes,2,opt,name=project,proto3" json:"project,omitempty"` +} + +func (x *GetHmacKeyRequest) Reset() { + *x = GetHmacKeyRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[34] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetHmacKeyRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetHmacKeyRequest) ProtoMessage() {} + +func (x *GetHmacKeyRequest) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[34] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetHmacKeyRequest.ProtoReflect.Descriptor instead. +func (*GetHmacKeyRequest) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{34} +} + +func (x *GetHmacKeyRequest) GetAccessId() string { + if x != nil { + return x.AccessId + } + return "" +} + +func (x *GetHmacKeyRequest) GetProject() string { + if x != nil { + return x.Project + } + return "" +} + +// Request to fetch a list of HMAC keys under a given project. +type ListHmacKeysRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Required. The project to list HMAC keys for, in the format of + // "projects/". + // can be the project ID or project number. + Project string `protobuf:"bytes,1,opt,name=project,proto3" json:"project,omitempty"` + // The maximum number of keys to return. + PageSize int32 `protobuf:"varint,2,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` + // A previously returned token from ListHmacKeysResponse to get the next page. + PageToken string `protobuf:"bytes,3,opt,name=page_token,json=pageToken,proto3" json:"page_token,omitempty"` + // If set, filters to only return HMAC keys for specified service account. + ServiceAccountEmail string `protobuf:"bytes,4,opt,name=service_account_email,json=serviceAccountEmail,proto3" json:"service_account_email,omitempty"` + // If set, return deleted keys that have not yet been wiped out. + ShowDeletedKeys bool `protobuf:"varint,5,opt,name=show_deleted_keys,json=showDeletedKeys,proto3" json:"show_deleted_keys,omitempty"` +} + +func (x *ListHmacKeysRequest) Reset() { + *x = ListHmacKeysRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[35] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListHmacKeysRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListHmacKeysRequest) ProtoMessage() {} + +func (x *ListHmacKeysRequest) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[35] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListHmacKeysRequest.ProtoReflect.Descriptor instead. +func (*ListHmacKeysRequest) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{35} +} + +func (x *ListHmacKeysRequest) GetProject() string { + if x != nil { + return x.Project + } + return "" +} + +func (x *ListHmacKeysRequest) GetPageSize() int32 { + if x != nil { + return x.PageSize + } + return 0 +} + +func (x *ListHmacKeysRequest) GetPageToken() string { + if x != nil { + return x.PageToken + } + return "" +} + +func (x *ListHmacKeysRequest) GetServiceAccountEmail() string { + if x != nil { + return x.ServiceAccountEmail + } + return "" +} + +func (x *ListHmacKeysRequest) GetShowDeletedKeys() bool { + if x != nil { + return x.ShowDeletedKeys + } + return false +} + +// Hmac key list response with next page information. +type ListHmacKeysResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The list of items. + HmacKeys []*HmacKeyMetadata `protobuf:"bytes,1,rep,name=hmac_keys,json=hmacKeys,proto3" json:"hmac_keys,omitempty"` + // The continuation token, used to page through large result sets. Provide + // this value in a subsequent request to return the next page of results. + NextPageToken string `protobuf:"bytes,2,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"` +} + +func (x *ListHmacKeysResponse) Reset() { + *x = ListHmacKeysResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[36] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListHmacKeysResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListHmacKeysResponse) ProtoMessage() {} + +func (x *ListHmacKeysResponse) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[36] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListHmacKeysResponse.ProtoReflect.Descriptor instead. +func (*ListHmacKeysResponse) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{36} +} + +func (x *ListHmacKeysResponse) GetHmacKeys() []*HmacKeyMetadata { + if x != nil { + return x.HmacKeys + } + return nil +} + +func (x *ListHmacKeysResponse) GetNextPageToken() string { + if x != nil { + return x.NextPageToken + } + return "" +} + +// Request object to update an HMAC key state. +// HmacKeyMetadata.state is required and the only writable field in +// UpdateHmacKey operation. Specifying fields other than state will result in an +// error. +type UpdateHmacKeyRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Required. The HMAC key to update. + // If present, the hmac_key's `id` field will be used to identify the key. + // Otherwise, the hmac_key's access_id and project fields will be used to + // identify the key. + HmacKey *HmacKeyMetadata `protobuf:"bytes,1,opt,name=hmac_key,json=hmacKey,proto3" json:"hmac_key,omitempty"` + // Update mask for hmac_key. + // Not specifying any fields will mean only the `state` field is updated to + // the value specified in `hmac_key`. + UpdateMask *fieldmaskpb.FieldMask `protobuf:"bytes,3,opt,name=update_mask,json=updateMask,proto3" json:"update_mask,omitempty"` +} + +func (x *UpdateHmacKeyRequest) Reset() { + *x = UpdateHmacKeyRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[37] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateHmacKeyRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateHmacKeyRequest) ProtoMessage() {} + +func (x *UpdateHmacKeyRequest) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[37] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateHmacKeyRequest.ProtoReflect.Descriptor instead. +func (*UpdateHmacKeyRequest) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{37} +} + +func (x *UpdateHmacKeyRequest) GetHmacKey() *HmacKeyMetadata { + if x != nil { + return x.HmacKey + } + return nil +} + +func (x *UpdateHmacKeyRequest) GetUpdateMask() *fieldmaskpb.FieldMask { + if x != nil { + return x.UpdateMask + } + return nil +} + +// Parameters that can be passed to any object request. +type CommonObjectRequestParams struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Encryption algorithm used with the Customer-Supplied Encryption Keys + // feature. + EncryptionAlgorithm string `protobuf:"bytes,1,opt,name=encryption_algorithm,json=encryptionAlgorithm,proto3" json:"encryption_algorithm,omitempty"` + // Encryption key used with the Customer-Supplied Encryption Keys feature. + // In raw bytes format (not base64-encoded). + EncryptionKeyBytes []byte `protobuf:"bytes,4,opt,name=encryption_key_bytes,json=encryptionKeyBytes,proto3" json:"encryption_key_bytes,omitempty"` + // SHA256 hash of encryption key used with the Customer-Supplied Encryption + // Keys feature. + EncryptionKeySha256Bytes []byte `protobuf:"bytes,5,opt,name=encryption_key_sha256_bytes,json=encryptionKeySha256Bytes,proto3" json:"encryption_key_sha256_bytes,omitempty"` +} + +func (x *CommonObjectRequestParams) Reset() { + *x = CommonObjectRequestParams{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[38] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommonObjectRequestParams) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommonObjectRequestParams) ProtoMessage() {} + +func (x *CommonObjectRequestParams) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[38] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommonObjectRequestParams.ProtoReflect.Descriptor instead. +func (*CommonObjectRequestParams) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{38} +} + +func (x *CommonObjectRequestParams) GetEncryptionAlgorithm() string { + if x != nil { + return x.EncryptionAlgorithm + } + return "" +} + +func (x *CommonObjectRequestParams) GetEncryptionKeyBytes() []byte { + if x != nil { + return x.EncryptionKeyBytes + } + return nil +} + +func (x *CommonObjectRequestParams) GetEncryptionKeySha256Bytes() []byte { + if x != nil { + return x.EncryptionKeySha256Bytes + } + return nil +} + +// Shared constants. +type ServiceConstants struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ServiceConstants) Reset() { + *x = ServiceConstants{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[39] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ServiceConstants) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServiceConstants) ProtoMessage() {} + +func (x *ServiceConstants) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[39] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServiceConstants.ProtoReflect.Descriptor instead. +func (*ServiceConstants) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{39} +} + +// A bucket. +type Bucket struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Immutable. The name of the bucket. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // Output only. The user-chosen part of the bucket name. The `{bucket}` portion of the + // `name` field. For globally unique buckets, this is equal to the "bucket + // name" of other Cloud Storage APIs. Example: "pub". + BucketId string `protobuf:"bytes,2,opt,name=bucket_id,json=bucketId,proto3" json:"bucket_id,omitempty"` + // The etag of the bucket. + // If included in the metadata of an UpdateBucketRequest, the operation will + // only be performed if the etag matches that of the bucket. + Etag string `protobuf:"bytes,29,opt,name=etag,proto3" json:"etag,omitempty"` + // Immutable. The project which owns this bucket, in the format of + // "projects/". + // can be the project ID or project number. + Project string `protobuf:"bytes,3,opt,name=project,proto3" json:"project,omitempty"` + // Output only. The metadata generation of this bucket. + // Attempting to set or update this field will result in a + // [FieldViolation][google.rpc.BadRequest.FieldViolation]. + Metageneration int64 `protobuf:"varint,4,opt,name=metageneration,proto3" json:"metageneration,omitempty"` + // Immutable. The location of the bucket. Object data for objects in the bucket resides + // in physical storage within this region. Defaults to `US`. See the + // [https://developers.google.com/storage/docs/concepts-techniques#specifyinglocations"][developer's + // guide] for the authoritative list. Attempting to update this field after + // the bucket is created will result in an error. + Location string `protobuf:"bytes,5,opt,name=location,proto3" json:"location,omitempty"` + // Output only. The location type of the bucket (region, dual-region, multi-region, etc). + LocationType string `protobuf:"bytes,6,opt,name=location_type,json=locationType,proto3" json:"location_type,omitempty"` + // The bucket's default storage class, used whenever no storageClass is + // specified for a newly-created object. This defines how objects in the + // bucket are stored and determines the SLA and the cost of storage. + // If this value is not specified when the bucket is created, it will default + // to `STANDARD`. For more information, see + // https://developers.google.com/storage/docs/storage-classes. + StorageClass string `protobuf:"bytes,7,opt,name=storage_class,json=storageClass,proto3" json:"storage_class,omitempty"` + // The recovery point objective for cross-region replication of the bucket. + // Applicable only for dual- and multi-region buckets. "DEFAULT" uses default + // replication. "ASYNC_TURBO" enables turbo replication, valid for dual-region + // buckets only. If rpo is not specified when the bucket is created, it + // defaults to "DEFAULT". For more information, see + // https://cloud.google.com/storage/docs/turbo-replication. + Rpo string `protobuf:"bytes,27,opt,name=rpo,proto3" json:"rpo,omitempty"` + // Access controls on the bucket. + // If iamConfig.uniformBucketLevelAccess is enabled on this bucket, + // requests to set, read, or modify acl is an error. + Acl []*BucketAccessControl `protobuf:"bytes,8,rep,name=acl,proto3" json:"acl,omitempty"` + // Default access controls to apply to new objects when no ACL is provided. + // If iamConfig.uniformBucketLevelAccess is enabled on this bucket, + // requests to set, read, or modify acl is an error. + DefaultObjectAcl []*ObjectAccessControl `protobuf:"bytes,9,rep,name=default_object_acl,json=defaultObjectAcl,proto3" json:"default_object_acl,omitempty"` + // The bucket's lifecycle config. See + // [https://developers.google.com/storage/docs/lifecycle]Lifecycle Management] + // for more information. + Lifecycle *Bucket_Lifecycle `protobuf:"bytes,10,opt,name=lifecycle,proto3" json:"lifecycle,omitempty"` + // Output only. The creation time of the bucket. + // Attempting to set or update this field will result in a + // [FieldViolation][google.rpc.BadRequest.FieldViolation]. + CreateTime *timestamppb.Timestamp `protobuf:"bytes,11,opt,name=create_time,json=createTime,proto3" json:"create_time,omitempty"` + // The bucket's [https://www.w3.org/TR/cors/][Cross-Origin Resource Sharing] + // (CORS) config. + Cors []*Bucket_Cors `protobuf:"bytes,12,rep,name=cors,proto3" json:"cors,omitempty"` + // Output only. The modification time of the bucket. + // Attempting to set or update this field will result in a + // [FieldViolation][google.rpc.BadRequest.FieldViolation]. + UpdateTime *timestamppb.Timestamp `protobuf:"bytes,13,opt,name=update_time,json=updateTime,proto3" json:"update_time,omitempty"` + // The default value for event-based hold on newly created objects in this + // bucket. Event-based hold is a way to retain objects indefinitely until an + // event occurs, signified by the + // hold's release. After being released, such objects will be subject to + // bucket-level retention (if any). One sample use case of this flag is for + // banks to hold loan documents for at least 3 years after loan is paid in + // full. Here, bucket-level retention is 3 years and the event is loan being + // paid in full. In this example, these objects will be held intact for any + // number of years until the event has occurred (event-based hold on the + // object is released) and then 3 more years after that. That means retention + // duration of the objects begins from the moment event-based hold + // transitioned from true to false. Objects under event-based hold cannot be + // deleted, overwritten or archived until the hold is removed. + DefaultEventBasedHold bool `protobuf:"varint,14,opt,name=default_event_based_hold,json=defaultEventBasedHold,proto3" json:"default_event_based_hold,omitempty"` + // User-provided labels, in key/value pairs. + Labels map[string]string `protobuf:"bytes,15,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // The bucket's website config, controlling how the service behaves + // when accessing bucket contents as a web site. See the + // [https://cloud.google.com/storage/docs/static-website][Static Website + // Examples] for more information. + Website *Bucket_Website `protobuf:"bytes,16,opt,name=website,proto3" json:"website,omitempty"` + // The bucket's versioning config. + Versioning *Bucket_Versioning `protobuf:"bytes,17,opt,name=versioning,proto3" json:"versioning,omitempty"` + // The bucket's logging config, which defines the destination bucket + // and name prefix (if any) for the current bucket's logs. + Logging *Bucket_Logging `protobuf:"bytes,18,opt,name=logging,proto3" json:"logging,omitempty"` + // Output only. The owner of the bucket. This is always the project team's owner group. + Owner *Owner `protobuf:"bytes,19,opt,name=owner,proto3" json:"owner,omitempty"` + // Encryption config for a bucket. + Encryption *Bucket_Encryption `protobuf:"bytes,20,opt,name=encryption,proto3" json:"encryption,omitempty"` + // The bucket's billing config. + Billing *Bucket_Billing `protobuf:"bytes,21,opt,name=billing,proto3" json:"billing,omitempty"` + // The bucket's retention policy. The retention policy enforces a minimum + // retention time for all objects contained in the bucket, based on their + // creation time. Any attempt to overwrite or delete objects younger than the + // retention period will result in a PERMISSION_DENIED error. An unlocked + // retention policy can be modified or removed from the bucket via a + // storage.buckets.update operation. A locked retention policy cannot be + // removed or shortened in duration for the lifetime of the bucket. + // Attempting to remove or decrease period of a locked retention policy will + // result in a PERMISSION_DENIED error. + RetentionPolicy *Bucket_RetentionPolicy `protobuf:"bytes,22,opt,name=retention_policy,json=retentionPolicy,proto3" json:"retention_policy,omitempty"` + // The bucket's IAM config. + IamConfig *Bucket_IamConfig `protobuf:"bytes,23,opt,name=iam_config,json=iamConfig,proto3" json:"iam_config,omitempty"` + // Reserved for future use. + SatisfiesPzs bool `protobuf:"varint,25,opt,name=satisfies_pzs,json=satisfiesPzs,proto3" json:"satisfies_pzs,omitempty"` + // Configuration that, if present, specifies the data placement for a + // [https://cloud.google.com/storage/docs/use-dual-regions][Dual Region]. + CustomPlacementConfig *Bucket_CustomPlacementConfig `protobuf:"bytes,26,opt,name=custom_placement_config,json=customPlacementConfig,proto3" json:"custom_placement_config,omitempty"` + // The bucket's Autoclass configuration. If there is no configuration, the + // Autoclass feature will be disabled and have no effect on the bucket. + Autoclass *Bucket_Autoclass `protobuf:"bytes,28,opt,name=autoclass,proto3" json:"autoclass,omitempty"` +} + +func (x *Bucket) Reset() { + *x = Bucket{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[40] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Bucket) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Bucket) ProtoMessage() {} + +func (x *Bucket) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[40] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Bucket.ProtoReflect.Descriptor instead. +func (*Bucket) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{40} +} + +func (x *Bucket) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Bucket) GetBucketId() string { + if x != nil { + return x.BucketId + } + return "" +} + +func (x *Bucket) GetEtag() string { + if x != nil { + return x.Etag + } + return "" +} + +func (x *Bucket) GetProject() string { + if x != nil { + return x.Project + } + return "" +} + +func (x *Bucket) GetMetageneration() int64 { + if x != nil { + return x.Metageneration + } + return 0 +} + +func (x *Bucket) GetLocation() string { + if x != nil { + return x.Location + } + return "" +} + +func (x *Bucket) GetLocationType() string { + if x != nil { + return x.LocationType + } + return "" +} + +func (x *Bucket) GetStorageClass() string { + if x != nil { + return x.StorageClass + } + return "" +} + +func (x *Bucket) GetRpo() string { + if x != nil { + return x.Rpo + } + return "" +} + +func (x *Bucket) GetAcl() []*BucketAccessControl { + if x != nil { + return x.Acl + } + return nil +} + +func (x *Bucket) GetDefaultObjectAcl() []*ObjectAccessControl { + if x != nil { + return x.DefaultObjectAcl + } + return nil +} + +func (x *Bucket) GetLifecycle() *Bucket_Lifecycle { + if x != nil { + return x.Lifecycle + } + return nil +} + +func (x *Bucket) GetCreateTime() *timestamppb.Timestamp { + if x != nil { + return x.CreateTime + } + return nil +} + +func (x *Bucket) GetCors() []*Bucket_Cors { + if x != nil { + return x.Cors + } + return nil +} + +func (x *Bucket) GetUpdateTime() *timestamppb.Timestamp { + if x != nil { + return x.UpdateTime + } + return nil +} + +func (x *Bucket) GetDefaultEventBasedHold() bool { + if x != nil { + return x.DefaultEventBasedHold + } + return false +} + +func (x *Bucket) GetLabels() map[string]string { + if x != nil { + return x.Labels + } + return nil +} + +func (x *Bucket) GetWebsite() *Bucket_Website { + if x != nil { + return x.Website + } + return nil +} + +func (x *Bucket) GetVersioning() *Bucket_Versioning { + if x != nil { + return x.Versioning + } + return nil +} + +func (x *Bucket) GetLogging() *Bucket_Logging { + if x != nil { + return x.Logging + } + return nil +} + +func (x *Bucket) GetOwner() *Owner { + if x != nil { + return x.Owner + } + return nil +} + +func (x *Bucket) GetEncryption() *Bucket_Encryption { + if x != nil { + return x.Encryption + } + return nil +} + +func (x *Bucket) GetBilling() *Bucket_Billing { + if x != nil { + return x.Billing + } + return nil +} + +func (x *Bucket) GetRetentionPolicy() *Bucket_RetentionPolicy { + if x != nil { + return x.RetentionPolicy + } + return nil +} + +func (x *Bucket) GetIamConfig() *Bucket_IamConfig { + if x != nil { + return x.IamConfig + } + return nil +} + +func (x *Bucket) GetSatisfiesPzs() bool { + if x != nil { + return x.SatisfiesPzs + } + return false +} + +func (x *Bucket) GetCustomPlacementConfig() *Bucket_CustomPlacementConfig { + if x != nil { + return x.CustomPlacementConfig + } + return nil +} + +func (x *Bucket) GetAutoclass() *Bucket_Autoclass { + if x != nil { + return x.Autoclass + } + return nil +} + +// An access-control entry. +type BucketAccessControl struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The access permission for the entity. + Role string `protobuf:"bytes,1,opt,name=role,proto3" json:"role,omitempty"` + // The ID of the access-control entry. + Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` + // The entity holding the permission, in one of the following forms: + // * `user-{userid}` + // * `user-{email}` + // * `group-{groupid}` + // * `group-{email}` + // * `domain-{domain}` + // * `project-{team}-{projectnumber}` + // * `project-{team}-{projectid}` + // * `allUsers` + // * `allAuthenticatedUsers` + // Examples: + // * The user `liz@example.com` would be `user-liz@example.com`. + // * The group `example@googlegroups.com` would be + // `group-example@googlegroups.com` + // * All members of the Google Apps for Business domain `example.com` would be + // `domain-example.com` + // For project entities, `project-{team}-{projectnumber}` format will be + // returned on response. + Entity string `protobuf:"bytes,3,opt,name=entity,proto3" json:"entity,omitempty"` + // Output only. The alternative entity format, if exists. For project entities, + // `project-{team}-{projectid}` format will be returned on response. + EntityAlt string `protobuf:"bytes,9,opt,name=entity_alt,json=entityAlt,proto3" json:"entity_alt,omitempty"` + // The ID for the entity, if any. + EntityId string `protobuf:"bytes,4,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"` + // The etag of the BucketAccessControl. + // If included in the metadata of an update or delete request message, the + // operation operation will only be performed if the etag matches that of the + // bucket's BucketAccessControl. + Etag string `protobuf:"bytes,8,opt,name=etag,proto3" json:"etag,omitempty"` + // The email address associated with the entity, if any. + Email string `protobuf:"bytes,5,opt,name=email,proto3" json:"email,omitempty"` + // The domain associated with the entity, if any. + Domain string `protobuf:"bytes,6,opt,name=domain,proto3" json:"domain,omitempty"` + // The project team associated with the entity, if any. + ProjectTeam *ProjectTeam `protobuf:"bytes,7,opt,name=project_team,json=projectTeam,proto3" json:"project_team,omitempty"` +} + +func (x *BucketAccessControl) Reset() { + *x = BucketAccessControl{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[41] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BucketAccessControl) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BucketAccessControl) ProtoMessage() {} + +func (x *BucketAccessControl) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[41] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BucketAccessControl.ProtoReflect.Descriptor instead. +func (*BucketAccessControl) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{41} +} + +func (x *BucketAccessControl) GetRole() string { + if x != nil { + return x.Role + } + return "" +} + +func (x *BucketAccessControl) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *BucketAccessControl) GetEntity() string { + if x != nil { + return x.Entity + } + return "" +} + +func (x *BucketAccessControl) GetEntityAlt() string { + if x != nil { + return x.EntityAlt + } + return "" +} + +func (x *BucketAccessControl) GetEntityId() string { + if x != nil { + return x.EntityId + } + return "" +} + +func (x *BucketAccessControl) GetEtag() string { + if x != nil { + return x.Etag + } + return "" +} + +func (x *BucketAccessControl) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +func (x *BucketAccessControl) GetDomain() string { + if x != nil { + return x.Domain + } + return "" +} + +func (x *BucketAccessControl) GetProjectTeam() *ProjectTeam { + if x != nil { + return x.ProjectTeam + } + return nil +} + +// Message used to convey content being read or written, along with an optional +// checksum. +type ChecksummedData struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The data. + Content []byte `protobuf:"bytes,1,opt,name=content,proto3" json:"content,omitempty"` + // If set, the CRC32C digest of the content field. + Crc32C *uint32 `protobuf:"fixed32,2,opt,name=crc32c,proto3,oneof" json:"crc32c,omitempty"` +} + +func (x *ChecksummedData) Reset() { + *x = ChecksummedData{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[42] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ChecksummedData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ChecksummedData) ProtoMessage() {} + +func (x *ChecksummedData) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[42] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ChecksummedData.ProtoReflect.Descriptor instead. +func (*ChecksummedData) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{42} +} + +func (x *ChecksummedData) GetContent() []byte { + if x != nil { + return x.Content + } + return nil +} + +func (x *ChecksummedData) GetCrc32C() uint32 { + if x != nil && x.Crc32C != nil { + return *x.Crc32C + } + return 0 +} + +// Message used for storing full (not subrange) object checksums. +type ObjectChecksums struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // CRC32C digest of the object data. Computed by the Cloud Storage service for + // all written objects. + // If set in an WriteObjectRequest, service will validate that the stored + // object matches this checksum. + Crc32C *uint32 `protobuf:"fixed32,1,opt,name=crc32c,proto3,oneof" json:"crc32c,omitempty"` + // 128 bit MD5 hash of the object data. + // For more information about using the MD5 hash, see + // [https://cloud.google.com/storage/docs/hashes-etags#json-api][Hashes and + // ETags: Best Practices]. + // Not all objects will provide an MD5 hash. For example, composite objects + // provide only crc32c hashes. + // This value is equivalent to running `cat object.txt | openssl md5 -binary` + Md5Hash []byte `protobuf:"bytes,2,opt,name=md5_hash,json=md5Hash,proto3" json:"md5_hash,omitempty"` +} + +func (x *ObjectChecksums) Reset() { + *x = ObjectChecksums{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[43] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ObjectChecksums) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ObjectChecksums) ProtoMessage() {} + +func (x *ObjectChecksums) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[43] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ObjectChecksums.ProtoReflect.Descriptor instead. +func (*ObjectChecksums) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{43} +} + +func (x *ObjectChecksums) GetCrc32C() uint32 { + if x != nil && x.Crc32C != nil { + return *x.Crc32C + } + return 0 +} + +func (x *ObjectChecksums) GetMd5Hash() []byte { + if x != nil { + return x.Md5Hash + } + return nil +} + +// Hmac Key Metadata, which includes all information other than the secret. +type HmacKeyMetadata struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Immutable. Resource name ID of the key in the format + // /. + // can be the project ID or project number. + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + // Immutable. Globally unique id for keys. + AccessId string `protobuf:"bytes,2,opt,name=access_id,json=accessId,proto3" json:"access_id,omitempty"` + // Immutable. Identifies the project that owns the service account of the specified HMAC + // key, in the format "projects/". can + // be the project ID or project number. + Project string `protobuf:"bytes,3,opt,name=project,proto3" json:"project,omitempty"` + // Output only. Email of the service account the key authenticates as. + ServiceAccountEmail string `protobuf:"bytes,4,opt,name=service_account_email,json=serviceAccountEmail,proto3" json:"service_account_email,omitempty"` + // State of the key. One of ACTIVE, INACTIVE, or DELETED. + // Writable, can be updated by UpdateHmacKey operation. + State string `protobuf:"bytes,5,opt,name=state,proto3" json:"state,omitempty"` + // Output only. The creation time of the HMAC key. + CreateTime *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=create_time,json=createTime,proto3" json:"create_time,omitempty"` + // Output only. The last modification time of the HMAC key metadata. + UpdateTime *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=update_time,json=updateTime,proto3" json:"update_time,omitempty"` + // The etag of the HMAC key. + Etag string `protobuf:"bytes,8,opt,name=etag,proto3" json:"etag,omitempty"` +} + +func (x *HmacKeyMetadata) Reset() { + *x = HmacKeyMetadata{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[44] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *HmacKeyMetadata) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HmacKeyMetadata) ProtoMessage() {} + +func (x *HmacKeyMetadata) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[44] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HmacKeyMetadata.ProtoReflect.Descriptor instead. +func (*HmacKeyMetadata) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{44} +} + +func (x *HmacKeyMetadata) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *HmacKeyMetadata) GetAccessId() string { + if x != nil { + return x.AccessId + } + return "" +} + +func (x *HmacKeyMetadata) GetProject() string { + if x != nil { + return x.Project + } + return "" +} + +func (x *HmacKeyMetadata) GetServiceAccountEmail() string { + if x != nil { + return x.ServiceAccountEmail + } + return "" +} + +func (x *HmacKeyMetadata) GetState() string { + if x != nil { + return x.State + } + return "" +} + +func (x *HmacKeyMetadata) GetCreateTime() *timestamppb.Timestamp { + if x != nil { + return x.CreateTime + } + return nil +} + +func (x *HmacKeyMetadata) GetUpdateTime() *timestamppb.Timestamp { + if x != nil { + return x.UpdateTime + } + return nil +} + +func (x *HmacKeyMetadata) GetEtag() string { + if x != nil { + return x.Etag + } + return "" +} + +// A directive to publish Pub/Sub notifications upon changes to a bucket. +type Notification struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Required. The resource name of this notification. + // Format: + // `projects/{project}/buckets/{bucket}/notificationConfigs/{notification}` + // The `{project}` portion may be `_` for globally unique buckets. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // Required. The Pub/Sub topic to which this subscription publishes. Formatted as: + // '//pubsub.googleapis.com/projects/{project-identifier}/topics/{my-topic}' + Topic string `protobuf:"bytes,2,opt,name=topic,proto3" json:"topic,omitempty"` + // The etag of the Notification. + // If included in the metadata of GetNotificationRequest, the operation will + // only be performed if the etag matches that of the Notification. + Etag string `protobuf:"bytes,7,opt,name=etag,proto3" json:"etag,omitempty"` + // If present, only send notifications about listed event types. If empty, + // sent notifications for all event types. + EventTypes []string `protobuf:"bytes,3,rep,name=event_types,json=eventTypes,proto3" json:"event_types,omitempty"` + // A list of additional attributes to attach to each Pub/Sub + // message published for this notification subscription. + CustomAttributes map[string]string `protobuf:"bytes,4,rep,name=custom_attributes,json=customAttributes,proto3" json:"custom_attributes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // If present, only apply this notification config to object names that + // begin with this prefix. + ObjectNamePrefix string `protobuf:"bytes,5,opt,name=object_name_prefix,json=objectNamePrefix,proto3" json:"object_name_prefix,omitempty"` + // Required. The desired content of the Payload. + PayloadFormat string `protobuf:"bytes,6,opt,name=payload_format,json=payloadFormat,proto3" json:"payload_format,omitempty"` +} + +func (x *Notification) Reset() { + *x = Notification{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[45] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Notification) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Notification) ProtoMessage() {} + +func (x *Notification) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[45] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Notification.ProtoReflect.Descriptor instead. +func (*Notification) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{45} +} + +func (x *Notification) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Notification) GetTopic() string { + if x != nil { + return x.Topic + } + return "" +} + +func (x *Notification) GetEtag() string { + if x != nil { + return x.Etag + } + return "" +} + +func (x *Notification) GetEventTypes() []string { + if x != nil { + return x.EventTypes + } + return nil +} + +func (x *Notification) GetCustomAttributes() map[string]string { + if x != nil { + return x.CustomAttributes + } + return nil +} + +func (x *Notification) GetObjectNamePrefix() string { + if x != nil { + return x.ObjectNamePrefix + } + return "" +} + +func (x *Notification) GetPayloadFormat() string { + if x != nil { + return x.PayloadFormat + } + return "" +} + +// Describes the Customer-Supplied Encryption Key mechanism used to store an +// Object's data at rest. +type CustomerEncryption struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The encryption algorithm. + EncryptionAlgorithm string `protobuf:"bytes,1,opt,name=encryption_algorithm,json=encryptionAlgorithm,proto3" json:"encryption_algorithm,omitempty"` + // SHA256 hash value of the encryption key. + // In raw bytes format (not base64-encoded). + KeySha256Bytes []byte `protobuf:"bytes,3,opt,name=key_sha256_bytes,json=keySha256Bytes,proto3" json:"key_sha256_bytes,omitempty"` +} + +func (x *CustomerEncryption) Reset() { + *x = CustomerEncryption{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[46] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CustomerEncryption) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CustomerEncryption) ProtoMessage() {} + +func (x *CustomerEncryption) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[46] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CustomerEncryption.ProtoReflect.Descriptor instead. +func (*CustomerEncryption) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{46} +} + +func (x *CustomerEncryption) GetEncryptionAlgorithm() string { + if x != nil { + return x.EncryptionAlgorithm + } + return "" +} + +func (x *CustomerEncryption) GetKeySha256Bytes() []byte { + if x != nil { + return x.KeySha256Bytes + } + return nil +} + +// An object. +type Object struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Immutable. The name of this object. Nearly any sequence of unicode characters is + // valid. See + // [Guidelines](https://cloud.google.com/storage/docs/naming-objects). + // Example: `test.txt` + // The `name` field by itself does not uniquely identify a Cloud Storage + // object. A Cloud Storage object is uniquely identified by the tuple of + // (bucket, object, generation). + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // Immutable. The name of the bucket containing this object. + Bucket string `protobuf:"bytes,2,opt,name=bucket,proto3" json:"bucket,omitempty"` + // The etag of the object. + // If included in the metadata of an update or delete request message, the + // operation will only be performed if the etag matches that of the live + // object. + Etag string `protobuf:"bytes,27,opt,name=etag,proto3" json:"etag,omitempty"` + // Immutable. The content generation of this object. Used for object versioning. + // Attempting to set or update this field will result in a + // [FieldViolation][google.rpc.BadRequest.FieldViolation]. + Generation int64 `protobuf:"varint,3,opt,name=generation,proto3" json:"generation,omitempty"` + // Output only. The version of the metadata for this generation of this object. Used for + // preconditions and for detecting changes in metadata. A metageneration + // number is only meaningful in the context of a particular generation of a + // particular object. + // Attempting to set or update this field will result in a + // [FieldViolation][google.rpc.BadRequest.FieldViolation]. + Metageneration int64 `protobuf:"varint,4,opt,name=metageneration,proto3" json:"metageneration,omitempty"` + // Storage class of the object. + StorageClass string `protobuf:"bytes,5,opt,name=storage_class,json=storageClass,proto3" json:"storage_class,omitempty"` + // Output only. Content-Length of the object data in bytes, matching + // [https://tools.ietf.org/html/rfc7230#section-3.3.2][RFC 7230 §3.3.2]. + // Attempting to set or update this field will result in a + // [FieldViolation][google.rpc.BadRequest.FieldViolation]. + Size int64 `protobuf:"varint,6,opt,name=size,proto3" json:"size,omitempty"` + // Content-Encoding of the object data, matching + // [https://tools.ietf.org/html/rfc7231#section-3.1.2.2][RFC 7231 §3.1.2.2] + ContentEncoding string `protobuf:"bytes,7,opt,name=content_encoding,json=contentEncoding,proto3" json:"content_encoding,omitempty"` + // Content-Disposition of the object data, matching + // [https://tools.ietf.org/html/rfc6266][RFC 6266]. + ContentDisposition string `protobuf:"bytes,8,opt,name=content_disposition,json=contentDisposition,proto3" json:"content_disposition,omitempty"` + // Cache-Control directive for the object data, matching + // [https://tools.ietf.org/html/rfc7234#section-5.2"][RFC 7234 §5.2]. + // If omitted, and the object is accessible to all anonymous users, the + // default will be `public, max-age=3600`. + CacheControl string `protobuf:"bytes,9,opt,name=cache_control,json=cacheControl,proto3" json:"cache_control,omitempty"` + // Access controls on the object. + // If iamConfig.uniformBucketLevelAccess is enabled on the parent + // bucket, requests to set, read, or modify acl is an error. + Acl []*ObjectAccessControl `protobuf:"bytes,10,rep,name=acl,proto3" json:"acl,omitempty"` + // Content-Language of the object data, matching + // [https://tools.ietf.org/html/rfc7231#section-3.1.3.2][RFC 7231 §3.1.3.2]. + ContentLanguage string `protobuf:"bytes,11,opt,name=content_language,json=contentLanguage,proto3" json:"content_language,omitempty"` + // Output only. The deletion time of the object. Will be returned if and only if this + // version of the object has been deleted. + // Attempting to set or update this field will result in a + // [FieldViolation][google.rpc.BadRequest.FieldViolation]. + DeleteTime *timestamppb.Timestamp `protobuf:"bytes,12,opt,name=delete_time,json=deleteTime,proto3" json:"delete_time,omitempty"` + // Content-Type of the object data, matching + // [https://tools.ietf.org/html/rfc7231#section-3.1.1.5][RFC 7231 §3.1.1.5]. + // If an object is stored without a Content-Type, it is served as + // `application/octet-stream`. + ContentType string `protobuf:"bytes,13,opt,name=content_type,json=contentType,proto3" json:"content_type,omitempty"` + // Output only. The creation time of the object. + // Attempting to set or update this field will result in a + // [FieldViolation][google.rpc.BadRequest.FieldViolation]. + CreateTime *timestamppb.Timestamp `protobuf:"bytes,14,opt,name=create_time,json=createTime,proto3" json:"create_time,omitempty"` + // Output only. Number of underlying components that make up this object. Components are + // accumulated by compose operations. + // Attempting to set or update this field will result in a + // [FieldViolation][google.rpc.BadRequest.FieldViolation]. + ComponentCount int32 `protobuf:"varint,15,opt,name=component_count,json=componentCount,proto3" json:"component_count,omitempty"` + // Output only. Hashes for the data part of this object. + Checksums *ObjectChecksums `protobuf:"bytes,16,opt,name=checksums,proto3" json:"checksums,omitempty"` + // Output only. The modification time of the object metadata. + // Set initially to object creation time and then updated whenever any + // metadata of the object changes. This includes changes made by a requester, + // such as modifying custom metadata, as well as changes made by Cloud Storage + // on behalf of a requester, such as changing the storage class based on an + // Object Lifecycle Configuration. + // Attempting to set or update this field will result in a + // [FieldViolation][google.rpc.BadRequest.FieldViolation]. + UpdateTime *timestamppb.Timestamp `protobuf:"bytes,17,opt,name=update_time,json=updateTime,proto3" json:"update_time,omitempty"` + // Cloud KMS Key used to encrypt this object, if the object is encrypted by + // such a key. + KmsKey string `protobuf:"bytes,18,opt,name=kms_key,json=kmsKey,proto3" json:"kms_key,omitempty"` + // Output only. The time at which the object's storage class was last changed. When the + // object is initially created, it will be set to time_created. + // Attempting to set or update this field will result in a + // [FieldViolation][google.rpc.BadRequest.FieldViolation]. + UpdateStorageClassTime *timestamppb.Timestamp `protobuf:"bytes,19,opt,name=update_storage_class_time,json=updateStorageClassTime,proto3" json:"update_storage_class_time,omitempty"` + // Whether an object is under temporary hold. While this flag is set to true, + // the object is protected against deletion and overwrites. A common use case + // of this flag is regulatory investigations where objects need to be retained + // while the investigation is ongoing. Note that unlike event-based hold, + // temporary hold does not impact retention expiration time of an object. + TemporaryHold bool `protobuf:"varint,20,opt,name=temporary_hold,json=temporaryHold,proto3" json:"temporary_hold,omitempty"` + // A server-determined value that specifies the earliest time that the + // object's retention period expires. + // Note 1: This field is not provided for objects with an active event-based + // hold, since retention expiration is unknown until the hold is removed. + // Note 2: This value can be provided even when temporary hold is set (so that + // the user can reason about policy without having to first unset the + // temporary hold). + RetentionExpireTime *timestamppb.Timestamp `protobuf:"bytes,21,opt,name=retention_expire_time,json=retentionExpireTime,proto3" json:"retention_expire_time,omitempty"` + // User-provided metadata, in key/value pairs. + Metadata map[string]string `protobuf:"bytes,22,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // Whether an object is under event-based hold. + // An event-based hold is a way to force the retention of an object until + // after some event occurs. Once the hold is released by explicitly setting + // this field to false, the object will become subject to any bucket-level + // retention policy, except that the retention duration will be calculated + // from the time the event based hold was lifted, rather than the time the + // object was created. + // + // In a WriteObject request, not setting this field implies that the value + // should be taken from the parent bucket's "default_event_based_hold" field. + // In a response, this field will always be set to true or false. + EventBasedHold *bool `protobuf:"varint,23,opt,name=event_based_hold,json=eventBasedHold,proto3,oneof" json:"event_based_hold,omitempty"` + // Output only. The owner of the object. This will always be the uploader of the object. + // Attempting to set or update this field will result in a + // [FieldViolation][google.rpc.BadRequest.FieldViolation]. + Owner *Owner `protobuf:"bytes,24,opt,name=owner,proto3" json:"owner,omitempty"` + // Metadata of Customer-Supplied Encryption Key, if the object is encrypted by + // such a key. + CustomerEncryption *CustomerEncryption `protobuf:"bytes,25,opt,name=customer_encryption,json=customerEncryption,proto3" json:"customer_encryption,omitempty"` + // A user-specified timestamp set on an object. + CustomTime *timestamppb.Timestamp `protobuf:"bytes,26,opt,name=custom_time,json=customTime,proto3" json:"custom_time,omitempty"` +} + +func (x *Object) Reset() { + *x = Object{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[47] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Object) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Object) ProtoMessage() {} + +func (x *Object) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[47] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Object.ProtoReflect.Descriptor instead. +func (*Object) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{47} +} + +func (x *Object) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Object) GetBucket() string { + if x != nil { + return x.Bucket + } + return "" +} + +func (x *Object) GetEtag() string { + if x != nil { + return x.Etag + } + return "" +} + +func (x *Object) GetGeneration() int64 { + if x != nil { + return x.Generation + } + return 0 +} + +func (x *Object) GetMetageneration() int64 { + if x != nil { + return x.Metageneration + } + return 0 +} + +func (x *Object) GetStorageClass() string { + if x != nil { + return x.StorageClass + } + return "" +} + +func (x *Object) GetSize() int64 { + if x != nil { + return x.Size + } + return 0 +} + +func (x *Object) GetContentEncoding() string { + if x != nil { + return x.ContentEncoding + } + return "" +} + +func (x *Object) GetContentDisposition() string { + if x != nil { + return x.ContentDisposition + } + return "" +} + +func (x *Object) GetCacheControl() string { + if x != nil { + return x.CacheControl + } + return "" +} + +func (x *Object) GetAcl() []*ObjectAccessControl { + if x != nil { + return x.Acl + } + return nil +} + +func (x *Object) GetContentLanguage() string { + if x != nil { + return x.ContentLanguage + } + return "" +} + +func (x *Object) GetDeleteTime() *timestamppb.Timestamp { + if x != nil { + return x.DeleteTime + } + return nil +} + +func (x *Object) GetContentType() string { + if x != nil { + return x.ContentType + } + return "" +} + +func (x *Object) GetCreateTime() *timestamppb.Timestamp { + if x != nil { + return x.CreateTime + } + return nil +} + +func (x *Object) GetComponentCount() int32 { + if x != nil { + return x.ComponentCount + } + return 0 +} + +func (x *Object) GetChecksums() *ObjectChecksums { + if x != nil { + return x.Checksums + } + return nil +} + +func (x *Object) GetUpdateTime() *timestamppb.Timestamp { + if x != nil { + return x.UpdateTime + } + return nil +} + +func (x *Object) GetKmsKey() string { + if x != nil { + return x.KmsKey + } + return "" +} + +func (x *Object) GetUpdateStorageClassTime() *timestamppb.Timestamp { + if x != nil { + return x.UpdateStorageClassTime + } + return nil +} + +func (x *Object) GetTemporaryHold() bool { + if x != nil { + return x.TemporaryHold + } + return false +} + +func (x *Object) GetRetentionExpireTime() *timestamppb.Timestamp { + if x != nil { + return x.RetentionExpireTime + } + return nil +} + +func (x *Object) GetMetadata() map[string]string { + if x != nil { + return x.Metadata + } + return nil +} + +func (x *Object) GetEventBasedHold() bool { + if x != nil && x.EventBasedHold != nil { + return *x.EventBasedHold + } + return false +} + +func (x *Object) GetOwner() *Owner { + if x != nil { + return x.Owner + } + return nil +} + +func (x *Object) GetCustomerEncryption() *CustomerEncryption { + if x != nil { + return x.CustomerEncryption + } + return nil +} + +func (x *Object) GetCustomTime() *timestamppb.Timestamp { + if x != nil { + return x.CustomTime + } + return nil +} + +// An access-control entry. +type ObjectAccessControl struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The access permission for the entity. + Role string `protobuf:"bytes,1,opt,name=role,proto3" json:"role,omitempty"` + // The ID of the access-control entry. + Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` + // The entity holding the permission, in one of the following forms: + // * `user-{userid}` + // * `user-{email}` + // * `group-{groupid}` + // * `group-{email}` + // * `domain-{domain}` + // * `project-{team}-{projectnumber}` + // * `project-{team}-{projectid}` + // * `allUsers` + // * `allAuthenticatedUsers` + // Examples: + // * The user `liz@example.com` would be `user-liz@example.com`. + // * The group `example@googlegroups.com` would be + // `group-example@googlegroups.com`. + // * All members of the Google Apps for Business domain `example.com` would be + // `domain-example.com`. + // For project entities, `project-{team}-{projectnumber}` format will be + // returned on response. + Entity string `protobuf:"bytes,3,opt,name=entity,proto3" json:"entity,omitempty"` + // Output only. The alternative entity format, if exists. For project entities, + // `project-{team}-{projectid}` format will be returned on response. + EntityAlt string `protobuf:"bytes,9,opt,name=entity_alt,json=entityAlt,proto3" json:"entity_alt,omitempty"` + // The ID for the entity, if any. + EntityId string `protobuf:"bytes,4,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"` + // The etag of the ObjectAccessControl. + // If included in the metadata of an update or delete request message, the + // operation will only be performed if the etag matches that of the live + // object's ObjectAccessControl. + Etag string `protobuf:"bytes,8,opt,name=etag,proto3" json:"etag,omitempty"` + // The email address associated with the entity, if any. + Email string `protobuf:"bytes,5,opt,name=email,proto3" json:"email,omitempty"` + // The domain associated with the entity, if any. + Domain string `protobuf:"bytes,6,opt,name=domain,proto3" json:"domain,omitempty"` + // The project team associated with the entity, if any. + ProjectTeam *ProjectTeam `protobuf:"bytes,7,opt,name=project_team,json=projectTeam,proto3" json:"project_team,omitempty"` +} + +func (x *ObjectAccessControl) Reset() { + *x = ObjectAccessControl{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[48] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ObjectAccessControl) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ObjectAccessControl) ProtoMessage() {} + +func (x *ObjectAccessControl) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[48] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ObjectAccessControl.ProtoReflect.Descriptor instead. +func (*ObjectAccessControl) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{48} +} + +func (x *ObjectAccessControl) GetRole() string { + if x != nil { + return x.Role + } + return "" +} + +func (x *ObjectAccessControl) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *ObjectAccessControl) GetEntity() string { + if x != nil { + return x.Entity + } + return "" +} + +func (x *ObjectAccessControl) GetEntityAlt() string { + if x != nil { + return x.EntityAlt + } + return "" +} + +func (x *ObjectAccessControl) GetEntityId() string { + if x != nil { + return x.EntityId + } + return "" +} + +func (x *ObjectAccessControl) GetEtag() string { + if x != nil { + return x.Etag + } + return "" +} + +func (x *ObjectAccessControl) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +func (x *ObjectAccessControl) GetDomain() string { + if x != nil { + return x.Domain + } + return "" +} + +func (x *ObjectAccessControl) GetProjectTeam() *ProjectTeam { + if x != nil { + return x.ProjectTeam + } + return nil +} + +// The result of a call to Objects.ListObjects +type ListObjectsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The list of items. + Objects []*Object `protobuf:"bytes,1,rep,name=objects,proto3" json:"objects,omitempty"` + // The list of prefixes of objects matching-but-not-listed up to and including + // the requested delimiter. + Prefixes []string `protobuf:"bytes,2,rep,name=prefixes,proto3" json:"prefixes,omitempty"` + // The continuation token, used to page through large result sets. Provide + // this value in a subsequent request to return the next page of results. + NextPageToken string `protobuf:"bytes,3,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"` +} + +func (x *ListObjectsResponse) Reset() { + *x = ListObjectsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[49] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListObjectsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListObjectsResponse) ProtoMessage() {} + +func (x *ListObjectsResponse) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[49] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListObjectsResponse.ProtoReflect.Descriptor instead. +func (*ListObjectsResponse) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{49} +} + +func (x *ListObjectsResponse) GetObjects() []*Object { + if x != nil { + return x.Objects + } + return nil +} + +func (x *ListObjectsResponse) GetPrefixes() []string { + if x != nil { + return x.Prefixes + } + return nil +} + +func (x *ListObjectsResponse) GetNextPageToken() string { + if x != nil { + return x.NextPageToken + } + return "" +} + +// Represents the Viewers, Editors, or Owners of a given project. +type ProjectTeam struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The project number. + ProjectNumber string `protobuf:"bytes,1,opt,name=project_number,json=projectNumber,proto3" json:"project_number,omitempty"` + // The team. + Team string `protobuf:"bytes,2,opt,name=team,proto3" json:"team,omitempty"` +} + +func (x *ProjectTeam) Reset() { + *x = ProjectTeam{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[50] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ProjectTeam) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProjectTeam) ProtoMessage() {} + +func (x *ProjectTeam) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[50] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ProjectTeam.ProtoReflect.Descriptor instead. +func (*ProjectTeam) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{50} +} + +func (x *ProjectTeam) GetProjectNumber() string { + if x != nil { + return x.ProjectNumber + } + return "" +} + +func (x *ProjectTeam) GetTeam() string { + if x != nil { + return x.Team + } + return "" +} + +// A service account, owned by Cloud Storage, which may be used when taking +// action on behalf of a given project, for example to publish Pub/Sub +// notifications or to retrieve security keys. +type ServiceAccount struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The ID of the notification. + EmailAddress string `protobuf:"bytes,1,opt,name=email_address,json=emailAddress,proto3" json:"email_address,omitempty"` +} + +func (x *ServiceAccount) Reset() { + *x = ServiceAccount{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[51] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ServiceAccount) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServiceAccount) ProtoMessage() {} + +func (x *ServiceAccount) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[51] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServiceAccount.ProtoReflect.Descriptor instead. +func (*ServiceAccount) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{51} +} + +func (x *ServiceAccount) GetEmailAddress() string { + if x != nil { + return x.EmailAddress + } + return "" +} + +// The owner of a specific resource. +type Owner struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The entity, in the form `user-`*userId*. + Entity string `protobuf:"bytes,1,opt,name=entity,proto3" json:"entity,omitempty"` + // The ID for the entity. + EntityId string `protobuf:"bytes,2,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"` +} + +func (x *Owner) Reset() { + *x = Owner{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[52] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Owner) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Owner) ProtoMessage() {} + +func (x *Owner) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[52] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Owner.ProtoReflect.Descriptor instead. +func (*Owner) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{52} +} + +func (x *Owner) GetEntity() string { + if x != nil { + return x.Entity + } + return "" +} + +func (x *Owner) GetEntityId() string { + if x != nil { + return x.EntityId + } + return "" +} + +// Specifies a requested range of bytes to download. +type ContentRange struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The starting offset of the object data. + Start int64 `protobuf:"varint,1,opt,name=start,proto3" json:"start,omitempty"` + // The ending offset of the object data. + End int64 `protobuf:"varint,2,opt,name=end,proto3" json:"end,omitempty"` + // The complete length of the object data. + CompleteLength int64 `protobuf:"varint,3,opt,name=complete_length,json=completeLength,proto3" json:"complete_length,omitempty"` +} + +func (x *ContentRange) Reset() { + *x = ContentRange{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[53] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ContentRange) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ContentRange) ProtoMessage() {} + +func (x *ContentRange) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[53] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ContentRange.ProtoReflect.Descriptor instead. +func (*ContentRange) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{53} +} + +func (x *ContentRange) GetStart() int64 { + if x != nil { + return x.Start + } + return 0 +} + +func (x *ContentRange) GetEnd() int64 { + if x != nil { + return x.End + } + return 0 +} + +func (x *ContentRange) GetCompleteLength() int64 { + if x != nil { + return x.CompleteLength + } + return 0 +} + +// Description of a source object for a composition request. +type ComposeObjectRequest_SourceObject struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Required. The source object's name. All source objects must reside in the same + // bucket. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // The generation of this object to use as the source. + Generation int64 `protobuf:"varint,2,opt,name=generation,proto3" json:"generation,omitempty"` + // Conditions that must be met for this operation to execute. + ObjectPreconditions *ComposeObjectRequest_SourceObject_ObjectPreconditions `protobuf:"bytes,3,opt,name=object_preconditions,json=objectPreconditions,proto3" json:"object_preconditions,omitempty"` +} + +func (x *ComposeObjectRequest_SourceObject) Reset() { + *x = ComposeObjectRequest_SourceObject{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[54] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ComposeObjectRequest_SourceObject) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ComposeObjectRequest_SourceObject) ProtoMessage() {} + +func (x *ComposeObjectRequest_SourceObject) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[54] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ComposeObjectRequest_SourceObject.ProtoReflect.Descriptor instead. +func (*ComposeObjectRequest_SourceObject) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{12, 0} +} + +func (x *ComposeObjectRequest_SourceObject) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *ComposeObjectRequest_SourceObject) GetGeneration() int64 { + if x != nil { + return x.Generation + } + return 0 +} + +func (x *ComposeObjectRequest_SourceObject) GetObjectPreconditions() *ComposeObjectRequest_SourceObject_ObjectPreconditions { + if x != nil { + return x.ObjectPreconditions + } + return nil +} + +// Preconditions for a source object of a composition request. +type ComposeObjectRequest_SourceObject_ObjectPreconditions struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Only perform the composition if the generation of the source object + // that would be used matches this value. If this value and a generation + // are both specified, they must be the same value or the call will fail. + IfGenerationMatch *int64 `protobuf:"varint,1,opt,name=if_generation_match,json=ifGenerationMatch,proto3,oneof" json:"if_generation_match,omitempty"` +} + +func (x *ComposeObjectRequest_SourceObject_ObjectPreconditions) Reset() { + *x = ComposeObjectRequest_SourceObject_ObjectPreconditions{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[55] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ComposeObjectRequest_SourceObject_ObjectPreconditions) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ComposeObjectRequest_SourceObject_ObjectPreconditions) ProtoMessage() {} + +func (x *ComposeObjectRequest_SourceObject_ObjectPreconditions) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[55] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ComposeObjectRequest_SourceObject_ObjectPreconditions.ProtoReflect.Descriptor instead. +func (*ComposeObjectRequest_SourceObject_ObjectPreconditions) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{12, 0, 0} +} + +func (x *ComposeObjectRequest_SourceObject_ObjectPreconditions) GetIfGenerationMatch() int64 { + if x != nil && x.IfGenerationMatch != nil { + return *x.IfGenerationMatch + } + return 0 +} + +// Billing properties of a bucket. +type Bucket_Billing struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // When set to true, Requester Pays is enabled for this bucket. + RequesterPays bool `protobuf:"varint,1,opt,name=requester_pays,json=requesterPays,proto3" json:"requester_pays,omitempty"` +} + +func (x *Bucket_Billing) Reset() { + *x = Bucket_Billing{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[56] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Bucket_Billing) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Bucket_Billing) ProtoMessage() {} + +func (x *Bucket_Billing) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[56] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Bucket_Billing.ProtoReflect.Descriptor instead. +func (*Bucket_Billing) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{40, 0} +} + +func (x *Bucket_Billing) GetRequesterPays() bool { + if x != nil { + return x.RequesterPays + } + return false +} + +// Cross-Origin Response sharing (CORS) properties for a bucket. +// For more on Cloud Storage and CORS, see +// https://cloud.google.com/storage/docs/cross-origin. +// For more on CORS in general, see https://tools.ietf.org/html/rfc6454. +type Bucket_Cors struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The list of Origins eligible to receive CORS response headers. See + // [https://tools.ietf.org/html/rfc6454][RFC 6454] for more on origins. + // Note: "*" is permitted in the list of origins, and means "any Origin". + Origin []string `protobuf:"bytes,1,rep,name=origin,proto3" json:"origin,omitempty"` + // The list of HTTP methods on which to include CORS response headers, + // (`GET`, `OPTIONS`, `POST`, etc) Note: "*" is permitted in the list of + // methods, and means "any method". + Method []string `protobuf:"bytes,2,rep,name=method,proto3" json:"method,omitempty"` + // The list of HTTP headers other than the + // [https://www.w3.org/TR/cors/#simple-response-header][simple response + // headers] to give permission for the user-agent to share across domains. + ResponseHeader []string `protobuf:"bytes,3,rep,name=response_header,json=responseHeader,proto3" json:"response_header,omitempty"` + // The value, in seconds, to return in the + // [https://www.w3.org/TR/cors/#access-control-max-age-response-header][Access-Control-Max-Age + // header] used in preflight responses. + MaxAgeSeconds int32 `protobuf:"varint,4,opt,name=max_age_seconds,json=maxAgeSeconds,proto3" json:"max_age_seconds,omitempty"` +} + +func (x *Bucket_Cors) Reset() { + *x = Bucket_Cors{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[57] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Bucket_Cors) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Bucket_Cors) ProtoMessage() {} + +func (x *Bucket_Cors) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[57] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Bucket_Cors.ProtoReflect.Descriptor instead. +func (*Bucket_Cors) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{40, 1} +} + +func (x *Bucket_Cors) GetOrigin() []string { + if x != nil { + return x.Origin + } + return nil +} + +func (x *Bucket_Cors) GetMethod() []string { + if x != nil { + return x.Method + } + return nil +} + +func (x *Bucket_Cors) GetResponseHeader() []string { + if x != nil { + return x.ResponseHeader + } + return nil +} + +func (x *Bucket_Cors) GetMaxAgeSeconds() int32 { + if x != nil { + return x.MaxAgeSeconds + } + return 0 +} + +// Encryption properties of a bucket. +type Bucket_Encryption struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The name of the Cloud KMS key that will be used to encrypt objects + // inserted into this bucket, if no encryption method is specified. + DefaultKmsKey string `protobuf:"bytes,1,opt,name=default_kms_key,json=defaultKmsKey,proto3" json:"default_kms_key,omitempty"` +} + +func (x *Bucket_Encryption) Reset() { + *x = Bucket_Encryption{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[58] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Bucket_Encryption) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Bucket_Encryption) ProtoMessage() {} + +func (x *Bucket_Encryption) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[58] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Bucket_Encryption.ProtoReflect.Descriptor instead. +func (*Bucket_Encryption) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{40, 2} +} + +func (x *Bucket_Encryption) GetDefaultKmsKey() string { + if x != nil { + return x.DefaultKmsKey + } + return "" +} + +// Bucket restriction options. +type Bucket_IamConfig struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Bucket restriction options currently enforced on the bucket. + UniformBucketLevelAccess *Bucket_IamConfig_UniformBucketLevelAccess `protobuf:"bytes,1,opt,name=uniform_bucket_level_access,json=uniformBucketLevelAccess,proto3" json:"uniform_bucket_level_access,omitempty"` + // Whether IAM will enforce public access prevention. Valid values are + // "enforced" or "inherited". + PublicAccessPrevention string `protobuf:"bytes,3,opt,name=public_access_prevention,json=publicAccessPrevention,proto3" json:"public_access_prevention,omitempty"` +} + +func (x *Bucket_IamConfig) Reset() { + *x = Bucket_IamConfig{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[59] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Bucket_IamConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Bucket_IamConfig) ProtoMessage() {} + +func (x *Bucket_IamConfig) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[59] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Bucket_IamConfig.ProtoReflect.Descriptor instead. +func (*Bucket_IamConfig) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{40, 3} +} + +func (x *Bucket_IamConfig) GetUniformBucketLevelAccess() *Bucket_IamConfig_UniformBucketLevelAccess { + if x != nil { + return x.UniformBucketLevelAccess + } + return nil +} + +func (x *Bucket_IamConfig) GetPublicAccessPrevention() string { + if x != nil { + return x.PublicAccessPrevention + } + return "" +} + +// Lifecycle properties of a bucket. +// For more information, see https://cloud.google.com/storage/docs/lifecycle. +type Bucket_Lifecycle struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // A lifecycle management rule, which is made of an action to take and the + // condition(s) under which the action will be taken. + Rule []*Bucket_Lifecycle_Rule `protobuf:"bytes,1,rep,name=rule,proto3" json:"rule,omitempty"` +} + +func (x *Bucket_Lifecycle) Reset() { + *x = Bucket_Lifecycle{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[60] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Bucket_Lifecycle) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Bucket_Lifecycle) ProtoMessage() {} + +func (x *Bucket_Lifecycle) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[60] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Bucket_Lifecycle.ProtoReflect.Descriptor instead. +func (*Bucket_Lifecycle) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{40, 4} +} + +func (x *Bucket_Lifecycle) GetRule() []*Bucket_Lifecycle_Rule { + if x != nil { + return x.Rule + } + return nil +} + +// Logging-related properties of a bucket. +type Bucket_Logging struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The destination bucket where the current bucket's logs should be placed, + // using path format (like `projects/123456/buckets/foo`). + LogBucket string `protobuf:"bytes,1,opt,name=log_bucket,json=logBucket,proto3" json:"log_bucket,omitempty"` + // A prefix for log object names. + LogObjectPrefix string `protobuf:"bytes,2,opt,name=log_object_prefix,json=logObjectPrefix,proto3" json:"log_object_prefix,omitempty"` +} + +func (x *Bucket_Logging) Reset() { + *x = Bucket_Logging{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[61] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Bucket_Logging) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Bucket_Logging) ProtoMessage() {} + +func (x *Bucket_Logging) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[61] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Bucket_Logging.ProtoReflect.Descriptor instead. +func (*Bucket_Logging) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{40, 5} +} + +func (x *Bucket_Logging) GetLogBucket() string { + if x != nil { + return x.LogBucket + } + return "" +} + +func (x *Bucket_Logging) GetLogObjectPrefix() string { + if x != nil { + return x.LogObjectPrefix + } + return "" +} + +// Retention policy properties of a bucket. +type Bucket_RetentionPolicy struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Server-determined value that indicates the time from which policy was + // enforced and effective. + EffectiveTime *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=effective_time,json=effectiveTime,proto3" json:"effective_time,omitempty"` + // Once locked, an object retention policy cannot be modified. + IsLocked bool `protobuf:"varint,2,opt,name=is_locked,json=isLocked,proto3" json:"is_locked,omitempty"` + // The duration in seconds that objects need to be retained. Retention + // duration must be greater than zero and less than 100 years. Note that + // enforcement of retention periods less than a day is not guaranteed. Such + // periods should only be used for testing purposes. + RetentionPeriod *int64 `protobuf:"varint,3,opt,name=retention_period,json=retentionPeriod,proto3,oneof" json:"retention_period,omitempty"` +} + +func (x *Bucket_RetentionPolicy) Reset() { + *x = Bucket_RetentionPolicy{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[62] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Bucket_RetentionPolicy) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Bucket_RetentionPolicy) ProtoMessage() {} + +func (x *Bucket_RetentionPolicy) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[62] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Bucket_RetentionPolicy.ProtoReflect.Descriptor instead. +func (*Bucket_RetentionPolicy) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{40, 6} +} + +func (x *Bucket_RetentionPolicy) GetEffectiveTime() *timestamppb.Timestamp { + if x != nil { + return x.EffectiveTime + } + return nil +} + +func (x *Bucket_RetentionPolicy) GetIsLocked() bool { + if x != nil { + return x.IsLocked + } + return false +} + +func (x *Bucket_RetentionPolicy) GetRetentionPeriod() int64 { + if x != nil && x.RetentionPeriod != nil { + return *x.RetentionPeriod + } + return 0 +} + +// Properties of a bucket related to versioning. +// For more on Cloud Storage versioning, see +// https://cloud.google.com/storage/docs/object-versioning. +type Bucket_Versioning struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // While set to true, versioning is fully enabled for this bucket. + Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"` +} + +func (x *Bucket_Versioning) Reset() { + *x = Bucket_Versioning{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[63] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Bucket_Versioning) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Bucket_Versioning) ProtoMessage() {} + +func (x *Bucket_Versioning) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[63] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Bucket_Versioning.ProtoReflect.Descriptor instead. +func (*Bucket_Versioning) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{40, 7} +} + +func (x *Bucket_Versioning) GetEnabled() bool { + if x != nil { + return x.Enabled + } + return false +} + +// Properties of a bucket related to accessing the contents as a static +// website. For more on hosting a static website via Cloud Storage, see +// https://cloud.google.com/storage/docs/hosting-static-website. +type Bucket_Website struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // If the requested object path is missing, the service will ensure the path + // has a trailing '/', append this suffix, and attempt to retrieve the + // resulting object. This allows the creation of `index.html` + // objects to represent directory pages. + MainPageSuffix string `protobuf:"bytes,1,opt,name=main_page_suffix,json=mainPageSuffix,proto3" json:"main_page_suffix,omitempty"` + // If the requested object path is missing, and any + // `mainPageSuffix` object is missing, if applicable, the service + // will return the named object from this bucket as the content for a + // [https://tools.ietf.org/html/rfc7231#section-6.5.4][404 Not Found] + // result. + NotFoundPage string `protobuf:"bytes,2,opt,name=not_found_page,json=notFoundPage,proto3" json:"not_found_page,omitempty"` +} + +func (x *Bucket_Website) Reset() { + *x = Bucket_Website{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[64] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Bucket_Website) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Bucket_Website) ProtoMessage() {} + +func (x *Bucket_Website) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[64] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Bucket_Website.ProtoReflect.Descriptor instead. +func (*Bucket_Website) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{40, 8} +} + +func (x *Bucket_Website) GetMainPageSuffix() string { + if x != nil { + return x.MainPageSuffix + } + return "" +} + +func (x *Bucket_Website) GetNotFoundPage() string { + if x != nil { + return x.NotFoundPage + } + return "" +} + +// Configuration for Custom Dual Regions. It should specify precisely two +// eligible regions within the same Multiregion. More information on regions +// may be found [https://cloud.google.com/storage/docs/locations][here]. +type Bucket_CustomPlacementConfig struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // List of locations to use for data placement. + DataLocations []string `protobuf:"bytes,1,rep,name=data_locations,json=dataLocations,proto3" json:"data_locations,omitempty"` +} + +func (x *Bucket_CustomPlacementConfig) Reset() { + *x = Bucket_CustomPlacementConfig{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[65] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Bucket_CustomPlacementConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Bucket_CustomPlacementConfig) ProtoMessage() {} + +func (x *Bucket_CustomPlacementConfig) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[65] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Bucket_CustomPlacementConfig.ProtoReflect.Descriptor instead. +func (*Bucket_CustomPlacementConfig) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{40, 9} +} + +func (x *Bucket_CustomPlacementConfig) GetDataLocations() []string { + if x != nil { + return x.DataLocations + } + return nil +} + +// Configuration for a bucket's Autoclass feature. +type Bucket_Autoclass struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Enables Autoclass. + Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"` + // Output only. Latest instant at which the `enabled` field was set to true after being + // disabled/unconfigured or set to false after being enabled. If Autoclass + // is enabled when the bucket is created, the toggle_time is set to the + // bucket creation time. + ToggleTime *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=toggle_time,json=toggleTime,proto3" json:"toggle_time,omitempty"` +} + +func (x *Bucket_Autoclass) Reset() { + *x = Bucket_Autoclass{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[66] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Bucket_Autoclass) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Bucket_Autoclass) ProtoMessage() {} + +func (x *Bucket_Autoclass) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[66] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Bucket_Autoclass.ProtoReflect.Descriptor instead. +func (*Bucket_Autoclass) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{40, 10} +} + +func (x *Bucket_Autoclass) GetEnabled() bool { + if x != nil { + return x.Enabled + } + return false +} + +func (x *Bucket_Autoclass) GetToggleTime() *timestamppb.Timestamp { + if x != nil { + return x.ToggleTime + } + return nil +} + +// Settings for Uniform Bucket level access. +// See https://cloud.google.com/storage/docs/uniform-bucket-level-access. +type Bucket_IamConfig_UniformBucketLevelAccess struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // If set, access checks only use bucket-level IAM policies or above. + Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"` + // The deadline time for changing + // `iamConfig.uniformBucketLevelAccess.enabled` from `true` to `false`. + // Mutable until the specified deadline is reached, but not afterward. + LockTime *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=lock_time,json=lockTime,proto3" json:"lock_time,omitempty"` +} + +func (x *Bucket_IamConfig_UniformBucketLevelAccess) Reset() { + *x = Bucket_IamConfig_UniformBucketLevelAccess{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[68] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Bucket_IamConfig_UniformBucketLevelAccess) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Bucket_IamConfig_UniformBucketLevelAccess) ProtoMessage() {} + +func (x *Bucket_IamConfig_UniformBucketLevelAccess) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[68] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Bucket_IamConfig_UniformBucketLevelAccess.ProtoReflect.Descriptor instead. +func (*Bucket_IamConfig_UniformBucketLevelAccess) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{40, 3, 0} +} + +func (x *Bucket_IamConfig_UniformBucketLevelAccess) GetEnabled() bool { + if x != nil { + return x.Enabled + } + return false +} + +func (x *Bucket_IamConfig_UniformBucketLevelAccess) GetLockTime() *timestamppb.Timestamp { + if x != nil { + return x.LockTime + } + return nil +} + +// A lifecycle Rule, combining an action to take on an object and a +// condition which will trigger that action. +type Bucket_Lifecycle_Rule struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The action to take. + Action *Bucket_Lifecycle_Rule_Action `protobuf:"bytes,1,opt,name=action,proto3" json:"action,omitempty"` + // The condition(s) under which the action will be taken. + Condition *Bucket_Lifecycle_Rule_Condition `protobuf:"bytes,2,opt,name=condition,proto3" json:"condition,omitempty"` +} + +func (x *Bucket_Lifecycle_Rule) Reset() { + *x = Bucket_Lifecycle_Rule{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[69] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Bucket_Lifecycle_Rule) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Bucket_Lifecycle_Rule) ProtoMessage() {} + +func (x *Bucket_Lifecycle_Rule) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[69] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Bucket_Lifecycle_Rule.ProtoReflect.Descriptor instead. +func (*Bucket_Lifecycle_Rule) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{40, 4, 0} +} + +func (x *Bucket_Lifecycle_Rule) GetAction() *Bucket_Lifecycle_Rule_Action { + if x != nil { + return x.Action + } + return nil +} + +func (x *Bucket_Lifecycle_Rule) GetCondition() *Bucket_Lifecycle_Rule_Condition { + if x != nil { + return x.Condition + } + return nil +} + +// An action to take on an object. +type Bucket_Lifecycle_Rule_Action struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Type of the action. Currently, only `Delete`, `SetStorageClass`, and + // `AbortIncompleteMultipartUpload` are supported. + Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` + // Target storage class. Required iff the type of the action is + // SetStorageClass. + StorageClass string `protobuf:"bytes,2,opt,name=storage_class,json=storageClass,proto3" json:"storage_class,omitempty"` +} + +func (x *Bucket_Lifecycle_Rule_Action) Reset() { + *x = Bucket_Lifecycle_Rule_Action{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[70] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Bucket_Lifecycle_Rule_Action) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Bucket_Lifecycle_Rule_Action) ProtoMessage() {} + +func (x *Bucket_Lifecycle_Rule_Action) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[70] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Bucket_Lifecycle_Rule_Action.ProtoReflect.Descriptor instead. +func (*Bucket_Lifecycle_Rule_Action) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{40, 4, 0, 0} +} + +func (x *Bucket_Lifecycle_Rule_Action) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *Bucket_Lifecycle_Rule_Action) GetStorageClass() string { + if x != nil { + return x.StorageClass + } + return "" +} + +// A condition of an object which triggers some action. +type Bucket_Lifecycle_Rule_Condition struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Age of an object (in days). This condition is satisfied when an + // object reaches the specified age. + // A value of 0 indicates that all objects immediately match this + // condition. + AgeDays *int32 `protobuf:"varint,1,opt,name=age_days,json=ageDays,proto3,oneof" json:"age_days,omitempty"` + // This condition is satisfied when an object is created before midnight + // of the specified date in UTC. + CreatedBefore *date.Date `protobuf:"bytes,2,opt,name=created_before,json=createdBefore,proto3" json:"created_before,omitempty"` + // Relevant only for versioned objects. If the value is + // `true`, this condition matches live objects; if the value + // is `false`, it matches archived objects. + IsLive *bool `protobuf:"varint,3,opt,name=is_live,json=isLive,proto3,oneof" json:"is_live,omitempty"` + // Relevant only for versioned objects. If the value is N, this + // condition is satisfied when there are at least N versions (including + // the live version) newer than this version of the object. + NumNewerVersions *int32 `protobuf:"varint,4,opt,name=num_newer_versions,json=numNewerVersions,proto3,oneof" json:"num_newer_versions,omitempty"` + // Objects having any of the storage classes specified by this condition + // will be matched. Values include `MULTI_REGIONAL`, `REGIONAL`, + // `NEARLINE`, `COLDLINE`, `STANDARD`, and + // `DURABLE_REDUCED_AVAILABILITY`. + MatchesStorageClass []string `protobuf:"bytes,5,rep,name=matches_storage_class,json=matchesStorageClass,proto3" json:"matches_storage_class,omitempty"` + // Number of days that have elapsed since the custom timestamp set on an + // object. + // The value of the field must be a nonnegative integer. + DaysSinceCustomTime *int32 `protobuf:"varint,7,opt,name=days_since_custom_time,json=daysSinceCustomTime,proto3,oneof" json:"days_since_custom_time,omitempty"` + // An object matches this condition if the custom timestamp set on the + // object is before the specified date in UTC. + CustomTimeBefore *date.Date `protobuf:"bytes,8,opt,name=custom_time_before,json=customTimeBefore,proto3" json:"custom_time_before,omitempty"` + // This condition is relevant only for versioned objects. An object + // version satisfies this condition only if these many days have been + // passed since it became noncurrent. The value of the field must be a + // nonnegative integer. If it's zero, the object version will become + // eligible for Lifecycle action as soon as it becomes noncurrent. + DaysSinceNoncurrentTime *int32 `protobuf:"varint,9,opt,name=days_since_noncurrent_time,json=daysSinceNoncurrentTime,proto3,oneof" json:"days_since_noncurrent_time,omitempty"` + // This condition is relevant only for versioned objects. An object + // version satisfies this condition only if it became noncurrent before + // the specified date in UTC. + NoncurrentTimeBefore *date.Date `protobuf:"bytes,10,opt,name=noncurrent_time_before,json=noncurrentTimeBefore,proto3" json:"noncurrent_time_before,omitempty"` + // List of object name prefixes. If any prefix exactly matches the + // beginning of the object name, the condition evaluates to true. + MatchesPrefix []string `protobuf:"bytes,11,rep,name=matches_prefix,json=matchesPrefix,proto3" json:"matches_prefix,omitempty"` + // List of object name suffixes. If any suffix exactly matches the + // end of the object name, the condition evaluates to true. + MatchesSuffix []string `protobuf:"bytes,12,rep,name=matches_suffix,json=matchesSuffix,proto3" json:"matches_suffix,omitempty"` +} + +func (x *Bucket_Lifecycle_Rule_Condition) Reset() { + *x = Bucket_Lifecycle_Rule_Condition{} + if protoimpl.UnsafeEnabled { + mi := &file_google_storage_v2_storage_proto_msgTypes[71] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Bucket_Lifecycle_Rule_Condition) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Bucket_Lifecycle_Rule_Condition) ProtoMessage() {} + +func (x *Bucket_Lifecycle_Rule_Condition) ProtoReflect() protoreflect.Message { + mi := &file_google_storage_v2_storage_proto_msgTypes[71] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Bucket_Lifecycle_Rule_Condition.ProtoReflect.Descriptor instead. +func (*Bucket_Lifecycle_Rule_Condition) Descriptor() ([]byte, []int) { + return file_google_storage_v2_storage_proto_rawDescGZIP(), []int{40, 4, 0, 1} +} + +func (x *Bucket_Lifecycle_Rule_Condition) GetAgeDays() int32 { + if x != nil && x.AgeDays != nil { + return *x.AgeDays + } + return 0 +} + +func (x *Bucket_Lifecycle_Rule_Condition) GetCreatedBefore() *date.Date { + if x != nil { + return x.CreatedBefore + } + return nil +} + +func (x *Bucket_Lifecycle_Rule_Condition) GetIsLive() bool { + if x != nil && x.IsLive != nil { + return *x.IsLive + } + return false +} + +func (x *Bucket_Lifecycle_Rule_Condition) GetNumNewerVersions() int32 { + if x != nil && x.NumNewerVersions != nil { + return *x.NumNewerVersions + } + return 0 +} + +func (x *Bucket_Lifecycle_Rule_Condition) GetMatchesStorageClass() []string { + if x != nil { + return x.MatchesStorageClass + } + return nil +} + +func (x *Bucket_Lifecycle_Rule_Condition) GetDaysSinceCustomTime() int32 { + if x != nil && x.DaysSinceCustomTime != nil { + return *x.DaysSinceCustomTime + } + return 0 +} + +func (x *Bucket_Lifecycle_Rule_Condition) GetCustomTimeBefore() *date.Date { + if x != nil { + return x.CustomTimeBefore + } + return nil +} + +func (x *Bucket_Lifecycle_Rule_Condition) GetDaysSinceNoncurrentTime() int32 { + if x != nil && x.DaysSinceNoncurrentTime != nil { + return *x.DaysSinceNoncurrentTime + } + return 0 +} + +func (x *Bucket_Lifecycle_Rule_Condition) GetNoncurrentTimeBefore() *date.Date { + if x != nil { + return x.NoncurrentTimeBefore + } + return nil +} + +func (x *Bucket_Lifecycle_Rule_Condition) GetMatchesPrefix() []string { + if x != nil { + return x.MatchesPrefix + } + return nil +} + +func (x *Bucket_Lifecycle_Rule_Condition) GetMatchesSuffix() []string { + if x != nil { + return x.MatchesSuffix + } + return nil +} + +var File_google_storage_v2_storage_proto protoreflect.FileDescriptor + +var file_google_storage_v2_storage_proto_rawDesc = []byte{ + 0x0a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, + 0x2f, 0x76, 0x32, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x12, 0x11, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, + 0x65, 0x2e, 0x76, 0x32, 0x1a, 0x17, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, + 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, + 0x62, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x18, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x69, 0x61, 0x6d, 0x2f, + 0x76, 0x31, 0x2f, 0x69, 0x61, 0x6d, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x1a, 0x1a, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x69, 0x61, 0x6d, 0x2f, + 0x76, 0x31, 0x2f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, + 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x20, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x66, 0x69, + 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, + 0x16, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x2f, 0x64, 0x61, 0x74, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x8d, 0x02, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x39, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x25, 0xe0, + 0x41, 0x02, 0xfa, 0x41, 0x1f, 0x0a, 0x1d, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x42, 0x75, + 0x63, 0x6b, 0x65, 0x74, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3b, 0x0a, 0x17, 0x69, 0x66, + 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x15, 0x69, + 0x66, 0x4d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, + 0x61, 0x74, 0x63, 0x68, 0x88, 0x01, 0x01, 0x12, 0x42, 0x0a, 0x1b, 0x69, 0x66, 0x5f, 0x6d, 0x65, + 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x74, + 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x48, 0x01, 0x52, 0x18, + 0x69, 0x66, 0x4d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x4e, 0x6f, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x88, 0x01, 0x01, 0x42, 0x1a, 0x0a, 0x18, 0x5f, + 0x69, 0x66, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x42, 0x1e, 0x0a, 0x1c, 0x5f, 0x69, 0x66, 0x5f, 0x6d, + 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, + 0x74, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x22, 0xd6, 0x02, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x42, + 0x75, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x39, 0x0a, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x25, 0xe0, 0x41, 0x02, 0xfa, + 0x41, 0x1f, 0x0a, 0x1d, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x42, 0x75, 0x63, 0x6b, 0x65, + 0x74, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3b, 0x0a, 0x17, 0x69, 0x66, 0x5f, 0x6d, 0x65, + 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x74, + 0x63, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x15, 0x69, 0x66, 0x4d, 0x65, + 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, + 0x68, 0x88, 0x01, 0x01, 0x12, 0x42, 0x0a, 0x1b, 0x69, 0x66, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x67, + 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x74, 0x5f, 0x6d, 0x61, + 0x74, 0x63, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x48, 0x01, 0x52, 0x18, 0x69, 0x66, 0x4d, + 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, + 0x4d, 0x61, 0x74, 0x63, 0x68, 0x88, 0x01, 0x01, 0x12, 0x3c, 0x0a, 0x09, 0x72, 0x65, 0x61, 0x64, + 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, + 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x48, 0x02, 0x52, 0x08, 0x72, 0x65, 0x61, 0x64, 0x4d, + 0x61, 0x73, 0x6b, 0x88, 0x01, 0x01, 0x42, 0x1a, 0x0a, 0x18, 0x5f, 0x69, 0x66, 0x5f, 0x6d, 0x65, + 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x74, + 0x63, 0x68, 0x42, 0x1e, 0x0a, 0x1c, 0x5f, 0x69, 0x66, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x67, 0x65, + 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x74, 0x5f, 0x6d, 0x61, 0x74, + 0x63, 0x68, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, + 0x22, 0xa1, 0x02, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42, 0x75, 0x63, 0x6b, 0x65, + 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4b, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, + 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x33, 0xe0, 0x41, 0x02, 0xfa, 0x41, 0x2d, + 0x0a, 0x2b, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x6d, + 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, + 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x06, 0x70, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x31, 0x0a, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, + 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, + 0x52, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x20, 0x0a, 0x09, 0x62, 0x75, 0x63, 0x6b, + 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02, + 0x52, 0x08, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, + 0x65, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x61, 0x63, 0x6c, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0d, 0x70, 0x72, 0x65, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x41, 0x63, + 0x6c, 0x12, 0x41, 0x0a, 0x1d, 0x70, 0x72, 0x65, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x5f, + 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x61, + 0x63, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x1a, 0x70, 0x72, 0x65, 0x64, 0x65, 0x66, + 0x69, 0x6e, 0x65, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x41, 0x63, 0x6c, 0x22, 0x81, 0x02, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x75, 0x63, + 0x6b, 0x65, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4b, 0x0a, 0x06, 0x70, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x33, 0xe0, 0x41, 0x02, + 0xfa, 0x41, 0x2d, 0x0a, 0x2b, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, + 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x61, 0x67, + 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, + 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x67, 0x65, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, 0x3c, 0x0a, 0x09, + 0x72, 0x65, 0x61, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x48, 0x00, 0x52, 0x08, 0x72, + 0x65, 0x61, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x88, 0x01, 0x01, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x72, + 0x65, 0x61, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x22, 0x72, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, + 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x33, 0x0a, 0x07, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, + 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x07, 0x62, 0x75, 0x63, + 0x6b, 0x65, 0x74, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, + 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, + 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x9e, 0x01, 0x0a, + 0x20, 0x4c, 0x6f, 0x63, 0x6b, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x65, 0x74, 0x65, 0x6e, + 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x3d, 0x0a, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x25, 0xe0, 0x41, 0x02, 0xfa, 0x41, 0x1f, 0x0a, 0x1d, 0x73, 0x74, 0x6f, 0x72, 0x61, + 0x67, 0x65, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, + 0x12, 0x3b, 0x0a, 0x17, 0x69, 0x66, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x03, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x15, 0x69, 0x66, 0x4d, 0x65, 0x74, 0x61, 0x67, 0x65, + 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0xb6, 0x03, + 0x0a, 0x13, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x36, 0x0a, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, + 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, + 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x3b, 0x0a, + 0x17, 0x69, 0x66, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, + 0x52, 0x15, 0x69, 0x66, 0x4d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x88, 0x01, 0x01, 0x12, 0x42, 0x0a, 0x1b, 0x69, 0x66, + 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x6e, 0x6f, 0x74, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x48, + 0x01, 0x52, 0x18, 0x69, 0x66, 0x4d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x88, 0x01, 0x01, 0x12, 0x25, + 0x0a, 0x0e, 0x70, 0x72, 0x65, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x61, 0x63, 0x6c, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x72, 0x65, 0x64, 0x65, 0x66, 0x69, 0x6e, + 0x65, 0x64, 0x41, 0x63, 0x6c, 0x12, 0x41, 0x0a, 0x1d, 0x70, 0x72, 0x65, 0x64, 0x65, 0x66, 0x69, + 0x6e, 0x65, 0x64, 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x6f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x5f, 0x61, 0x63, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x1a, 0x70, 0x72, + 0x65, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x4f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x41, 0x63, 0x6c, 0x12, 0x40, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x0a, + 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x61, 0x73, 0x6b, 0x42, 0x1a, 0x0a, 0x18, 0x5f, 0x69, + 0x66, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x42, 0x1e, 0x0a, 0x1c, 0x5f, 0x69, 0x66, 0x5f, 0x6d, 0x65, + 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x74, + 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x5c, 0x0a, 0x19, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x2b, 0xe0, 0x41, 0x02, 0xfa, 0x41, 0x25, 0x0a, 0x23, 0x73, 0x74, 0x6f, 0x72, 0x61, + 0x67, 0x65, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x53, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x39, + 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x25, 0xe0, 0x41, + 0x02, 0xfa, 0x41, 0x1f, 0x0a, 0x1d, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x42, 0x75, 0x63, + 0x6b, 0x65, 0x74, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0xa4, 0x01, 0x0a, 0x19, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3d, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x25, 0xe0, 0x41, 0x02, 0xfa, 0x41, 0x1f, 0x12, + 0x1d, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, + 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x06, + 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x48, 0x0a, 0x0c, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, + 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x03, 0xe0, + 0x41, 0x02, 0x52, 0x0c, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x22, 0x95, 0x01, 0x0a, 0x18, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3d, 0x0a, + 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x25, 0xe0, + 0x41, 0x02, 0xfa, 0x41, 0x1f, 0x12, 0x1d, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x42, 0x75, + 0x63, 0x6b, 0x65, 0x74, 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, + 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x67, + 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, + 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x8a, 0x01, 0x0a, 0x19, 0x4c, 0x69, 0x73, + 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x45, 0x0a, 0x0d, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, + 0x32, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0d, + 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x26, 0x0a, + 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0xf4, 0x06, 0x0a, 0x14, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x73, + 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x40, + 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, + 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x42, 0x03, + 0xe0, 0x41, 0x02, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x5b, 0x0a, 0x0e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6f, 0x6d, + 0x70, 0x6f, 0x73, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x2e, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x0d, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x3c, 0x0a, + 0x1a, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x65, + 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x61, 0x63, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x18, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, + 0x65, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x41, 0x63, 0x6c, 0x12, 0x33, 0x0a, 0x13, 0x69, + 0x66, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x74, + 0x63, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x11, 0x69, 0x66, 0x47, 0x65, + 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x88, 0x01, 0x01, + 0x12, 0x3b, 0x0a, 0x17, 0x69, 0x66, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x03, 0x48, 0x01, 0x52, 0x15, 0x69, 0x66, 0x4d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x88, 0x01, 0x01, 0x12, 0x3f, 0x0a, + 0x07, 0x6b, 0x6d, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, 0x26, + 0xfa, 0x41, 0x23, 0x0a, 0x21, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x6b, 0x6d, 0x73, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x72, 0x79, + 0x70, 0x74, 0x6f, 0x4b, 0x65, 0x79, 0x52, 0x06, 0x6b, 0x6d, 0x73, 0x4b, 0x65, 0x79, 0x12, 0x6d, + 0x0a, 0x1c, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, + 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x72, 0x61, + 0x6d, 0x73, 0x52, 0x19, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0xa8, 0x02, + 0x0a, 0x0c, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x17, + 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, + 0x02, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x67, 0x65, 0x6e, 0x65, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x67, 0x65, 0x6e, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x7b, 0x0a, 0x14, 0x6f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x5f, 0x70, 0x72, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x48, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, + 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x73, + 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x53, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x4f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x50, 0x72, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, + 0x13, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x50, 0x72, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x62, 0x0a, 0x13, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x50, 0x72, + 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x33, 0x0a, 0x13, 0x69, + 0x66, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x74, + 0x63, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x11, 0x69, 0x66, 0x47, 0x65, + 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x88, 0x01, 0x01, + 0x42, 0x16, 0x0a, 0x14, 0x5f, 0x69, 0x66, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x42, 0x16, 0x0a, 0x14, 0x5f, 0x69, 0x66, 0x5f, + 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, + 0x42, 0x1a, 0x0a, 0x18, 0x5f, 0x69, 0x66, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x22, 0xc0, 0x04, 0x0a, + 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, + 0x74, 0x12, 0x1b, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1e, + 0x0a, 0x0a, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x0a, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x33, + 0x0a, 0x13, 0x69, 0x66, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x11, 0x69, + 0x66, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, + 0x88, 0x01, 0x01, 0x12, 0x3a, 0x0a, 0x17, 0x69, 0x66, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x74, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x03, 0x48, 0x01, 0x52, 0x14, 0x69, 0x66, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x88, 0x01, 0x01, 0x12, + 0x3b, 0x0a, 0x17, 0x69, 0x66, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, + 0x48, 0x02, 0x52, 0x15, 0x69, 0x66, 0x4d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x88, 0x01, 0x01, 0x12, 0x42, 0x0a, 0x1b, + 0x69, 0x66, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x6e, 0x6f, 0x74, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x08, 0x20, 0x01, 0x28, + 0x03, 0x48, 0x03, 0x52, 0x18, 0x69, 0x66, 0x4d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x88, 0x01, 0x01, + 0x12, 0x6d, 0x0a, 0x1c, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, + 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, + 0x72, 0x61, 0x6d, 0x73, 0x52, 0x19, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x42, + 0x16, 0x0a, 0x14, 0x5f, 0x69, 0x66, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x42, 0x1a, 0x0a, 0x18, 0x5f, 0x69, 0x66, 0x5f, 0x67, + 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x74, 0x5f, 0x6d, 0x61, + 0x74, 0x63, 0x68, 0x42, 0x1a, 0x0a, 0x18, 0x5f, 0x69, 0x66, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x67, + 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x42, + 0x1e, 0x0a, 0x1c, 0x5f, 0x69, 0x66, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x74, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x22, + 0x3f, 0x0a, 0x1b, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x61, 0x62, + 0x6c, 0x65, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, + 0x0a, 0x09, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x08, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, + 0x22, 0x1e, 0x0a, 0x1c, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x61, + 0x62, 0x6c, 0x65, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0xca, 0x05, 0x0a, 0x11, 0x52, 0x65, 0x61, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x06, 0x62, 0x75, 0x63, + 0x6b, 0x65, 0x74, 0x12, 0x1b, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x12, 0x1e, 0x0a, 0x0a, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x72, 0x65, 0x61, 0x64, 0x4f, 0x66, 0x66, 0x73, 0x65, + 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x72, 0x65, 0x61, 0x64, 0x4c, 0x69, 0x6d, 0x69, 0x74, + 0x12, 0x33, 0x0a, 0x13, 0x69, 0x66, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, + 0x11, 0x69, 0x66, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x74, + 0x63, 0x68, 0x88, 0x01, 0x01, 0x12, 0x3a, 0x0a, 0x17, 0x69, 0x66, 0x5f, 0x67, 0x65, 0x6e, 0x65, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x74, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x48, 0x01, 0x52, 0x14, 0x69, 0x66, 0x47, 0x65, 0x6e, 0x65, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x88, 0x01, + 0x01, 0x12, 0x3b, 0x0a, 0x17, 0x69, 0x66, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x03, 0x48, 0x02, 0x52, 0x15, 0x69, 0x66, 0x4d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x88, 0x01, 0x01, 0x12, 0x42, + 0x0a, 0x1b, 0x69, 0x66, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x74, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x09, 0x20, + 0x01, 0x28, 0x03, 0x48, 0x03, 0x52, 0x18, 0x69, 0x66, 0x4d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x88, + 0x01, 0x01, 0x12, 0x6d, 0x0a, 0x1c, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x5f, 0x6f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x70, 0x61, 0x72, 0x61, + 0x6d, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x19, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, + 0x73, 0x12, 0x3c, 0x0a, 0x09, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x0c, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, + 0x48, 0x04, 0x52, 0x08, 0x72, 0x65, 0x61, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x88, 0x01, 0x01, 0x42, + 0x16, 0x0a, 0x14, 0x5f, 0x69, 0x66, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x42, 0x1a, 0x0a, 0x18, 0x5f, 0x69, 0x66, 0x5f, 0x67, + 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x74, 0x5f, 0x6d, 0x61, + 0x74, 0x63, 0x68, 0x42, 0x1a, 0x0a, 0x18, 0x5f, 0x69, 0x66, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x67, + 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x42, + 0x1e, 0x0a, 0x1c, 0x5f, 0x69, 0x66, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x74, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x42, + 0x0c, 0x0a, 0x0a, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x22, 0x89, 0x05, + 0x0a, 0x10, 0x47, 0x65, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x12, + 0x1b, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x03, 0xe0, 0x41, 0x02, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1e, 0x0a, 0x0a, + 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x0a, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x13, + 0x69, 0x66, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, + 0x74, 0x63, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x11, 0x69, 0x66, 0x47, + 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x88, 0x01, + 0x01, 0x12, 0x3a, 0x0a, 0x17, 0x69, 0x66, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x74, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x03, 0x48, 0x01, 0x52, 0x14, 0x69, 0x66, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x88, 0x01, 0x01, 0x12, 0x3b, 0x0a, + 0x17, 0x69, 0x66, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x48, 0x02, + 0x52, 0x15, 0x69, 0x66, 0x4d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x88, 0x01, 0x01, 0x12, 0x42, 0x0a, 0x1b, 0x69, 0x66, + 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x6e, 0x6f, 0x74, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x48, + 0x03, 0x52, 0x18, 0x69, 0x66, 0x4d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x88, 0x01, 0x01, 0x12, 0x6d, + 0x0a, 0x1c, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x08, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, + 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x72, 0x61, + 0x6d, 0x73, 0x52, 0x19, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x3c, 0x0a, + 0x09, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x48, 0x04, 0x52, 0x08, + 0x72, 0x65, 0x61, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x88, 0x01, 0x01, 0x42, 0x16, 0x0a, 0x14, 0x5f, + 0x69, 0x66, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, + 0x74, 0x63, 0x68, 0x42, 0x1a, 0x0a, 0x18, 0x5f, 0x69, 0x66, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x74, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x42, + 0x1a, 0x0a, 0x18, 0x5f, 0x69, 0x66, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x42, 0x1e, 0x0a, 0x1c, 0x5f, + 0x69, 0x66, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x6e, 0x6f, 0x74, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, + 0x72, 0x65, 0x61, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x22, 0xaf, 0x02, 0x0a, 0x12, 0x52, 0x65, + 0x61, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x4d, 0x0a, 0x10, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x6d, 0x65, 0x64, 0x5f, + 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x43, + 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x6d, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x52, 0x0f, + 0x63, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x6d, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x12, + 0x4d, 0x0a, 0x10, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x73, + 0x75, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x4f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x73, 0x52, 0x0f, 0x6f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x73, 0x12, 0x44, + 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, + 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, + 0x61, 0x6e, 0x67, 0x65, 0x12, 0x35, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x8c, 0x04, 0x0a, 0x0f, + 0x57, 0x72, 0x69, 0x74, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x70, 0x65, 0x63, 0x12, + 0x3a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, + 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x42, 0x03, 0xe0, 0x41, + 0x02, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x70, + 0x72, 0x65, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x61, 0x63, 0x6c, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x72, 0x65, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x41, + 0x63, 0x6c, 0x12, 0x33, 0x0a, 0x13, 0x69, 0x66, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x48, + 0x00, 0x52, 0x11, 0x69, 0x66, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, + 0x61, 0x74, 0x63, 0x68, 0x88, 0x01, 0x01, 0x12, 0x3a, 0x0a, 0x17, 0x69, 0x66, 0x5f, 0x67, 0x65, + 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x74, 0x5f, 0x6d, 0x61, 0x74, + 0x63, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x48, 0x01, 0x52, 0x14, 0x69, 0x66, 0x47, 0x65, + 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, + 0x88, 0x01, 0x01, 0x12, 0x3b, 0x0a, 0x17, 0x69, 0x66, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x67, 0x65, + 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x03, 0x48, 0x02, 0x52, 0x15, 0x69, 0x66, 0x4d, 0x65, 0x74, 0x61, 0x67, 0x65, + 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x88, 0x01, 0x01, + 0x12, 0x42, 0x0a, 0x1b, 0x69, 0x66, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x74, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x03, 0x48, 0x03, 0x52, 0x18, 0x69, 0x66, 0x4d, 0x65, 0x74, 0x61, 0x67, + 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x4d, 0x61, 0x74, 0x63, + 0x68, 0x88, 0x01, 0x01, 0x12, 0x24, 0x0a, 0x0b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x73, + 0x69, 0x7a, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x48, 0x04, 0x52, 0x0a, 0x6f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x88, 0x01, 0x01, 0x42, 0x16, 0x0a, 0x14, 0x5f, 0x69, + 0x66, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x74, + 0x63, 0x68, 0x42, 0x1a, 0x0a, 0x18, 0x5f, 0x69, 0x66, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x74, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x42, 0x1a, + 0x0a, 0x18, 0x5f, 0x69, 0x66, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x42, 0x1e, 0x0a, 0x1c, 0x5f, 0x69, + 0x66, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x6e, 0x6f, 0x74, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x6f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x22, 0xf8, 0x03, 0x0a, 0x12, 0x57, + 0x72, 0x69, 0x74, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x1d, 0x0a, 0x09, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x08, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, + 0x12, 0x50, 0x0a, 0x11, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x5f, 0x73, 0x70, 0x65, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, + 0x57, 0x72, 0x69, 0x74, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x70, 0x65, 0x63, 0x48, + 0x00, 0x52, 0x0f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x70, + 0x65, 0x63, 0x12, 0x26, 0x0a, 0x0c, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x6f, 0x66, 0x66, 0x73, + 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x0b, 0x77, + 0x72, 0x69, 0x74, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x4f, 0x0a, 0x10, 0x63, 0x68, + 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x6d, 0x65, 0x64, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, + 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, + 0x6d, 0x6d, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x48, 0x01, 0x52, 0x0f, 0x63, 0x68, 0x65, 0x63, + 0x6b, 0x73, 0x75, 0x6d, 0x6d, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x12, 0x4d, 0x0a, 0x10, 0x6f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x73, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, + 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x73, 0x52, 0x0f, 0x6f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x69, + 0x6e, 0x69, 0x73, 0x68, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0b, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x57, 0x72, 0x69, 0x74, 0x65, 0x12, 0x6d, 0x0a, + 0x1c, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x08, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, + 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, + 0x73, 0x52, 0x19, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x42, 0x0f, 0x0a, 0x0d, + 0x66, 0x69, 0x72, 0x73, 0x74, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x06, 0x0a, + 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x87, 0x01, 0x0a, 0x13, 0x57, 0x72, 0x69, 0x74, 0x65, 0x4f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x27, 0x0a, + 0x0e, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x0d, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, + 0x65, 0x64, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x37, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x4f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x48, 0x00, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x42, + 0x0e, 0x0a, 0x0c, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, + 0xc9, 0x03, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3d, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x25, 0xe0, 0x41, 0x02, 0xfa, 0x41, 0x1f, 0x12, 0x1d, + 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, + 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x06, 0x70, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, + 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, + 0x7a, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x65, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x72, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x64, 0x65, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x72, 0x12, + 0x3c, 0x0a, 0x1a, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x74, 0x72, 0x61, 0x69, 0x6c, + 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x72, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x18, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x54, 0x72, 0x61, 0x69, + 0x6c, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x72, 0x12, 0x16, 0x0a, + 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, + 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x12, 0x3c, 0x0a, 0x09, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x08, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, + 0x48, 0x00, 0x52, 0x08, 0x72, 0x65, 0x61, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x88, 0x01, 0x01, 0x12, + 0x2f, 0x0a, 0x13, 0x6c, 0x65, 0x78, 0x69, 0x63, 0x6f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, + 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x6c, 0x65, + 0x78, 0x69, 0x63, 0x6f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x53, 0x74, 0x61, 0x72, 0x74, + 0x12, 0x2b, 0x0a, 0x11, 0x6c, 0x65, 0x78, 0x69, 0x63, 0x6f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, + 0x63, 0x5f, 0x65, 0x6e, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x6c, 0x65, 0x78, + 0x69, 0x63, 0x6f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x45, 0x6e, 0x64, 0x42, 0x0c, 0x0a, + 0x0a, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x22, 0xaa, 0x01, 0x0a, 0x17, + 0x51, 0x75, 0x65, 0x72, 0x79, 0x57, 0x72, 0x69, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x09, 0x75, 0x70, 0x6c, 0x6f, 0x61, + 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, + 0x08, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x12, 0x6d, 0x0a, 0x1c, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x2c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, + 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x19, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x22, 0x8c, 0x01, 0x0a, 0x18, 0x51, 0x75, 0x65, + 0x72, 0x79, 0x57, 0x72, 0x69, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0e, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, + 0x65, 0x64, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, + 0x0d, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x64, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x37, + 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, + 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x48, 0x00, 0x52, 0x08, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x42, 0x0e, 0x0a, 0x0c, 0x77, 0x72, 0x69, 0x74, 0x65, + 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0xc4, 0x0d, 0x0a, 0x14, 0x52, 0x65, 0x77, 0x72, + 0x69, 0x74, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x31, 0x0a, 0x10, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x18, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, 0xe0, 0x41, 0x02, 0xe0, + 0x41, 0x05, 0x52, 0x0f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, + 0x61, 0x6d, 0x65, 0x12, 0x57, 0x0a, 0x12, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x19, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x28, 0xe0, 0x41, 0x02, 0xe0, 0x41, 0x05, 0xfa, 0x41, 0x1f, 0x0a, 0x1d, 0x73, 0x74, 0x6f, 0x72, + 0x61, 0x67, 0x65, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x11, 0x64, 0x65, 0x73, 0x74, 0x69, + 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x56, 0x0a, 0x13, + 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x6d, 0x73, 0x5f, + 0x6b, 0x65, 0x79, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x09, 0x42, 0x26, 0xfa, 0x41, 0x23, 0x0a, 0x21, + 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x6b, 0x6d, 0x73, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, + 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x4b, 0x65, + 0x79, 0x52, 0x11, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x6d, + 0x73, 0x4b, 0x65, 0x79, 0x12, 0x3b, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x4f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x28, 0x0a, 0x0d, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x62, 0x75, 0x63, 0x6b, + 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x0c, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x28, 0x0a, 0x0d, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x0c, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x2b, 0x0a, 0x11, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, + 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x10, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x74, 0x6f, + 0x6b, 0x65, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x77, 0x72, 0x69, + 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x3c, 0x0a, 0x1a, 0x64, 0x65, 0x73, 0x74, 0x69, + 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x65, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, + 0x64, 0x5f, 0x61, 0x63, 0x6c, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x18, 0x64, 0x65, 0x73, + 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x65, 0x64, 0x65, 0x66, 0x69, 0x6e, + 0x65, 0x64, 0x41, 0x63, 0x6c, 0x12, 0x33, 0x0a, 0x13, 0x69, 0x66, 0x5f, 0x67, 0x65, 0x6e, 0x65, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x03, 0x48, 0x00, 0x52, 0x11, 0x69, 0x66, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x88, 0x01, 0x01, 0x12, 0x3a, 0x0a, 0x17, 0x69, 0x66, + 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x74, 0x5f, + 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x48, 0x01, 0x52, 0x14, 0x69, + 0x66, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x4d, 0x61, + 0x74, 0x63, 0x68, 0x88, 0x01, 0x01, 0x12, 0x3b, 0x0a, 0x17, 0x69, 0x66, 0x5f, 0x6d, 0x65, 0x74, + 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x74, 0x63, + 0x68, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x48, 0x02, 0x52, 0x15, 0x69, 0x66, 0x4d, 0x65, 0x74, + 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, + 0x88, 0x01, 0x01, 0x12, 0x42, 0x0a, 0x1b, 0x69, 0x66, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x67, 0x65, + 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x74, 0x5f, 0x6d, 0x61, 0x74, + 0x63, 0x68, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x48, 0x03, 0x52, 0x18, 0x69, 0x66, 0x4d, 0x65, + 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x4d, + 0x61, 0x74, 0x63, 0x68, 0x88, 0x01, 0x01, 0x12, 0x40, 0x0a, 0x1a, 0x69, 0x66, 0x5f, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x48, 0x04, 0x52, 0x17, 0x69, + 0x66, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x88, 0x01, 0x01, 0x12, 0x47, 0x0a, 0x1e, 0x69, 0x66, 0x5f, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x6e, 0x6f, 0x74, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x0c, 0x20, 0x01, 0x28, + 0x03, 0x48, 0x05, 0x52, 0x1a, 0x69, 0x66, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x65, 0x6e, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x88, + 0x01, 0x01, 0x12, 0x48, 0x0a, 0x1e, 0x69, 0x66, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, + 0x6d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, + 0x61, 0x74, 0x63, 0x68, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x03, 0x48, 0x06, 0x52, 0x1b, 0x69, 0x66, + 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x88, 0x01, 0x01, 0x12, 0x4f, 0x0a, 0x22, + 0x69, 0x66, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x67, 0x65, + 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x74, 0x5f, 0x6d, 0x61, 0x74, + 0x63, 0x68, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x03, 0x48, 0x07, 0x52, 0x1e, 0x69, 0x66, 0x53, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x88, 0x01, 0x01, 0x12, 0x3e, 0x0a, + 0x1c, 0x6d, 0x61, 0x78, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x72, 0x65, 0x77, 0x72, 0x69, + 0x74, 0x74, 0x65, 0x6e, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x18, 0x0f, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x18, 0x6d, 0x61, 0x78, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x65, 0x77, + 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x50, 0x65, 0x72, 0x43, 0x61, 0x6c, 0x6c, 0x12, 0x47, 0x0a, + 0x20, 0x63, 0x6f, 0x70, 0x79, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x65, 0x6e, 0x63, + 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, + 0x6d, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x1d, 0x63, 0x6f, 0x70, 0x79, 0x53, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x6c, 0x67, + 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12, 0x46, 0x0a, 0x20, 0x63, 0x6f, 0x70, 0x79, 0x5f, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x1c, 0x63, 0x6f, 0x70, 0x79, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x45, 0x6e, 0x63, 0x72, + 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x53, + 0x0a, 0x27, 0x63, 0x6f, 0x70, 0x79, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x65, 0x6e, + 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x73, 0x68, 0x61, + 0x32, 0x35, 0x36, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x22, 0x63, 0x6f, 0x70, 0x79, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x45, 0x6e, 0x63, 0x72, 0x79, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x53, 0x68, 0x61, 0x32, 0x35, 0x36, 0x42, 0x79, + 0x74, 0x65, 0x73, 0x12, 0x6d, 0x0a, 0x1c, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x5f, 0x6f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x70, 0x61, 0x72, + 0x61, 0x6d, 0x73, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x19, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x72, 0x61, + 0x6d, 0x73, 0x42, 0x16, 0x0a, 0x14, 0x5f, 0x69, 0x66, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x42, 0x1a, 0x0a, 0x18, 0x5f, 0x69, + 0x66, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x74, + 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x42, 0x1a, 0x0a, 0x18, 0x5f, 0x69, 0x66, 0x5f, 0x6d, 0x65, + 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x74, + 0x63, 0x68, 0x42, 0x1e, 0x0a, 0x1c, 0x5f, 0x69, 0x66, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x67, 0x65, + 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x74, 0x5f, 0x6d, 0x61, 0x74, + 0x63, 0x68, 0x42, 0x1d, 0x0a, 0x1b, 0x5f, 0x69, 0x66, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x74, 0x63, + 0x68, 0x42, 0x21, 0x0a, 0x1f, 0x5f, 0x69, 0x66, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, + 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x74, 0x5f, 0x6d, + 0x61, 0x74, 0x63, 0x68, 0x42, 0x21, 0x0a, 0x1f, 0x5f, 0x69, 0x66, 0x5f, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x42, 0x25, 0x0a, 0x23, 0x5f, 0x69, 0x66, 0x5f, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x74, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x22, 0xd6, + 0x01, 0x0a, 0x0f, 0x52, 0x65, 0x77, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x32, 0x0a, 0x15, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x62, 0x79, 0x74, 0x65, + 0x73, 0x5f, 0x72, 0x65, 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x13, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x65, 0x77, + 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x6f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x6f, 0x6e, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x64, 0x6f, 0x6e, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x72, + 0x65, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x77, 0x72, 0x69, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, + 0x12, 0x35, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, + 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x08, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0xe0, 0x01, 0x0a, 0x1a, 0x53, 0x74, 0x61, 0x72, + 0x74, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x61, 0x62, 0x6c, 0x65, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x53, 0x0a, 0x11, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, + 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, + 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x53, 0x70, 0x65, 0x63, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x0f, 0x77, 0x72, 0x69, 0x74, + 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x70, 0x65, 0x63, 0x12, 0x6d, 0x0a, 0x1c, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x2c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, + 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, + 0x19, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x22, 0x3a, 0x0a, 0x1b, 0x53, 0x74, + 0x61, 0x72, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x61, 0x62, 0x6c, 0x65, 0x57, 0x72, 0x69, 0x74, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x75, 0x70, 0x6c, + 0x6f, 0x61, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x70, + 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x64, 0x22, 0x87, 0x05, 0x0a, 0x13, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x36, + 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, + 0x76, 0x32, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x06, + 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x33, 0x0a, 0x13, 0x69, 0x66, 0x5f, 0x67, 0x65, 0x6e, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x11, 0x69, 0x66, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x88, 0x01, 0x01, 0x12, 0x3a, 0x0a, 0x17, 0x69, + 0x66, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x74, + 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x48, 0x01, 0x52, 0x14, + 0x69, 0x66, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, 0x4d, + 0x61, 0x74, 0x63, 0x68, 0x88, 0x01, 0x01, 0x12, 0x3b, 0x0a, 0x17, 0x69, 0x66, 0x5f, 0x6d, 0x65, + 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x74, + 0x63, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x48, 0x02, 0x52, 0x15, 0x69, 0x66, 0x4d, 0x65, + 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, + 0x68, 0x88, 0x01, 0x01, 0x12, 0x42, 0x0a, 0x1b, 0x69, 0x66, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x67, + 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x74, 0x5f, 0x6d, 0x61, + 0x74, 0x63, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x48, 0x03, 0x52, 0x18, 0x69, 0x66, 0x4d, + 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x6f, 0x74, + 0x4d, 0x61, 0x74, 0x63, 0x68, 0x88, 0x01, 0x01, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x65, 0x64, + 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x61, 0x63, 0x6c, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0d, 0x70, 0x72, 0x65, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x41, 0x63, 0x6c, 0x12, + 0x40, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, + 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x61, 0x73, + 0x6b, 0x12, 0x6d, 0x0a, 0x1c, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x5f, 0x6f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, + 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, + 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x19, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, + 0x42, 0x16, 0x0a, 0x14, 0x5f, 0x69, 0x66, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x42, 0x1a, 0x0a, 0x18, 0x5f, 0x69, 0x66, 0x5f, + 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x74, 0x5f, 0x6d, + 0x61, 0x74, 0x63, 0x68, 0x42, 0x1a, 0x0a, 0x18, 0x5f, 0x69, 0x66, 0x5f, 0x6d, 0x65, 0x74, 0x61, + 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, + 0x42, 0x1e, 0x0a, 0x1c, 0x5f, 0x69, 0x66, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x74, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, + 0x22, 0x69, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4d, 0x0a, 0x07, + 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x33, 0xe0, + 0x41, 0x02, 0xfa, 0x41, 0x2d, 0x0a, 0x2b, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x50, 0x72, 0x6f, 0x6a, 0x65, + 0x63, 0x74, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x9e, 0x01, 0x0a, 0x14, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x48, 0x6d, 0x61, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x4d, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x33, 0xe0, 0x41, 0x02, 0xfa, 0x41, 0x2d, 0x0a, 0x2b, 0x63, + 0x6c, 0x6f, 0x75, 0x64, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x6d, 0x61, 0x6e, 0x61, + 0x67, 0x65, 0x72, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, + 0x65, 0x63, 0x74, 0x12, 0x37, 0x0a, 0x15, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, + 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x13, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x81, 0x01, 0x0a, + 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x48, 0x6d, 0x61, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x48, 0x6d, 0x61, + 0x63, 0x4b, 0x65, 0x79, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x28, 0x0a, 0x10, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, + 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x0e, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x42, 0x79, 0x74, 0x65, 0x73, + 0x22, 0x87, 0x01, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x6d, 0x61, 0x63, 0x4b, + 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x09, 0x61, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, + 0x02, 0x52, 0x08, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x49, 0x64, 0x12, 0x4d, 0x0a, 0x07, 0x70, + 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x33, 0xe0, 0x41, + 0x02, 0xfa, 0x41, 0x2d, 0x0a, 0x2b, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, + 0x74, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x84, 0x01, 0x0a, 0x11, 0x47, + 0x65, 0x74, 0x48, 0x6d, 0x61, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x20, 0x0a, 0x09, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x08, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x49, 0x64, 0x12, 0x4d, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x42, 0x33, 0xe0, 0x41, 0x02, 0xfa, 0x41, 0x2d, 0x0a, 0x2b, 0x63, 0x6c, 0x6f, + 0x75, 0x64, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, + 0x72, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, + 0x74, 0x22, 0x80, 0x02, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x6d, 0x61, 0x63, 0x4b, 0x65, + 0x79, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4d, 0x0a, 0x07, 0x70, 0x72, 0x6f, + 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x33, 0xe0, 0x41, 0x02, 0xfa, + 0x41, 0x2d, 0x0a, 0x2b, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, + 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, + 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, + 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x61, 0x67, + 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, + 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x67, 0x65, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x32, 0x0a, 0x15, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, + 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x13, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x2a, 0x0a, 0x11, 0x73, 0x68, 0x6f, 0x77, + 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x0f, 0x73, 0x68, 0x6f, 0x77, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, + 0x4b, 0x65, 0x79, 0x73, 0x22, 0x7f, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x6d, 0x61, 0x63, + 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x09, + 0x68, 0x6d, 0x61, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, + 0x2e, 0x76, 0x32, 0x2e, 0x48, 0x6d, 0x61, 0x63, 0x4b, 0x65, 0x79, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x52, 0x08, 0x68, 0x6d, 0x61, 0x63, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x26, 0x0a, + 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x97, 0x01, 0x0a, 0x14, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x48, 0x6d, 0x61, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x42, + 0x0a, 0x08, 0x68, 0x6d, 0x61, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, + 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x48, 0x6d, 0x61, 0x63, 0x4b, 0x65, 0x79, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x07, 0x68, 0x6d, 0x61, 0x63, 0x4b, + 0x65, 0x79, 0x12, 0x3b, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, + 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, + 0x61, 0x73, 0x6b, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x61, 0x73, 0x6b, 0x22, + 0xbf, 0x01, 0x0a, 0x19, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x31, 0x0a, + 0x14, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x6c, 0x67, 0x6f, + 0x72, 0x69, 0x74, 0x68, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x65, 0x6e, 0x63, + 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, + 0x12, 0x30, 0x0a, 0x14, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, + 0x65, 0x79, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x12, + 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x42, 0x79, 0x74, + 0x65, 0x73, 0x12, 0x3d, 0x0a, 0x1b, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x5f, 0x62, 0x79, 0x74, 0x65, + 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x18, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x53, 0x68, 0x61, 0x32, 0x35, 0x36, 0x42, 0x79, 0x74, 0x65, + 0x73, 0x22, 0xca, 0x05, 0x0a, 0x10, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, + 0x73, 0x74, 0x61, 0x6e, 0x74, 0x73, 0x22, 0xb5, 0x05, 0x0a, 0x06, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x73, 0x12, 0x16, 0x0a, 0x12, 0x56, 0x41, 0x4c, 0x55, 0x45, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, + 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x14, 0x4d, 0x41, 0x58, + 0x5f, 0x52, 0x45, 0x41, 0x44, 0x5f, 0x43, 0x48, 0x55, 0x4e, 0x4b, 0x5f, 0x42, 0x59, 0x54, 0x45, + 0x53, 0x10, 0x80, 0x80, 0x80, 0x01, 0x12, 0x1c, 0x0a, 0x15, 0x4d, 0x41, 0x58, 0x5f, 0x57, 0x52, + 0x49, 0x54, 0x45, 0x5f, 0x43, 0x48, 0x55, 0x4e, 0x4b, 0x5f, 0x42, 0x59, 0x54, 0x45, 0x53, 0x10, + 0x80, 0x80, 0x80, 0x01, 0x12, 0x19, 0x0a, 0x12, 0x4d, 0x41, 0x58, 0x5f, 0x4f, 0x42, 0x4a, 0x45, + 0x43, 0x54, 0x5f, 0x53, 0x49, 0x5a, 0x45, 0x5f, 0x4d, 0x42, 0x10, 0x80, 0x80, 0xc0, 0x02, 0x12, + 0x29, 0x0a, 0x24, 0x4d, 0x41, 0x58, 0x5f, 0x43, 0x55, 0x53, 0x54, 0x4f, 0x4d, 0x5f, 0x4d, 0x45, + 0x54, 0x41, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x46, 0x49, 0x45, 0x4c, 0x44, 0x5f, 0x4e, 0x41, 0x4d, + 0x45, 0x5f, 0x42, 0x59, 0x54, 0x45, 0x53, 0x10, 0x80, 0x08, 0x12, 0x2a, 0x0a, 0x25, 0x4d, 0x41, + 0x58, 0x5f, 0x43, 0x55, 0x53, 0x54, 0x4f, 0x4d, 0x5f, 0x4d, 0x45, 0x54, 0x41, 0x44, 0x41, 0x54, + 0x41, 0x5f, 0x46, 0x49, 0x45, 0x4c, 0x44, 0x5f, 0x56, 0x41, 0x4c, 0x55, 0x45, 0x5f, 0x42, 0x59, + 0x54, 0x45, 0x53, 0x10, 0x80, 0x20, 0x12, 0x29, 0x0a, 0x24, 0x4d, 0x41, 0x58, 0x5f, 0x43, 0x55, + 0x53, 0x54, 0x4f, 0x4d, 0x5f, 0x4d, 0x45, 0x54, 0x41, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x54, 0x4f, + 0x54, 0x41, 0x4c, 0x5f, 0x53, 0x49, 0x5a, 0x45, 0x5f, 0x42, 0x59, 0x54, 0x45, 0x53, 0x10, 0x80, + 0x40, 0x12, 0x2a, 0x0a, 0x24, 0x4d, 0x41, 0x58, 0x5f, 0x42, 0x55, 0x43, 0x4b, 0x45, 0x54, 0x5f, + 0x4d, 0x45, 0x54, 0x41, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x54, 0x4f, 0x54, 0x41, 0x4c, 0x5f, 0x53, + 0x49, 0x5a, 0x45, 0x5f, 0x42, 0x59, 0x54, 0x45, 0x53, 0x10, 0x80, 0xa0, 0x01, 0x12, 0x27, 0x0a, + 0x23, 0x4d, 0x41, 0x58, 0x5f, 0x4e, 0x4f, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, + 0x4e, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x53, 0x5f, 0x50, 0x45, 0x52, 0x5f, 0x42, 0x55, + 0x43, 0x4b, 0x45, 0x54, 0x10, 0x64, 0x12, 0x22, 0x0a, 0x1e, 0x4d, 0x41, 0x58, 0x5f, 0x4c, 0x49, + 0x46, 0x45, 0x43, 0x59, 0x43, 0x4c, 0x45, 0x5f, 0x52, 0x55, 0x4c, 0x45, 0x53, 0x5f, 0x50, 0x45, + 0x52, 0x5f, 0x42, 0x55, 0x43, 0x4b, 0x45, 0x54, 0x10, 0x64, 0x12, 0x26, 0x0a, 0x22, 0x4d, 0x41, + 0x58, 0x5f, 0x4e, 0x4f, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x43, + 0x55, 0x53, 0x54, 0x4f, 0x4d, 0x5f, 0x41, 0x54, 0x54, 0x52, 0x49, 0x42, 0x55, 0x54, 0x45, 0x53, + 0x10, 0x05, 0x12, 0x31, 0x0a, 0x2c, 0x4d, 0x41, 0x58, 0x5f, 0x4e, 0x4f, 0x54, 0x49, 0x46, 0x49, + 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x43, 0x55, 0x53, 0x54, 0x4f, 0x4d, 0x5f, 0x41, 0x54, + 0x54, 0x52, 0x49, 0x42, 0x55, 0x54, 0x45, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x4c, 0x45, 0x4e, 0x47, + 0x54, 0x48, 0x10, 0x80, 0x02, 0x12, 0x33, 0x0a, 0x2e, 0x4d, 0x41, 0x58, 0x5f, 0x4e, 0x4f, 0x54, + 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x43, 0x55, 0x53, 0x54, 0x4f, 0x4d, + 0x5f, 0x41, 0x54, 0x54, 0x52, 0x49, 0x42, 0x55, 0x54, 0x45, 0x5f, 0x56, 0x41, 0x4c, 0x55, 0x45, + 0x5f, 0x4c, 0x45, 0x4e, 0x47, 0x54, 0x48, 0x10, 0x80, 0x08, 0x12, 0x1c, 0x0a, 0x18, 0x4d, 0x41, + 0x58, 0x5f, 0x4c, 0x41, 0x42, 0x45, 0x4c, 0x53, 0x5f, 0x45, 0x4e, 0x54, 0x52, 0x49, 0x45, 0x53, + 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x10, 0x40, 0x12, 0x1f, 0x0a, 0x1b, 0x4d, 0x41, 0x58, 0x5f, + 0x4c, 0x41, 0x42, 0x45, 0x4c, 0x53, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x56, 0x41, 0x4c, 0x55, 0x45, + 0x5f, 0x4c, 0x45, 0x4e, 0x47, 0x54, 0x48, 0x10, 0x3f, 0x12, 0x1f, 0x0a, 0x1a, 0x4d, 0x41, 0x58, + 0x5f, 0x4c, 0x41, 0x42, 0x45, 0x4c, 0x53, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x56, 0x41, 0x4c, 0x55, + 0x45, 0x5f, 0x42, 0x59, 0x54, 0x45, 0x53, 0x10, 0x80, 0x01, 0x12, 0x2e, 0x0a, 0x29, 0x4d, 0x41, + 0x58, 0x5f, 0x4f, 0x42, 0x4a, 0x45, 0x43, 0x54, 0x5f, 0x49, 0x44, 0x53, 0x5f, 0x50, 0x45, 0x52, + 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x4f, 0x42, 0x4a, 0x45, 0x43, 0x54, 0x53, 0x5f, + 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x10, 0xe8, 0x07, 0x12, 0x1e, 0x0a, 0x1a, 0x53, 0x50, + 0x4c, 0x49, 0x54, 0x5f, 0x54, 0x4f, 0x4b, 0x45, 0x4e, 0x5f, 0x4d, 0x41, 0x58, 0x5f, 0x56, 0x41, + 0x4c, 0x49, 0x44, 0x5f, 0x44, 0x41, 0x59, 0x53, 0x10, 0x0e, 0x1a, 0x02, 0x10, 0x01, 0x22, 0xa6, + 0x1e, 0x0a, 0x06, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x17, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x05, 0x52, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x09, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x03, 0x52, 0x08, 0x62, 0x75, 0x63, 0x6b, + 0x65, 0x74, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x74, 0x61, 0x67, 0x18, 0x1d, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x65, 0x74, 0x61, 0x67, 0x12, 0x4d, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, + 0x65, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x33, 0xe0, 0x41, 0x05, 0xfa, 0x41, + 0x2d, 0x0a, 0x2b, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, + 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x07, + 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x2b, 0x0a, 0x0e, 0x6d, 0x65, 0x74, 0x61, 0x67, + 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x42, + 0x03, 0xe0, 0x41, 0x03, 0x52, 0x0e, 0x6d, 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x05, 0x52, 0x08, 0x6c, 0x6f, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x0a, 0x0d, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, + 0x03, 0x52, 0x0c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, + 0x23, 0x0a, 0x0d, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, + 0x6c, 0x61, 0x73, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x72, 0x70, 0x6f, 0x18, 0x1b, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x72, 0x70, 0x6f, 0x12, 0x38, 0x0a, 0x03, 0x61, 0x63, 0x6c, 0x18, 0x08, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, + 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x41, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x52, 0x03, 0x61, 0x63, 0x6c, + 0x12, 0x54, 0x0a, 0x12, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x6f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x5f, 0x61, 0x63, 0x6c, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, + 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, + 0x74, 0x72, 0x6f, 0x6c, 0x52, 0x10, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x4f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x41, 0x63, 0x6c, 0x12, 0x41, 0x0a, 0x09, 0x6c, 0x69, 0x66, 0x65, 0x63, 0x79, + 0x63, 0x6c, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x75, + 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x4c, 0x69, 0x66, 0x65, 0x63, 0x79, 0x63, 0x6c, 0x65, 0x52, 0x09, + 0x6c, 0x69, 0x66, 0x65, 0x63, 0x79, 0x63, 0x6c, 0x65, 0x12, 0x40, 0x0a, 0x0b, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x03, 0xe0, 0x41, 0x03, 0x52, + 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x32, 0x0a, 0x04, 0x63, + 0x6f, 0x72, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x75, + 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x43, 0x6f, 0x72, 0x73, 0x52, 0x04, 0x63, 0x6f, 0x72, 0x73, 0x12, + 0x40, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0d, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x42, 0x03, 0xe0, 0x41, 0x03, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, + 0x65, 0x12, 0x37, 0x0a, 0x18, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x64, 0x5f, 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x0e, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x15, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x42, 0x61, 0x73, 0x65, 0x64, 0x48, 0x6f, 0x6c, 0x64, 0x12, 0x3d, 0x0a, 0x06, 0x6c, 0x61, + 0x62, 0x65, 0x6c, 0x73, 0x18, 0x0f, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x42, + 0x75, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x3b, 0x0a, 0x07, 0x77, 0x65, 0x62, + 0x73, 0x69, 0x74, 0x65, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x42, + 0x75, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x52, 0x07, 0x77, + 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x12, 0x44, 0x0a, 0x0a, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x69, 0x6e, 0x67, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x42, + 0x75, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, + 0x52, 0x0a, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x3b, 0x0a, 0x07, + 0x6c, 0x6f, 0x67, 0x67, 0x69, 0x6e, 0x67, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, + 0x32, 0x2e, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x4c, 0x6f, 0x67, 0x67, 0x69, 0x6e, 0x67, + 0x52, 0x07, 0x6c, 0x6f, 0x67, 0x67, 0x69, 0x6e, 0x67, 0x12, 0x33, 0x0a, 0x05, 0x6f, 0x77, 0x6e, + 0x65, 0x72, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x4f, 0x77, 0x6e, + 0x65, 0x72, 0x42, 0x03, 0xe0, 0x41, 0x03, 0x52, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x12, 0x44, + 0x0a, 0x0a, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x14, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, + 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x45, 0x6e, + 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3b, 0x0a, 0x07, 0x62, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x18, + 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, + 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, + 0x2e, 0x42, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x62, 0x69, 0x6c, 0x6c, 0x69, 0x6e, + 0x67, 0x12, 0x54, 0x0a, 0x10, 0x72, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, + 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x52, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, + 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x0f, 0x72, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, + 0x6e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x42, 0x0a, 0x0a, 0x69, 0x61, 0x6d, 0x5f, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, + 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x49, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x52, 0x09, 0x69, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x23, 0x0a, 0x0d, 0x73, + 0x61, 0x74, 0x69, 0x73, 0x66, 0x69, 0x65, 0x73, 0x5f, 0x70, 0x7a, 0x73, 0x18, 0x19, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x0c, 0x73, 0x61, 0x74, 0x69, 0x73, 0x66, 0x69, 0x65, 0x73, 0x50, 0x7a, 0x73, + 0x12, 0x67, 0x0a, 0x17, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x70, 0x6c, 0x61, 0x63, 0x65, + 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x1a, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x2f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, + 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x43, 0x75, 0x73, + 0x74, 0x6f, 0x6d, 0x50, 0x6c, 0x61, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x52, 0x15, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x50, 0x6c, 0x61, 0x63, 0x65, 0x6d, + 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x41, 0x0a, 0x09, 0x61, 0x75, 0x74, + 0x6f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, + 0x2e, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x41, 0x75, 0x74, 0x6f, 0x63, 0x6c, 0x61, 0x73, + 0x73, 0x52, 0x09, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x1a, 0x30, 0x0a, 0x07, + 0x42, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x65, 0x72, 0x5f, 0x70, 0x61, 0x79, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0d, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x65, 0x72, 0x50, 0x61, 0x79, 0x73, 0x1a, 0x87, + 0x01, 0x0a, 0x04, 0x43, 0x6f, 0x72, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, + 0x6e, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x12, + 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x72, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x0e, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, + 0x12, 0x26, 0x0a, 0x0f, 0x6d, 0x61, 0x78, 0x5f, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x65, 0x63, 0x6f, + 0x6e, 0x64, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x6d, 0x61, 0x78, 0x41, 0x67, + 0x65, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x1a, 0x5c, 0x0a, 0x0a, 0x45, 0x6e, 0x63, 0x72, + 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4e, 0x0a, 0x0f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, + 0x74, 0x5f, 0x6b, 0x6d, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x26, 0xfa, 0x41, 0x23, 0x0a, 0x21, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x6b, 0x6d, 0x73, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x72, + 0x79, 0x70, 0x74, 0x6f, 0x4b, 0x65, 0x79, 0x52, 0x0d, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, + 0x4b, 0x6d, 0x73, 0x4b, 0x65, 0x79, 0x1a, 0xb1, 0x02, 0x0a, 0x09, 0x49, 0x61, 0x6d, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x12, 0x7b, 0x0a, 0x1b, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x5f, + 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x5f, 0x61, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x75, + 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x49, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x55, + 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x4c, 0x65, 0x76, 0x65, + 0x6c, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x18, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, + 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x41, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x12, 0x38, 0x0a, 0x18, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x61, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x5f, 0x70, 0x72, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x16, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x41, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x50, 0x72, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x6d, 0x0a, 0x18, 0x55, + 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x4c, 0x65, 0x76, 0x65, + 0x6c, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, + 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, + 0x64, 0x12, 0x37, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x1a, 0xdb, 0x07, 0x0a, 0x09, 0x4c, + 0x69, 0x66, 0x65, 0x63, 0x79, 0x63, 0x6c, 0x65, 0x12, 0x3c, 0x0a, 0x04, 0x72, 0x75, 0x6c, 0x65, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x75, 0x63, 0x6b, 0x65, + 0x74, 0x2e, 0x4c, 0x69, 0x66, 0x65, 0x63, 0x79, 0x63, 0x6c, 0x65, 0x2e, 0x52, 0x75, 0x6c, 0x65, + 0x52, 0x04, 0x72, 0x75, 0x6c, 0x65, 0x1a, 0x8f, 0x07, 0x0a, 0x04, 0x52, 0x75, 0x6c, 0x65, 0x12, + 0x47, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x2f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, + 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x4c, 0x69, 0x66, 0x65, 0x63, + 0x79, 0x63, 0x6c, 0x65, 0x2e, 0x52, 0x75, 0x6c, 0x65, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x50, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x64, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, + 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x4c, 0x69, 0x66, 0x65, 0x63, 0x79, 0x63, 0x6c, 0x65, + 0x2e, 0x52, 0x75, 0x6c, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x09, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x41, 0x0a, 0x06, 0x41, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x74, 0x6f, 0x72, + 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0c, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x1a, 0xa8, 0x05, + 0x0a, 0x09, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x08, 0x61, + 0x67, 0x65, 0x5f, 0x64, 0x61, 0x79, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x48, 0x00, 0x52, + 0x07, 0x61, 0x67, 0x65, 0x44, 0x61, 0x79, 0x73, 0x88, 0x01, 0x01, 0x12, 0x38, 0x0a, 0x0e, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x74, 0x79, 0x70, + 0x65, 0x2e, 0x44, 0x61, 0x74, 0x65, 0x52, 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x42, + 0x65, 0x66, 0x6f, 0x72, 0x65, 0x12, 0x1c, 0x0a, 0x07, 0x69, 0x73, 0x5f, 0x6c, 0x69, 0x76, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x48, 0x01, 0x52, 0x06, 0x69, 0x73, 0x4c, 0x69, 0x76, 0x65, + 0x88, 0x01, 0x01, 0x12, 0x31, 0x0a, 0x12, 0x6e, 0x75, 0x6d, 0x5f, 0x6e, 0x65, 0x77, 0x65, 0x72, + 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x48, + 0x02, 0x52, 0x10, 0x6e, 0x75, 0x6d, 0x4e, 0x65, 0x77, 0x65, 0x72, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x88, 0x01, 0x01, 0x12, 0x32, 0x0a, 0x15, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, + 0x73, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x18, + 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x53, 0x74, + 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x12, 0x38, 0x0a, 0x16, 0x64, 0x61, + 0x79, 0x73, 0x5f, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x5f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, + 0x74, 0x69, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x48, 0x03, 0x52, 0x13, 0x64, 0x61, + 0x79, 0x73, 0x53, 0x69, 0x6e, 0x63, 0x65, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x54, 0x69, 0x6d, + 0x65, 0x88, 0x01, 0x01, 0x12, 0x3f, 0x0a, 0x12, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x74, + 0x69, 0x6d, 0x65, 0x5f, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x11, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x2e, 0x44, + 0x61, 0x74, 0x65, 0x52, 0x10, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x54, 0x69, 0x6d, 0x65, 0x42, + 0x65, 0x66, 0x6f, 0x72, 0x65, 0x12, 0x40, 0x0a, 0x1a, 0x64, 0x61, 0x79, 0x73, 0x5f, 0x73, 0x69, + 0x6e, 0x63, 0x65, 0x5f, 0x6e, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x74, + 0x69, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x48, 0x04, 0x52, 0x17, 0x64, 0x61, 0x79, + 0x73, 0x53, 0x69, 0x6e, 0x63, 0x65, 0x4e, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, + 0x54, 0x69, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x47, 0x0a, 0x16, 0x6e, 0x6f, 0x6e, 0x63, 0x75, + 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x62, 0x65, 0x66, 0x6f, 0x72, + 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x74, 0x79, 0x70, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x65, 0x52, 0x14, 0x6e, 0x6f, 0x6e, 0x63, + 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, + 0x12, 0x25, 0x0a, 0x0e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x5f, 0x70, 0x72, 0x65, 0x66, + 0x69, 0x78, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, + 0x73, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, 0x25, 0x0a, 0x0e, 0x6d, 0x61, 0x74, 0x63, 0x68, + 0x65, 0x73, 0x5f, 0x73, 0x75, 0x66, 0x66, 0x69, 0x78, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x0d, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x53, 0x75, 0x66, 0x66, 0x69, 0x78, 0x42, 0x0b, + 0x0a, 0x09, 0x5f, 0x61, 0x67, 0x65, 0x5f, 0x64, 0x61, 0x79, 0x73, 0x42, 0x0a, 0x0a, 0x08, 0x5f, + 0x69, 0x73, 0x5f, 0x6c, 0x69, 0x76, 0x65, 0x42, 0x15, 0x0a, 0x13, 0x5f, 0x6e, 0x75, 0x6d, 0x5f, + 0x6e, 0x65, 0x77, 0x65, 0x72, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x19, + 0x0a, 0x17, 0x5f, 0x64, 0x61, 0x79, 0x73, 0x5f, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x5f, 0x63, 0x75, + 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x42, 0x1d, 0x0a, 0x1b, 0x5f, 0x64, 0x61, + 0x79, 0x73, 0x5f, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x5f, 0x6e, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, + 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x1a, 0x54, 0x0a, 0x07, 0x4c, 0x6f, 0x67, 0x67, + 0x69, 0x6e, 0x67, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x6f, 0x67, 0x5f, 0x62, 0x75, 0x63, 0x6b, 0x65, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6c, 0x6f, 0x67, 0x42, 0x75, 0x63, 0x6b, + 0x65, 0x74, 0x12, 0x2a, 0x0a, 0x11, 0x6c, 0x6f, 0x67, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x6c, + 0x6f, 0x67, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x1a, 0xb6, + 0x01, 0x0a, 0x0f, 0x52, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x12, 0x41, 0x0a, 0x0e, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, + 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0d, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, + 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x73, 0x5f, 0x6c, 0x6f, 0x63, 0x6b, + 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, 0x73, 0x4c, 0x6f, 0x63, 0x6b, + 0x65, 0x64, 0x12, 0x2e, 0x0a, 0x10, 0x72, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x0f, + 0x72, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x88, + 0x01, 0x01, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x72, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x1a, 0x26, 0x0a, 0x0a, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x1a, + 0x59, 0x0a, 0x07, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x12, 0x28, 0x0a, 0x10, 0x6d, 0x61, + 0x69, 0x6e, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x75, 0x66, 0x66, 0x69, 0x78, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6d, 0x61, 0x69, 0x6e, 0x50, 0x61, 0x67, 0x65, 0x53, 0x75, + 0x66, 0x66, 0x69, 0x78, 0x12, 0x24, 0x0a, 0x0e, 0x6e, 0x6f, 0x74, 0x5f, 0x66, 0x6f, 0x75, 0x6e, + 0x64, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6e, 0x6f, + 0x74, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x50, 0x61, 0x67, 0x65, 0x1a, 0x3e, 0x0a, 0x15, 0x43, 0x75, + 0x73, 0x74, 0x6f, 0x6d, 0x50, 0x6c, 0x61, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6c, 0x6f, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x64, 0x61, 0x74, + 0x61, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x67, 0x0a, 0x09, 0x41, 0x75, + 0x74, 0x6f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, + 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, + 0x64, 0x12, 0x40, 0x0a, 0x0b, 0x74, 0x6f, 0x67, 0x67, 0x6c, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x42, 0x03, 0xe0, 0x41, 0x03, 0x52, 0x0a, 0x74, 0x6f, 0x67, 0x67, 0x6c, 0x65, 0x54, + 0x69, 0x6d, 0x65, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x3a, 0x47, + 0xea, 0x41, 0x44, 0x0a, 0x1d, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x42, 0x75, 0x63, 0x6b, + 0x65, 0x74, 0x12, 0x23, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x7b, 0x70, 0x72, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x7d, 0x2f, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x2f, 0x7b, + 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x7d, 0x22, 0x97, 0x02, 0x0a, 0x13, 0x42, 0x75, 0x63, 0x6b, + 0x65, 0x74, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x12, + 0x12, 0x0a, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, + 0x6f, 0x6c, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x22, 0x0a, 0x0a, 0x65, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x61, 0x6c, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x03, 0xe0, 0x41, 0x03, 0x52, 0x09, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x41, 0x6c, 0x74, 0x12, + 0x1b, 0x0a, 0x09, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, + 0x65, 0x74, 0x61, 0x67, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x65, 0x74, 0x61, 0x67, + 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x41, + 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x65, 0x61, 0x6d, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, + 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x54, 0x65, 0x61, 0x6d, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x65, 0x61, + 0x6d, 0x22, 0x53, 0x0a, 0x0f, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x6d, 0x65, 0x64, + 0x44, 0x61, 0x74, 0x61, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x1b, + 0x0a, 0x06, 0x63, 0x72, 0x63, 0x33, 0x32, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x07, 0x48, 0x00, + 0x52, 0x06, 0x63, 0x72, 0x63, 0x33, 0x32, 0x63, 0x88, 0x01, 0x01, 0x42, 0x09, 0x0a, 0x07, 0x5f, + 0x63, 0x72, 0x63, 0x33, 0x32, 0x63, 0x22, 0x54, 0x0a, 0x0f, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x73, 0x12, 0x1b, 0x0a, 0x06, 0x63, 0x72, 0x63, + 0x33, 0x32, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x07, 0x48, 0x00, 0x52, 0x06, 0x63, 0x72, 0x63, + 0x33, 0x32, 0x63, 0x88, 0x01, 0x01, 0x12, 0x19, 0x0a, 0x08, 0x6d, 0x64, 0x35, 0x5f, 0x68, 0x61, + 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6d, 0x64, 0x35, 0x48, 0x61, 0x73, + 0x68, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x63, 0x72, 0x63, 0x33, 0x32, 0x63, 0x22, 0xfe, 0x02, 0x0a, + 0x0f, 0x48, 0x6d, 0x61, 0x63, 0x4b, 0x65, 0x79, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x12, 0x13, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, + 0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x20, 0x0a, 0x09, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, + 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x05, 0x52, 0x08, 0x61, + 0x63, 0x63, 0x65, 0x73, 0x73, 0x49, 0x64, 0x12, 0x4d, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, + 0x63, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x33, 0xe0, 0x41, 0x05, 0xfa, 0x41, 0x2d, + 0x0a, 0x2b, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x6d, + 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, + 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x07, 0x70, + 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x37, 0x0a, 0x15, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x03, 0x52, 0x13, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, + 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x40, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, + 0x74, 0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x03, 0xe0, 0x41, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x40, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x03, 0xe0, 0x41, 0x03, 0x52, 0x0a, 0x75, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x74, 0x61, + 0x67, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x65, 0x74, 0x61, 0x67, 0x22, 0xec, 0x03, + 0x0a, 0x0c, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x17, + 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, + 0x02, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x19, 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x05, 0x74, 0x6f, 0x70, + 0x69, 0x63, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x74, 0x61, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x65, 0x74, 0x61, 0x67, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, + 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x62, 0x0a, 0x11, 0x63, 0x75, 0x73, 0x74, 0x6f, + 0x6d, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, + 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x2e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, + 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x10, 0x63, 0x75, 0x73, 0x74, 0x6f, + 0x6d, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x6f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, + 0x78, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x4e, + 0x61, 0x6d, 0x65, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, 0x2a, 0x0a, 0x0e, 0x70, 0x61, 0x79, + 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x0d, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x46, + 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x1a, 0x43, 0x0a, 0x15, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x41, + 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x3a, 0x70, 0xea, 0x41, 0x6d, 0x0a, + 0x23, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, + 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x46, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x7b, + 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x7d, 0x2f, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x73, + 0x2f, 0x7b, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x7d, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x2f, 0x7b, 0x6e, + 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x7d, 0x22, 0x71, 0x0a, 0x12, + 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x65, 0x72, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x31, 0x0a, 0x14, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x13, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x6c, 0x67, 0x6f, + 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12, 0x28, 0x0a, 0x10, 0x6b, 0x65, 0x79, 0x5f, 0x73, 0x68, 0x61, + 0x32, 0x35, 0x36, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x0e, 0x6b, 0x65, 0x79, 0x53, 0x68, 0x61, 0x32, 0x35, 0x36, 0x42, 0x79, 0x74, 0x65, 0x73, 0x22, + 0xec, 0x0b, 0x0a, 0x06, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x17, 0x0a, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x05, 0x52, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x12, 0x3d, 0x0a, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x42, 0x25, 0xe0, 0x41, 0x05, 0xfa, 0x41, 0x1f, 0x0a, 0x1d, 0x73, 0x74, 0x6f, + 0x72, 0x61, 0x67, 0x65, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x06, 0x62, 0x75, 0x63, 0x6b, + 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x74, 0x61, 0x67, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x65, 0x74, 0x61, 0x67, 0x12, 0x23, 0x0a, 0x0a, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x42, 0x03, 0xe0, 0x41, 0x05, 0x52, + 0x0a, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2b, 0x0a, 0x0e, 0x6d, + 0x65, 0x74, 0x61, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x03, 0x42, 0x03, 0xe0, 0x41, 0x03, 0x52, 0x0e, 0x6d, 0x65, 0x74, 0x61, 0x67, 0x65, + 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x74, 0x6f, 0x72, + 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0c, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x12, 0x17, 0x0a, + 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x42, 0x03, 0xe0, 0x41, 0x03, + 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x5f, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, + 0x67, 0x12, 0x2f, 0x0a, 0x13, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x64, 0x69, 0x73, + 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x44, 0x69, 0x73, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x61, 0x63, 0x68, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x61, 0x63, 0x68, 0x65, + 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x12, 0x38, 0x0a, 0x03, 0x61, 0x63, 0x6c, 0x18, 0x0a, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, + 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x41, + 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x52, 0x03, 0x61, 0x63, + 0x6c, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x6c, 0x61, 0x6e, + 0x67, 0x75, 0x61, 0x67, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x12, 0x40, 0x0a, 0x0b, + 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x03, 0xe0, + 0x41, 0x03, 0x52, 0x0a, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x21, + 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x0d, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x40, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, + 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x42, 0x03, 0xe0, 0x41, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, + 0x69, 0x6d, 0x65, 0x12, 0x2c, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, + 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x05, 0x42, 0x03, 0xe0, 0x41, + 0x03, 0x52, 0x0e, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x75, 0x6e, + 0x74, 0x12, 0x45, 0x0a, 0x09, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x73, 0x18, 0x10, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, + 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x43, + 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x73, 0x42, 0x03, 0xe0, 0x41, 0x03, 0x52, 0x09, 0x63, + 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x73, 0x12, 0x40, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x03, 0xe0, 0x41, 0x03, 0x52, 0x0a, + 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x3f, 0x0a, 0x07, 0x6b, 0x6d, + 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x42, 0x26, 0xfa, 0x41, 0x23, + 0x0a, 0x21, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x6b, 0x6d, 0x73, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, + 0x4b, 0x65, 0x79, 0x52, 0x06, 0x6b, 0x6d, 0x73, 0x4b, 0x65, 0x79, 0x12, 0x5a, 0x0a, 0x19, 0x75, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6c, + 0x61, 0x73, 0x73, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x03, 0xe0, 0x41, 0x03, 0x52, + 0x16, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x43, 0x6c, + 0x61, 0x73, 0x73, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x65, 0x6d, 0x70, 0x6f, + 0x72, 0x61, 0x72, 0x79, 0x5f, 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0d, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x72, 0x79, 0x48, 0x6f, 0x6c, 0x64, 0x12, 0x4e, + 0x0a, 0x15, 0x72, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x78, 0x70, 0x69, + 0x72, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x13, 0x72, 0x65, 0x74, 0x65, 0x6e, + 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x43, + 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x16, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x27, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, + 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x12, 0x2d, 0x0a, 0x10, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x62, 0x61, 0x73, + 0x65, 0x64, 0x5f, 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x17, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, + 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x42, 0x61, 0x73, 0x65, 0x64, 0x48, 0x6f, 0x6c, 0x64, 0x88, + 0x01, 0x01, 0x12, 0x33, 0x0a, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x18, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x18, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, + 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x42, 0x03, 0xe0, 0x41, 0x03, + 0x52, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x12, 0x56, 0x0a, 0x13, 0x63, 0x75, 0x73, 0x74, 0x6f, + 0x6d, 0x65, 0x72, 0x5f, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x19, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, + 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x65, + 0x72, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x12, 0x63, 0x75, 0x73, + 0x74, 0x6f, 0x6d, 0x65, 0x72, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x3b, 0x0a, 0x0b, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x1a, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x52, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x54, 0x69, 0x6d, 0x65, 0x1a, 0x3b, 0x0a, 0x0d, + 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x64, 0x5f, 0x68, 0x6f, 0x6c, 0x64, 0x22, 0x97, + 0x02, 0x0a, 0x13, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x43, + 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, 0x6e, 0x74, 0x69, + 0x74, 0x79, 0x12, 0x22, 0x0a, 0x0a, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x61, 0x6c, 0x74, + 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x03, 0x52, 0x09, 0x65, 0x6e, 0x74, + 0x69, 0x74, 0x79, 0x41, 0x6c, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, + 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x74, 0x69, 0x74, + 0x79, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x74, 0x61, 0x67, 0x18, 0x08, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x65, 0x74, 0x61, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x16, 0x0a, + 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, + 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x41, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x5f, 0x74, 0x65, 0x61, 0x6d, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, + 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x54, 0x65, 0x61, 0x6d, 0x52, 0x0b, 0x70, 0x72, 0x6f, + 0x6a, 0x65, 0x63, 0x74, 0x54, 0x65, 0x61, 0x6d, 0x22, 0x8e, 0x01, 0x0a, 0x13, 0x4c, 0x69, 0x73, + 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x33, 0x0a, 0x07, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, + 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x07, 0x6f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x65, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x65, + 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, + 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, + 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x48, 0x0a, 0x0b, 0x50, 0x72, 0x6f, + 0x6a, 0x65, 0x63, 0x74, 0x54, 0x65, 0x61, 0x6d, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x6a, + 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, + 0x12, 0x0a, 0x04, 0x74, 0x65, 0x61, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, + 0x65, 0x61, 0x6d, 0x22, 0x35, 0x0a, 0x0e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x5f, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x6d, + 0x61, 0x69, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x3c, 0x0a, 0x05, 0x4f, 0x77, + 0x6e, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x65, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, 0x64, 0x22, 0x5f, 0x0a, 0x0c, 0x43, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x10, + 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x65, 0x6e, 0x64, + 0x12, 0x27, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x5f, 0x6c, 0x65, 0x6e, + 0x67, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x63, 0x6f, 0x6d, 0x70, 0x6c, + 0x65, 0x74, 0x65, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x32, 0x97, 0x26, 0x0a, 0x07, 0x53, 0x74, + 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0x72, 0x0a, 0x0c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x42, + 0x75, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x26, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, + 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x22, 0x8a, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x12, 0x13, 0x0a, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x0b, 0x7b, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x3d, 0x2a, + 0x2a, 0x7d, 0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x6f, 0x0a, 0x09, 0x47, 0x65, 0x74, + 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x23, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x75, + 0x63, 0x6b, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, + 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x22, 0x22, 0x8a, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x12, 0x13, + 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x0b, 0x7b, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x3d, + 0x2a, 0x2a, 0x7d, 0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x8b, 0x01, 0x0a, 0x0c, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x26, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, + 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x22, 0x38, + 0x8a, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, + 0x12, 0x0c, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x3d, 0x2a, 0x2a, 0x7d, 0xda, 0x41, + 0x17, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x2c, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x2c, 0x62, + 0x75, 0x63, 0x6b, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x12, 0x85, 0x01, 0x0a, 0x0b, 0x4c, 0x69, 0x73, + 0x74, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x12, 0x25, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x4c, 0x69, 0x73, + 0x74, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x26, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, + 0x2e, 0x76, 0x32, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x27, 0x8a, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x12, + 0x16, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x0c, 0x7b, 0x70, 0x72, 0x6f, 0x6a, + 0x65, 0x63, 0x74, 0x3d, 0x2a, 0x2a, 0x7d, 0xda, 0x41, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, + 0x12, 0x93, 0x01, 0x0a, 0x19, 0x4c, 0x6f, 0x63, 0x6b, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x52, + 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x33, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, + 0x76, 0x32, 0x2e, 0x4c, 0x6f, 0x63, 0x6b, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x65, 0x74, + 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, + 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x22, 0x26, + 0x8a, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, 0x0a, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, + 0x12, 0x0b, 0x7b, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x3d, 0x2a, 0x2a, 0x7d, 0xda, 0x41, 0x06, + 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x12, 0xab, 0x01, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x49, 0x61, + 0x6d, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x61, 0x6d, 0x50, 0x6f, + 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x22, 0x60, 0x8a, 0xd3, 0xe4, 0x93, 0x02, 0x4f, 0x12, 0x17, 0x0a, 0x08, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x0b, 0x7b, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x3d, + 0x2a, 0x2a, 0x7d, 0x12, 0x34, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, + 0x28, 0x7b, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x73, 0x2f, 0x2a, 0x2f, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x6f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2a, 0xda, 0x41, 0x08, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x12, 0xb2, 0x01, 0x0a, 0x0c, 0x53, 0x65, 0x74, 0x49, 0x61, 0x6d, 0x50, + 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x69, + 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x49, 0x61, 0x6d, 0x50, 0x6f, 0x6c, 0x69, + 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, + 0x22, 0x67, 0x8a, 0xd3, 0xe4, 0x93, 0x02, 0x4f, 0x12, 0x17, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x12, 0x0b, 0x7b, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x3d, 0x2a, 0x2a, + 0x7d, 0x12, 0x34, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x28, 0x7b, + 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, + 0x2a, 0x2f, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x6f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2a, 0xda, 0x41, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x2c, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0xd7, 0x01, 0x0a, 0x12, 0x54, 0x65, + 0x73, 0x74, 0x49, 0x61, 0x6d, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, + 0x12, 0x28, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x76, 0x31, + 0x2e, 0x54, 0x65, 0x73, 0x74, 0x49, 0x61, 0x6d, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x49, + 0x61, 0x6d, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x6c, 0x8a, 0xd3, 0xe4, 0x93, 0x02, 0x4f, 0x12, 0x17, 0x0a, + 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x0b, 0x7b, 0x62, 0x75, 0x63, 0x6b, + 0x65, 0x74, 0x3d, 0x2a, 0x2a, 0x7d, 0x12, 0x34, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x12, 0x28, 0x7b, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x3d, 0x70, 0x72, 0x6f, 0x6a, + 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x2f, 0x2a, + 0x7d, 0x2f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2a, 0xda, 0x41, 0x14, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2c, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x12, 0x8a, 0x01, 0x0a, 0x0c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x42, 0x75, + 0x63, 0x6b, 0x65, 0x74, 0x12, 0x26, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, + 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x42, + 0x75, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, + 0x2e, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x22, 0x37, 0x8a, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x12, + 0x1a, 0x0a, 0x0b, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x0b, + 0x7b, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x3d, 0x2a, 0x2a, 0x7d, 0xda, 0x41, 0x12, 0x62, 0x75, + 0x63, 0x6b, 0x65, 0x74, 0x2c, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, + 0x12, 0x93, 0x01, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4e, 0x6f, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x37, 0x8a, + 0xd3, 0xe4, 0x93, 0x02, 0x2a, 0x12, 0x28, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x7b, + 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, + 0x2a, 0x2f, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x2a, 0x2a, 0xda, + 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x96, 0x01, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x4e, 0x6f, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x47, + 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, + 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x37, 0x8a, 0xd3, 0xe4, 0x93, 0x02, 0x2a, 0x12, 0x28, + 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x7b, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x3d, + 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x62, 0x75, 0x63, 0x6b, 0x65, + 0x74, 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x2a, 0x2a, 0xda, 0x41, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x98, 0x01, 0x0a, 0x12, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, + 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x33, 0x8a, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, 0x0a, + 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x0b, 0x7b, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, + 0x3d, 0x2a, 0x2a, 0x7d, 0xda, 0x41, 0x13, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x2c, 0x6e, 0x6f, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x96, 0x01, 0x0a, 0x11, 0x4c, + 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x12, 0x2b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, + 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, + 0x32, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x26, 0x8a, 0xd3, 0xe4, + 0x93, 0x02, 0x17, 0x12, 0x15, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x0b, 0x7b, + 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x3d, 0x2a, 0x2a, 0x7d, 0xda, 0x41, 0x06, 0x70, 0x61, 0x72, + 0x65, 0x6e, 0x74, 0x12, 0x7e, 0x0a, 0x0d, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x73, 0x65, 0x4f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x12, 0x27, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, + 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x73, 0x65, + 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, + 0x32, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x29, 0x8a, 0xd3, 0xe4, 0x93, 0x02, 0x23, + 0x12, 0x21, 0x0a, 0x12, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x0b, 0x7b, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x3d, + 0x2a, 0x2a, 0x7d, 0x12, 0x98, 0x01, 0x0a, 0x0c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x12, 0x26, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, + 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, + 0x6d, 0x70, 0x74, 0x79, 0x22, 0x48, 0x8a, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, 0x0a, 0x06, + 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x0b, 0x7b, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x3d, + 0x2a, 0x2a, 0x7d, 0xda, 0x41, 0x0d, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x2c, 0x6f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0xda, 0x41, 0x18, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x2c, 0x6f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x2c, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0xba, + 0x01, 0x0a, 0x14, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x61, 0x62, + 0x6c, 0x65, 0x57, 0x72, 0x69, 0x74, 0x65, 0x12, 0x2e, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x61, 0x6e, 0x63, + 0x65, 0x6c, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x61, 0x62, 0x6c, 0x65, 0x57, 0x72, 0x69, 0x74, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x61, 0x6e, 0x63, + 0x65, 0x6c, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x61, 0x62, 0x6c, 0x65, 0x57, 0x72, 0x69, 0x74, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x41, 0x8a, 0xd3, 0xe4, 0x93, 0x02, 0x2f, + 0x12, 0x2d, 0x0a, 0x09, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x69, 0x64, 0x12, 0x20, 0x7b, + 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, + 0x2a, 0x2f, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x2a, 0x2a, 0xda, + 0x41, 0x09, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x69, 0x64, 0x12, 0x95, 0x01, 0x0a, 0x09, + 0x47, 0x65, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x23, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, + 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, + 0x76, 0x32, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x48, 0x8a, 0xd3, 0xe4, 0x93, 0x02, + 0x17, 0x12, 0x15, 0x0a, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x0b, 0x7b, 0x62, 0x75, + 0x63, 0x6b, 0x65, 0x74, 0x3d, 0x2a, 0x2a, 0x7d, 0xda, 0x41, 0x0d, 0x62, 0x75, 0x63, 0x6b, 0x65, + 0x74, 0x2c, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0xda, 0x41, 0x18, 0x62, 0x75, 0x63, 0x6b, 0x65, + 0x74, 0x2c, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2c, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0xa5, 0x01, 0x0a, 0x0a, 0x52, 0x65, 0x61, 0x64, 0x4f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x12, 0x24, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, + 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x61, + 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x48, 0x8a, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, 0x0a, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, + 0x74, 0x12, 0x0b, 0x7b, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x3d, 0x2a, 0x2a, 0x7d, 0xda, 0x41, + 0x0d, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x2c, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0xda, 0x41, + 0x18, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x2c, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2c, 0x67, + 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x30, 0x01, 0x12, 0x8c, 0x01, 0x0a, 0x0c, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x26, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, + 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, + 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, + 0x39, 0x8a, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x12, 0x1c, 0x0a, 0x0d, 0x6f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x2e, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x0b, 0x7b, 0x62, 0x75, 0x63, 0x6b, 0x65, + 0x74, 0x3d, 0x2a, 0x2a, 0x7d, 0xda, 0x41, 0x12, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2c, 0x75, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x12, 0xc7, 0x01, 0x0a, 0x0b, 0x57, + 0x72, 0x69, 0x74, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x25, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x57, + 0x72, 0x69, 0x74, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x26, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, + 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x67, 0x8a, 0xd3, 0xe4, 0x93, 0x02, + 0x61, 0x12, 0x30, 0x0a, 0x21, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, + 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x0b, 0x7b, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x3d, + 0x2a, 0x2a, 0x7d, 0x12, 0x2d, 0x0a, 0x09, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x69, 0x64, + 0x12, 0x20, 0x7b, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, + 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x2f, 0x2a, 0x7d, 0x2f, + 0x2a, 0x2a, 0x28, 0x01, 0x12, 0x84, 0x01, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x73, 0x12, 0x25, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, + 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, + 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x26, 0x8a, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, 0x0a, 0x06, 0x70, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x0b, 0x7b, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x3d, 0x2a, + 0x2a, 0x7d, 0xda, 0x41, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x98, 0x01, 0x0a, 0x0d, + 0x52, 0x65, 0x77, 0x72, 0x69, 0x74, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x27, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, + 0x32, 0x2e, 0x52, 0x65, 0x77, 0x72, 0x69, 0x74, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x77, 0x72, 0x69, + 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3a, 0x8a, 0xd3, 0xe4, 0x93, + 0x02, 0x34, 0x12, 0x0f, 0x0a, 0x0d, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x62, 0x75, 0x63, + 0x6b, 0x65, 0x74, 0x12, 0x21, 0x0a, 0x12, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x0b, 0x7b, 0x62, 0x75, 0x63, 0x6b, + 0x65, 0x74, 0x3d, 0x2a, 0x2a, 0x7d, 0x12, 0xae, 0x01, 0x0a, 0x13, 0x53, 0x74, 0x61, 0x72, 0x74, + 0x52, 0x65, 0x73, 0x75, 0x6d, 0x61, 0x62, 0x6c, 0x65, 0x57, 0x72, 0x69, 0x74, 0x65, 0x12, 0x2d, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, + 0x76, 0x32, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x61, 0x62, 0x6c, + 0x65, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, + 0x32, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x61, 0x62, 0x6c, 0x65, + 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x38, 0x8a, + 0xd3, 0xe4, 0x93, 0x02, 0x32, 0x12, 0x30, 0x0a, 0x21, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x6f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x2e, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x0b, 0x7b, 0x62, 0x75, 0x63, + 0x6b, 0x65, 0x74, 0x3d, 0x2a, 0x2a, 0x7d, 0x12, 0xae, 0x01, 0x0a, 0x10, 0x51, 0x75, 0x65, 0x72, + 0x79, 0x57, 0x72, 0x69, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x2a, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, + 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x57, 0x72, 0x69, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x51, 0x75, 0x65, + 0x72, 0x79, 0x57, 0x72, 0x69, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x41, 0x8a, 0xd3, 0xe4, 0x93, 0x02, 0x2f, 0x12, 0x2d, 0x0a, + 0x09, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x69, 0x64, 0x12, 0x20, 0x7b, 0x62, 0x75, 0x63, + 0x6b, 0x65, 0x74, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x2f, 0x62, + 0x75, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x2a, 0x2a, 0xda, 0x41, 0x09, 0x75, + 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x69, 0x64, 0x12, 0x80, 0x01, 0x0a, 0x11, 0x47, 0x65, 0x74, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x2b, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, + 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x1b, + 0x8a, 0xd3, 0xe4, 0x93, 0x02, 0x0b, 0x12, 0x09, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, + 0x74, 0xda, 0x41, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x95, 0x01, 0x0a, 0x0d, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x48, 0x6d, 0x61, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x27, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, + 0x32, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x48, 0x6d, 0x61, 0x63, 0x4b, 0x65, 0x79, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x48, 0x6d, 0x61, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x31, 0x8a, 0xd3, 0xe4, 0x93, 0x02, 0x0b, 0x12, 0x09, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, + 0x65, 0x63, 0x74, 0xda, 0x41, 0x1d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x2c, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x65, 0x6d, + 0x61, 0x69, 0x6c, 0x12, 0x77, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x6d, 0x61, + 0x63, 0x4b, 0x65, 0x79, 0x12, 0x27, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, + 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x48, + 0x6d, 0x61, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x25, 0x8a, 0xd3, 0xe4, 0x93, 0x02, 0x0b, 0x12, 0x09, 0x0a, + 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0xda, 0x41, 0x11, 0x61, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x5f, 0x69, 0x64, 0x2c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x7d, 0x0a, 0x0a, + 0x47, 0x65, 0x74, 0x48, 0x6d, 0x61, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x47, + 0x65, 0x74, 0x48, 0x6d, 0x61, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, + 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x48, 0x6d, 0x61, 0x63, 0x4b, 0x65, 0x79, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x22, 0x25, 0x8a, 0xd3, 0xe4, 0x93, 0x02, 0x0b, 0x12, 0x09, 0x0a, 0x07, + 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0xda, 0x41, 0x11, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x5f, 0x69, 0x64, 0x2c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x7c, 0x0a, 0x0c, 0x4c, + 0x69, 0x73, 0x74, 0x48, 0x6d, 0x61, 0x63, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x26, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, + 0x4c, 0x69, 0x73, 0x74, 0x48, 0x6d, 0x61, 0x63, 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, + 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x6d, 0x61, 0x63, + 0x4b, 0x65, 0x79, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x8a, 0xd3, + 0xe4, 0x93, 0x02, 0x0b, 0x12, 0x09, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0xda, + 0x41, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x9d, 0x01, 0x0a, 0x0d, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x48, 0x6d, 0x61, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x27, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x6d, 0x61, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x73, 0x74, + 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x2e, 0x48, 0x6d, 0x61, 0x63, 0x4b, 0x65, 0x79, + 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x3f, 0x8a, 0xd3, 0xe4, 0x93, 0x02, 0x22, + 0x12, 0x20, 0x0a, 0x10, 0x68, 0x6d, 0x61, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x2e, 0x70, 0x72, 0x6f, + 0x6a, 0x65, 0x63, 0x74, 0x12, 0x0c, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x3d, 0x2a, + 0x2a, 0x7d, 0xda, 0x41, 0x14, 0x68, 0x6d, 0x61, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x2c, 0x75, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x1a, 0xa7, 0x02, 0xca, 0x41, 0x16, 0x73, + 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, + 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0xd2, 0x41, 0x8a, 0x02, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, + 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2d, 0x70, + 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x2c, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, + 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2d, 0x70, 0x6c, + 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x2e, 0x72, 0x65, 0x61, 0x64, 0x2d, 0x6f, 0x6e, 0x6c, 0x79, + 0x2c, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x75, 0x74, 0x68, + 0x2f, 0x64, 0x65, 0x76, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x6c, + 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2c, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, + 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2f, 0x64, 0x65, 0x76, 0x73, 0x74, 0x6f, 0x72, + 0x61, 0x67, 0x65, 0x2e, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x2c, 0x68, 0x74, + 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2f, 0x64, 0x65, + 0x76, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x77, 0x72, + 0x69, 0x74, 0x65, 0x42, 0xdc, 0x01, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x32, 0x42, 0x0c, 0x53, + 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x38, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, + 0x2f, 0x67, 0x65, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x61, 0x70, 0x69, 0x73, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2f, 0x76, 0x32, 0x3b, + 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0xea, 0x41, 0x78, 0x0a, 0x21, 0x63, 0x6c, 0x6f, 0x75, + 0x64, 0x6b, 0x6d, 0x73, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x4b, 0x65, 0x79, 0x12, 0x53, 0x70, + 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x7d, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x7b, 0x6c, 0x6f, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x7d, 0x2f, 0x6b, 0x65, 0x79, 0x52, 0x69, 0x6e, 0x67, 0x73, 0x2f, + 0x7b, 0x6b, 0x65, 0x79, 0x5f, 0x72, 0x69, 0x6e, 0x67, 0x7d, 0x2f, 0x63, 0x72, 0x79, 0x70, 0x74, + 0x6f, 0x4b, 0x65, 0x79, 0x73, 0x2f, 0x7b, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x5f, 0x6b, 0x65, + 0x79, 0x7d, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_google_storage_v2_storage_proto_rawDescOnce sync.Once + file_google_storage_v2_storage_proto_rawDescData = file_google_storage_v2_storage_proto_rawDesc +) + +func file_google_storage_v2_storage_proto_rawDescGZIP() []byte { + file_google_storage_v2_storage_proto_rawDescOnce.Do(func() { + file_google_storage_v2_storage_proto_rawDescData = protoimpl.X.CompressGZIP(file_google_storage_v2_storage_proto_rawDescData) + }) + return file_google_storage_v2_storage_proto_rawDescData +} + +var file_google_storage_v2_storage_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_google_storage_v2_storage_proto_msgTypes = make([]protoimpl.MessageInfo, 74) +var file_google_storage_v2_storage_proto_goTypes = []interface{}{ + (ServiceConstants_Values)(0), // 0: google.storage.v2.ServiceConstants.Values + (*DeleteBucketRequest)(nil), // 1: google.storage.v2.DeleteBucketRequest + (*GetBucketRequest)(nil), // 2: google.storage.v2.GetBucketRequest + (*CreateBucketRequest)(nil), // 3: google.storage.v2.CreateBucketRequest + (*ListBucketsRequest)(nil), // 4: google.storage.v2.ListBucketsRequest + (*ListBucketsResponse)(nil), // 5: google.storage.v2.ListBucketsResponse + (*LockBucketRetentionPolicyRequest)(nil), // 6: google.storage.v2.LockBucketRetentionPolicyRequest + (*UpdateBucketRequest)(nil), // 7: google.storage.v2.UpdateBucketRequest + (*DeleteNotificationRequest)(nil), // 8: google.storage.v2.DeleteNotificationRequest + (*GetNotificationRequest)(nil), // 9: google.storage.v2.GetNotificationRequest + (*CreateNotificationRequest)(nil), // 10: google.storage.v2.CreateNotificationRequest + (*ListNotificationsRequest)(nil), // 11: google.storage.v2.ListNotificationsRequest + (*ListNotificationsResponse)(nil), // 12: google.storage.v2.ListNotificationsResponse + (*ComposeObjectRequest)(nil), // 13: google.storage.v2.ComposeObjectRequest + (*DeleteObjectRequest)(nil), // 14: google.storage.v2.DeleteObjectRequest + (*CancelResumableWriteRequest)(nil), // 15: google.storage.v2.CancelResumableWriteRequest + (*CancelResumableWriteResponse)(nil), // 16: google.storage.v2.CancelResumableWriteResponse + (*ReadObjectRequest)(nil), // 17: google.storage.v2.ReadObjectRequest + (*GetObjectRequest)(nil), // 18: google.storage.v2.GetObjectRequest + (*ReadObjectResponse)(nil), // 19: google.storage.v2.ReadObjectResponse + (*WriteObjectSpec)(nil), // 20: google.storage.v2.WriteObjectSpec + (*WriteObjectRequest)(nil), // 21: google.storage.v2.WriteObjectRequest + (*WriteObjectResponse)(nil), // 22: google.storage.v2.WriteObjectResponse + (*ListObjectsRequest)(nil), // 23: google.storage.v2.ListObjectsRequest + (*QueryWriteStatusRequest)(nil), // 24: google.storage.v2.QueryWriteStatusRequest + (*QueryWriteStatusResponse)(nil), // 25: google.storage.v2.QueryWriteStatusResponse + (*RewriteObjectRequest)(nil), // 26: google.storage.v2.RewriteObjectRequest + (*RewriteResponse)(nil), // 27: google.storage.v2.RewriteResponse + (*StartResumableWriteRequest)(nil), // 28: google.storage.v2.StartResumableWriteRequest + (*StartResumableWriteResponse)(nil), // 29: google.storage.v2.StartResumableWriteResponse + (*UpdateObjectRequest)(nil), // 30: google.storage.v2.UpdateObjectRequest + (*GetServiceAccountRequest)(nil), // 31: google.storage.v2.GetServiceAccountRequest + (*CreateHmacKeyRequest)(nil), // 32: google.storage.v2.CreateHmacKeyRequest + (*CreateHmacKeyResponse)(nil), // 33: google.storage.v2.CreateHmacKeyResponse + (*DeleteHmacKeyRequest)(nil), // 34: google.storage.v2.DeleteHmacKeyRequest + (*GetHmacKeyRequest)(nil), // 35: google.storage.v2.GetHmacKeyRequest + (*ListHmacKeysRequest)(nil), // 36: google.storage.v2.ListHmacKeysRequest + (*ListHmacKeysResponse)(nil), // 37: google.storage.v2.ListHmacKeysResponse + (*UpdateHmacKeyRequest)(nil), // 38: google.storage.v2.UpdateHmacKeyRequest + (*CommonObjectRequestParams)(nil), // 39: google.storage.v2.CommonObjectRequestParams + (*ServiceConstants)(nil), // 40: google.storage.v2.ServiceConstants + (*Bucket)(nil), // 41: google.storage.v2.Bucket + (*BucketAccessControl)(nil), // 42: google.storage.v2.BucketAccessControl + (*ChecksummedData)(nil), // 43: google.storage.v2.ChecksummedData + (*ObjectChecksums)(nil), // 44: google.storage.v2.ObjectChecksums + (*HmacKeyMetadata)(nil), // 45: google.storage.v2.HmacKeyMetadata + (*Notification)(nil), // 46: google.storage.v2.Notification + (*CustomerEncryption)(nil), // 47: google.storage.v2.CustomerEncryption + (*Object)(nil), // 48: google.storage.v2.Object + (*ObjectAccessControl)(nil), // 49: google.storage.v2.ObjectAccessControl + (*ListObjectsResponse)(nil), // 50: google.storage.v2.ListObjectsResponse + (*ProjectTeam)(nil), // 51: google.storage.v2.ProjectTeam + (*ServiceAccount)(nil), // 52: google.storage.v2.ServiceAccount + (*Owner)(nil), // 53: google.storage.v2.Owner + (*ContentRange)(nil), // 54: google.storage.v2.ContentRange + (*ComposeObjectRequest_SourceObject)(nil), // 55: google.storage.v2.ComposeObjectRequest.SourceObject + (*ComposeObjectRequest_SourceObject_ObjectPreconditions)(nil), // 56: google.storage.v2.ComposeObjectRequest.SourceObject.ObjectPreconditions + (*Bucket_Billing)(nil), // 57: google.storage.v2.Bucket.Billing + (*Bucket_Cors)(nil), // 58: google.storage.v2.Bucket.Cors + (*Bucket_Encryption)(nil), // 59: google.storage.v2.Bucket.Encryption + (*Bucket_IamConfig)(nil), // 60: google.storage.v2.Bucket.IamConfig + (*Bucket_Lifecycle)(nil), // 61: google.storage.v2.Bucket.Lifecycle + (*Bucket_Logging)(nil), // 62: google.storage.v2.Bucket.Logging + (*Bucket_RetentionPolicy)(nil), // 63: google.storage.v2.Bucket.RetentionPolicy + (*Bucket_Versioning)(nil), // 64: google.storage.v2.Bucket.Versioning + (*Bucket_Website)(nil), // 65: google.storage.v2.Bucket.Website + (*Bucket_CustomPlacementConfig)(nil), // 66: google.storage.v2.Bucket.CustomPlacementConfig + (*Bucket_Autoclass)(nil), // 67: google.storage.v2.Bucket.Autoclass + nil, // 68: google.storage.v2.Bucket.LabelsEntry + (*Bucket_IamConfig_UniformBucketLevelAccess)(nil), // 69: google.storage.v2.Bucket.IamConfig.UniformBucketLevelAccess + (*Bucket_Lifecycle_Rule)(nil), // 70: google.storage.v2.Bucket.Lifecycle.Rule + (*Bucket_Lifecycle_Rule_Action)(nil), // 71: google.storage.v2.Bucket.Lifecycle.Rule.Action + (*Bucket_Lifecycle_Rule_Condition)(nil), // 72: google.storage.v2.Bucket.Lifecycle.Rule.Condition + nil, // 73: google.storage.v2.Notification.CustomAttributesEntry + nil, // 74: google.storage.v2.Object.MetadataEntry + (*fieldmaskpb.FieldMask)(nil), // 75: google.protobuf.FieldMask + (*timestamppb.Timestamp)(nil), // 76: google.protobuf.Timestamp + (*date.Date)(nil), // 77: google.type.Date + (*v1.GetIamPolicyRequest)(nil), // 78: google.iam.v1.GetIamPolicyRequest + (*v1.SetIamPolicyRequest)(nil), // 79: google.iam.v1.SetIamPolicyRequest + (*v1.TestIamPermissionsRequest)(nil), // 80: google.iam.v1.TestIamPermissionsRequest + (*emptypb.Empty)(nil), // 81: google.protobuf.Empty + (*v1.Policy)(nil), // 82: google.iam.v1.Policy + (*v1.TestIamPermissionsResponse)(nil), // 83: google.iam.v1.TestIamPermissionsResponse +} +var file_google_storage_v2_storage_proto_depIdxs = []int32{ + 75, // 0: google.storage.v2.GetBucketRequest.read_mask:type_name -> google.protobuf.FieldMask + 41, // 1: google.storage.v2.CreateBucketRequest.bucket:type_name -> google.storage.v2.Bucket + 75, // 2: google.storage.v2.ListBucketsRequest.read_mask:type_name -> google.protobuf.FieldMask + 41, // 3: google.storage.v2.ListBucketsResponse.buckets:type_name -> google.storage.v2.Bucket + 41, // 4: google.storage.v2.UpdateBucketRequest.bucket:type_name -> google.storage.v2.Bucket + 75, // 5: google.storage.v2.UpdateBucketRequest.update_mask:type_name -> google.protobuf.FieldMask + 46, // 6: google.storage.v2.CreateNotificationRequest.notification:type_name -> google.storage.v2.Notification + 46, // 7: google.storage.v2.ListNotificationsResponse.notifications:type_name -> google.storage.v2.Notification + 48, // 8: google.storage.v2.ComposeObjectRequest.destination:type_name -> google.storage.v2.Object + 55, // 9: google.storage.v2.ComposeObjectRequest.source_objects:type_name -> google.storage.v2.ComposeObjectRequest.SourceObject + 39, // 10: google.storage.v2.ComposeObjectRequest.common_object_request_params:type_name -> google.storage.v2.CommonObjectRequestParams + 39, // 11: google.storage.v2.DeleteObjectRequest.common_object_request_params:type_name -> google.storage.v2.CommonObjectRequestParams + 39, // 12: google.storage.v2.ReadObjectRequest.common_object_request_params:type_name -> google.storage.v2.CommonObjectRequestParams + 75, // 13: google.storage.v2.ReadObjectRequest.read_mask:type_name -> google.protobuf.FieldMask + 39, // 14: google.storage.v2.GetObjectRequest.common_object_request_params:type_name -> google.storage.v2.CommonObjectRequestParams + 75, // 15: google.storage.v2.GetObjectRequest.read_mask:type_name -> google.protobuf.FieldMask + 43, // 16: google.storage.v2.ReadObjectResponse.checksummed_data:type_name -> google.storage.v2.ChecksummedData + 44, // 17: google.storage.v2.ReadObjectResponse.object_checksums:type_name -> google.storage.v2.ObjectChecksums + 54, // 18: google.storage.v2.ReadObjectResponse.content_range:type_name -> google.storage.v2.ContentRange + 48, // 19: google.storage.v2.ReadObjectResponse.metadata:type_name -> google.storage.v2.Object + 48, // 20: google.storage.v2.WriteObjectSpec.resource:type_name -> google.storage.v2.Object + 20, // 21: google.storage.v2.WriteObjectRequest.write_object_spec:type_name -> google.storage.v2.WriteObjectSpec + 43, // 22: google.storage.v2.WriteObjectRequest.checksummed_data:type_name -> google.storage.v2.ChecksummedData + 44, // 23: google.storage.v2.WriteObjectRequest.object_checksums:type_name -> google.storage.v2.ObjectChecksums + 39, // 24: google.storage.v2.WriteObjectRequest.common_object_request_params:type_name -> google.storage.v2.CommonObjectRequestParams + 48, // 25: google.storage.v2.WriteObjectResponse.resource:type_name -> google.storage.v2.Object + 75, // 26: google.storage.v2.ListObjectsRequest.read_mask:type_name -> google.protobuf.FieldMask + 39, // 27: google.storage.v2.QueryWriteStatusRequest.common_object_request_params:type_name -> google.storage.v2.CommonObjectRequestParams + 48, // 28: google.storage.v2.QueryWriteStatusResponse.resource:type_name -> google.storage.v2.Object + 48, // 29: google.storage.v2.RewriteObjectRequest.destination:type_name -> google.storage.v2.Object + 39, // 30: google.storage.v2.RewriteObjectRequest.common_object_request_params:type_name -> google.storage.v2.CommonObjectRequestParams + 48, // 31: google.storage.v2.RewriteResponse.resource:type_name -> google.storage.v2.Object + 20, // 32: google.storage.v2.StartResumableWriteRequest.write_object_spec:type_name -> google.storage.v2.WriteObjectSpec + 39, // 33: google.storage.v2.StartResumableWriteRequest.common_object_request_params:type_name -> google.storage.v2.CommonObjectRequestParams + 48, // 34: google.storage.v2.UpdateObjectRequest.object:type_name -> google.storage.v2.Object + 75, // 35: google.storage.v2.UpdateObjectRequest.update_mask:type_name -> google.protobuf.FieldMask + 39, // 36: google.storage.v2.UpdateObjectRequest.common_object_request_params:type_name -> google.storage.v2.CommonObjectRequestParams + 45, // 37: google.storage.v2.CreateHmacKeyResponse.metadata:type_name -> google.storage.v2.HmacKeyMetadata + 45, // 38: google.storage.v2.ListHmacKeysResponse.hmac_keys:type_name -> google.storage.v2.HmacKeyMetadata + 45, // 39: google.storage.v2.UpdateHmacKeyRequest.hmac_key:type_name -> google.storage.v2.HmacKeyMetadata + 75, // 40: google.storage.v2.UpdateHmacKeyRequest.update_mask:type_name -> google.protobuf.FieldMask + 42, // 41: google.storage.v2.Bucket.acl:type_name -> google.storage.v2.BucketAccessControl + 49, // 42: google.storage.v2.Bucket.default_object_acl:type_name -> google.storage.v2.ObjectAccessControl + 61, // 43: google.storage.v2.Bucket.lifecycle:type_name -> google.storage.v2.Bucket.Lifecycle + 76, // 44: google.storage.v2.Bucket.create_time:type_name -> google.protobuf.Timestamp + 58, // 45: google.storage.v2.Bucket.cors:type_name -> google.storage.v2.Bucket.Cors + 76, // 46: google.storage.v2.Bucket.update_time:type_name -> google.protobuf.Timestamp + 68, // 47: google.storage.v2.Bucket.labels:type_name -> google.storage.v2.Bucket.LabelsEntry + 65, // 48: google.storage.v2.Bucket.website:type_name -> google.storage.v2.Bucket.Website + 64, // 49: google.storage.v2.Bucket.versioning:type_name -> google.storage.v2.Bucket.Versioning + 62, // 50: google.storage.v2.Bucket.logging:type_name -> google.storage.v2.Bucket.Logging + 53, // 51: google.storage.v2.Bucket.owner:type_name -> google.storage.v2.Owner + 59, // 52: google.storage.v2.Bucket.encryption:type_name -> google.storage.v2.Bucket.Encryption + 57, // 53: google.storage.v2.Bucket.billing:type_name -> google.storage.v2.Bucket.Billing + 63, // 54: google.storage.v2.Bucket.retention_policy:type_name -> google.storage.v2.Bucket.RetentionPolicy + 60, // 55: google.storage.v2.Bucket.iam_config:type_name -> google.storage.v2.Bucket.IamConfig + 66, // 56: google.storage.v2.Bucket.custom_placement_config:type_name -> google.storage.v2.Bucket.CustomPlacementConfig + 67, // 57: google.storage.v2.Bucket.autoclass:type_name -> google.storage.v2.Bucket.Autoclass + 51, // 58: google.storage.v2.BucketAccessControl.project_team:type_name -> google.storage.v2.ProjectTeam + 76, // 59: google.storage.v2.HmacKeyMetadata.create_time:type_name -> google.protobuf.Timestamp + 76, // 60: google.storage.v2.HmacKeyMetadata.update_time:type_name -> google.protobuf.Timestamp + 73, // 61: google.storage.v2.Notification.custom_attributes:type_name -> google.storage.v2.Notification.CustomAttributesEntry + 49, // 62: google.storage.v2.Object.acl:type_name -> google.storage.v2.ObjectAccessControl + 76, // 63: google.storage.v2.Object.delete_time:type_name -> google.protobuf.Timestamp + 76, // 64: google.storage.v2.Object.create_time:type_name -> google.protobuf.Timestamp + 44, // 65: google.storage.v2.Object.checksums:type_name -> google.storage.v2.ObjectChecksums + 76, // 66: google.storage.v2.Object.update_time:type_name -> google.protobuf.Timestamp + 76, // 67: google.storage.v2.Object.update_storage_class_time:type_name -> google.protobuf.Timestamp + 76, // 68: google.storage.v2.Object.retention_expire_time:type_name -> google.protobuf.Timestamp + 74, // 69: google.storage.v2.Object.metadata:type_name -> google.storage.v2.Object.MetadataEntry + 53, // 70: google.storage.v2.Object.owner:type_name -> google.storage.v2.Owner + 47, // 71: google.storage.v2.Object.customer_encryption:type_name -> google.storage.v2.CustomerEncryption + 76, // 72: google.storage.v2.Object.custom_time:type_name -> google.protobuf.Timestamp + 51, // 73: google.storage.v2.ObjectAccessControl.project_team:type_name -> google.storage.v2.ProjectTeam + 48, // 74: google.storage.v2.ListObjectsResponse.objects:type_name -> google.storage.v2.Object + 56, // 75: google.storage.v2.ComposeObjectRequest.SourceObject.object_preconditions:type_name -> google.storage.v2.ComposeObjectRequest.SourceObject.ObjectPreconditions + 69, // 76: google.storage.v2.Bucket.IamConfig.uniform_bucket_level_access:type_name -> google.storage.v2.Bucket.IamConfig.UniformBucketLevelAccess + 70, // 77: google.storage.v2.Bucket.Lifecycle.rule:type_name -> google.storage.v2.Bucket.Lifecycle.Rule + 76, // 78: google.storage.v2.Bucket.RetentionPolicy.effective_time:type_name -> google.protobuf.Timestamp + 76, // 79: google.storage.v2.Bucket.Autoclass.toggle_time:type_name -> google.protobuf.Timestamp + 76, // 80: google.storage.v2.Bucket.IamConfig.UniformBucketLevelAccess.lock_time:type_name -> google.protobuf.Timestamp + 71, // 81: google.storage.v2.Bucket.Lifecycle.Rule.action:type_name -> google.storage.v2.Bucket.Lifecycle.Rule.Action + 72, // 82: google.storage.v2.Bucket.Lifecycle.Rule.condition:type_name -> google.storage.v2.Bucket.Lifecycle.Rule.Condition + 77, // 83: google.storage.v2.Bucket.Lifecycle.Rule.Condition.created_before:type_name -> google.type.Date + 77, // 84: google.storage.v2.Bucket.Lifecycle.Rule.Condition.custom_time_before:type_name -> google.type.Date + 77, // 85: google.storage.v2.Bucket.Lifecycle.Rule.Condition.noncurrent_time_before:type_name -> google.type.Date + 1, // 86: google.storage.v2.Storage.DeleteBucket:input_type -> google.storage.v2.DeleteBucketRequest + 2, // 87: google.storage.v2.Storage.GetBucket:input_type -> google.storage.v2.GetBucketRequest + 3, // 88: google.storage.v2.Storage.CreateBucket:input_type -> google.storage.v2.CreateBucketRequest + 4, // 89: google.storage.v2.Storage.ListBuckets:input_type -> google.storage.v2.ListBucketsRequest + 6, // 90: google.storage.v2.Storage.LockBucketRetentionPolicy:input_type -> google.storage.v2.LockBucketRetentionPolicyRequest + 78, // 91: google.storage.v2.Storage.GetIamPolicy:input_type -> google.iam.v1.GetIamPolicyRequest + 79, // 92: google.storage.v2.Storage.SetIamPolicy:input_type -> google.iam.v1.SetIamPolicyRequest + 80, // 93: google.storage.v2.Storage.TestIamPermissions:input_type -> google.iam.v1.TestIamPermissionsRequest + 7, // 94: google.storage.v2.Storage.UpdateBucket:input_type -> google.storage.v2.UpdateBucketRequest + 8, // 95: google.storage.v2.Storage.DeleteNotification:input_type -> google.storage.v2.DeleteNotificationRequest + 9, // 96: google.storage.v2.Storage.GetNotification:input_type -> google.storage.v2.GetNotificationRequest + 10, // 97: google.storage.v2.Storage.CreateNotification:input_type -> google.storage.v2.CreateNotificationRequest + 11, // 98: google.storage.v2.Storage.ListNotifications:input_type -> google.storage.v2.ListNotificationsRequest + 13, // 99: google.storage.v2.Storage.ComposeObject:input_type -> google.storage.v2.ComposeObjectRequest + 14, // 100: google.storage.v2.Storage.DeleteObject:input_type -> google.storage.v2.DeleteObjectRequest + 15, // 101: google.storage.v2.Storage.CancelResumableWrite:input_type -> google.storage.v2.CancelResumableWriteRequest + 18, // 102: google.storage.v2.Storage.GetObject:input_type -> google.storage.v2.GetObjectRequest + 17, // 103: google.storage.v2.Storage.ReadObject:input_type -> google.storage.v2.ReadObjectRequest + 30, // 104: google.storage.v2.Storage.UpdateObject:input_type -> google.storage.v2.UpdateObjectRequest + 21, // 105: google.storage.v2.Storage.WriteObject:input_type -> google.storage.v2.WriteObjectRequest + 23, // 106: google.storage.v2.Storage.ListObjects:input_type -> google.storage.v2.ListObjectsRequest + 26, // 107: google.storage.v2.Storage.RewriteObject:input_type -> google.storage.v2.RewriteObjectRequest + 28, // 108: google.storage.v2.Storage.StartResumableWrite:input_type -> google.storage.v2.StartResumableWriteRequest + 24, // 109: google.storage.v2.Storage.QueryWriteStatus:input_type -> google.storage.v2.QueryWriteStatusRequest + 31, // 110: google.storage.v2.Storage.GetServiceAccount:input_type -> google.storage.v2.GetServiceAccountRequest + 32, // 111: google.storage.v2.Storage.CreateHmacKey:input_type -> google.storage.v2.CreateHmacKeyRequest + 34, // 112: google.storage.v2.Storage.DeleteHmacKey:input_type -> google.storage.v2.DeleteHmacKeyRequest + 35, // 113: google.storage.v2.Storage.GetHmacKey:input_type -> google.storage.v2.GetHmacKeyRequest + 36, // 114: google.storage.v2.Storage.ListHmacKeys:input_type -> google.storage.v2.ListHmacKeysRequest + 38, // 115: google.storage.v2.Storage.UpdateHmacKey:input_type -> google.storage.v2.UpdateHmacKeyRequest + 81, // 116: google.storage.v2.Storage.DeleteBucket:output_type -> google.protobuf.Empty + 41, // 117: google.storage.v2.Storage.GetBucket:output_type -> google.storage.v2.Bucket + 41, // 118: google.storage.v2.Storage.CreateBucket:output_type -> google.storage.v2.Bucket + 5, // 119: google.storage.v2.Storage.ListBuckets:output_type -> google.storage.v2.ListBucketsResponse + 41, // 120: google.storage.v2.Storage.LockBucketRetentionPolicy:output_type -> google.storage.v2.Bucket + 82, // 121: google.storage.v2.Storage.GetIamPolicy:output_type -> google.iam.v1.Policy + 82, // 122: google.storage.v2.Storage.SetIamPolicy:output_type -> google.iam.v1.Policy + 83, // 123: google.storage.v2.Storage.TestIamPermissions:output_type -> google.iam.v1.TestIamPermissionsResponse + 41, // 124: google.storage.v2.Storage.UpdateBucket:output_type -> google.storage.v2.Bucket + 81, // 125: google.storage.v2.Storage.DeleteNotification:output_type -> google.protobuf.Empty + 46, // 126: google.storage.v2.Storage.GetNotification:output_type -> google.storage.v2.Notification + 46, // 127: google.storage.v2.Storage.CreateNotification:output_type -> google.storage.v2.Notification + 12, // 128: google.storage.v2.Storage.ListNotifications:output_type -> google.storage.v2.ListNotificationsResponse + 48, // 129: google.storage.v2.Storage.ComposeObject:output_type -> google.storage.v2.Object + 81, // 130: google.storage.v2.Storage.DeleteObject:output_type -> google.protobuf.Empty + 16, // 131: google.storage.v2.Storage.CancelResumableWrite:output_type -> google.storage.v2.CancelResumableWriteResponse + 48, // 132: google.storage.v2.Storage.GetObject:output_type -> google.storage.v2.Object + 19, // 133: google.storage.v2.Storage.ReadObject:output_type -> google.storage.v2.ReadObjectResponse + 48, // 134: google.storage.v2.Storage.UpdateObject:output_type -> google.storage.v2.Object + 22, // 135: google.storage.v2.Storage.WriteObject:output_type -> google.storage.v2.WriteObjectResponse + 50, // 136: google.storage.v2.Storage.ListObjects:output_type -> google.storage.v2.ListObjectsResponse + 27, // 137: google.storage.v2.Storage.RewriteObject:output_type -> google.storage.v2.RewriteResponse + 29, // 138: google.storage.v2.Storage.StartResumableWrite:output_type -> google.storage.v2.StartResumableWriteResponse + 25, // 139: google.storage.v2.Storage.QueryWriteStatus:output_type -> google.storage.v2.QueryWriteStatusResponse + 52, // 140: google.storage.v2.Storage.GetServiceAccount:output_type -> google.storage.v2.ServiceAccount + 33, // 141: google.storage.v2.Storage.CreateHmacKey:output_type -> google.storage.v2.CreateHmacKeyResponse + 81, // 142: google.storage.v2.Storage.DeleteHmacKey:output_type -> google.protobuf.Empty + 45, // 143: google.storage.v2.Storage.GetHmacKey:output_type -> google.storage.v2.HmacKeyMetadata + 37, // 144: google.storage.v2.Storage.ListHmacKeys:output_type -> google.storage.v2.ListHmacKeysResponse + 45, // 145: google.storage.v2.Storage.UpdateHmacKey:output_type -> google.storage.v2.HmacKeyMetadata + 116, // [116:146] is the sub-list for method output_type + 86, // [86:116] is the sub-list for method input_type + 86, // [86:86] is the sub-list for extension type_name + 86, // [86:86] is the sub-list for extension extendee + 0, // [0:86] is the sub-list for field type_name +} + +func init() { file_google_storage_v2_storage_proto_init() } +func file_google_storage_v2_storage_proto_init() { + if File_google_storage_v2_storage_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_google_storage_v2_storage_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteBucketRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetBucketRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateBucketRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ListBucketsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ListBucketsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LockBucketRetentionPolicyRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateBucketRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteNotificationRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetNotificationRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateNotificationRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ListNotificationsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ListNotificationsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ComposeObjectRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteObjectRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CancelResumableWriteRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CancelResumableWriteResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ReadObjectRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetObjectRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ReadObjectResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*WriteObjectSpec); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*WriteObjectRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*WriteObjectResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ListObjectsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*QueryWriteStatusRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*QueryWriteStatusResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RewriteObjectRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RewriteResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StartResumableWriteRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StartResumableWriteResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateObjectRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetServiceAccountRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateHmacKeyRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateHmacKeyResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteHmacKeyRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetHmacKeyRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ListHmacKeysRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ListHmacKeysResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateHmacKeyRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommonObjectRequestParams); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ServiceConstants); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Bucket); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BucketAccessControl); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ChecksummedData); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ObjectChecksums); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*HmacKeyMetadata); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Notification); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CustomerEncryption); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Object); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[48].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ObjectAccessControl); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ListObjectsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[50].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ProjectTeam); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[51].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ServiceAccount); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[52].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Owner); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[53].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ContentRange); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[54].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ComposeObjectRequest_SourceObject); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[55].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ComposeObjectRequest_SourceObject_ObjectPreconditions); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[56].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Bucket_Billing); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[57].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Bucket_Cors); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[58].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Bucket_Encryption); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[59].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Bucket_IamConfig); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[60].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Bucket_Lifecycle); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[61].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Bucket_Logging); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[62].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Bucket_RetentionPolicy); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[63].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Bucket_Versioning); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[64].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Bucket_Website); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[65].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Bucket_CustomPlacementConfig); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[66].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Bucket_Autoclass); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[68].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Bucket_IamConfig_UniformBucketLevelAccess); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[69].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Bucket_Lifecycle_Rule); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[70].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Bucket_Lifecycle_Rule_Action); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_storage_v2_storage_proto_msgTypes[71].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Bucket_Lifecycle_Rule_Condition); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_google_storage_v2_storage_proto_msgTypes[0].OneofWrappers = []interface{}{} + file_google_storage_v2_storage_proto_msgTypes[1].OneofWrappers = []interface{}{} + file_google_storage_v2_storage_proto_msgTypes[3].OneofWrappers = []interface{}{} + file_google_storage_v2_storage_proto_msgTypes[6].OneofWrappers = []interface{}{} + file_google_storage_v2_storage_proto_msgTypes[12].OneofWrappers = []interface{}{} + file_google_storage_v2_storage_proto_msgTypes[13].OneofWrappers = []interface{}{} + file_google_storage_v2_storage_proto_msgTypes[16].OneofWrappers = []interface{}{} + file_google_storage_v2_storage_proto_msgTypes[17].OneofWrappers = []interface{}{} + file_google_storage_v2_storage_proto_msgTypes[19].OneofWrappers = []interface{}{} + file_google_storage_v2_storage_proto_msgTypes[20].OneofWrappers = []interface{}{ + (*WriteObjectRequest_UploadId)(nil), + (*WriteObjectRequest_WriteObjectSpec)(nil), + (*WriteObjectRequest_ChecksummedData)(nil), + } + file_google_storage_v2_storage_proto_msgTypes[21].OneofWrappers = []interface{}{ + (*WriteObjectResponse_PersistedSize)(nil), + (*WriteObjectResponse_Resource)(nil), + } + file_google_storage_v2_storage_proto_msgTypes[22].OneofWrappers = []interface{}{} + file_google_storage_v2_storage_proto_msgTypes[24].OneofWrappers = []interface{}{ + (*QueryWriteStatusResponse_PersistedSize)(nil), + (*QueryWriteStatusResponse_Resource)(nil), + } + file_google_storage_v2_storage_proto_msgTypes[25].OneofWrappers = []interface{}{} + file_google_storage_v2_storage_proto_msgTypes[29].OneofWrappers = []interface{}{} + file_google_storage_v2_storage_proto_msgTypes[42].OneofWrappers = []interface{}{} + file_google_storage_v2_storage_proto_msgTypes[43].OneofWrappers = []interface{}{} + file_google_storage_v2_storage_proto_msgTypes[47].OneofWrappers = []interface{}{} + file_google_storage_v2_storage_proto_msgTypes[55].OneofWrappers = []interface{}{} + file_google_storage_v2_storage_proto_msgTypes[62].OneofWrappers = []interface{}{} + file_google_storage_v2_storage_proto_msgTypes[71].OneofWrappers = []interface{}{} + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_google_storage_v2_storage_proto_rawDesc, + NumEnums: 1, + NumMessages: 74, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_google_storage_v2_storage_proto_goTypes, + DependencyIndexes: file_google_storage_v2_storage_proto_depIdxs, + EnumInfos: file_google_storage_v2_storage_proto_enumTypes, + MessageInfos: file_google_storage_v2_storage_proto_msgTypes, + }.Build() + File_google_storage_v2_storage_proto = out.File + file_google_storage_v2_storage_proto_rawDesc = nil + file_google_storage_v2_storage_proto_goTypes = nil + file_google_storage_v2_storage_proto_depIdxs = nil +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConnInterface + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion6 + +// StorageClient is the client API for Storage service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type StorageClient interface { + // Permanently deletes an empty bucket. + DeleteBucket(ctx context.Context, in *DeleteBucketRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) + // Returns metadata for the specified bucket. + GetBucket(ctx context.Context, in *GetBucketRequest, opts ...grpc.CallOption) (*Bucket, error) + // Creates a new bucket. + CreateBucket(ctx context.Context, in *CreateBucketRequest, opts ...grpc.CallOption) (*Bucket, error) + // Retrieves a list of buckets for a given project. + ListBuckets(ctx context.Context, in *ListBucketsRequest, opts ...grpc.CallOption) (*ListBucketsResponse, error) + // Locks retention policy on a bucket. + LockBucketRetentionPolicy(ctx context.Context, in *LockBucketRetentionPolicyRequest, opts ...grpc.CallOption) (*Bucket, error) + // Gets the IAM policy for a specified bucket or object. + GetIamPolicy(ctx context.Context, in *v1.GetIamPolicyRequest, opts ...grpc.CallOption) (*v1.Policy, error) + // Updates an IAM policy for the specified bucket or object. + SetIamPolicy(ctx context.Context, in *v1.SetIamPolicyRequest, opts ...grpc.CallOption) (*v1.Policy, error) + // Tests a set of permissions on the given bucket or object to see which, if + // any, are held by the caller. + TestIamPermissions(ctx context.Context, in *v1.TestIamPermissionsRequest, opts ...grpc.CallOption) (*v1.TestIamPermissionsResponse, error) + // Updates a bucket. Equivalent to JSON API's storage.buckets.patch method. + UpdateBucket(ctx context.Context, in *UpdateBucketRequest, opts ...grpc.CallOption) (*Bucket, error) + // Permanently deletes a notification subscription. + DeleteNotification(ctx context.Context, in *DeleteNotificationRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) + // View a notification config. + GetNotification(ctx context.Context, in *GetNotificationRequest, opts ...grpc.CallOption) (*Notification, error) + // Creates a notification subscription for a given bucket. + // These notifications, when triggered, publish messages to the specified + // Pub/Sub topics. + // See https://cloud.google.com/storage/docs/pubsub-notifications. + CreateNotification(ctx context.Context, in *CreateNotificationRequest, opts ...grpc.CallOption) (*Notification, error) + // Retrieves a list of notification subscriptions for a given bucket. + ListNotifications(ctx context.Context, in *ListNotificationsRequest, opts ...grpc.CallOption) (*ListNotificationsResponse, error) + // Concatenates a list of existing objects into a new object in the same + // bucket. + ComposeObject(ctx context.Context, in *ComposeObjectRequest, opts ...grpc.CallOption) (*Object, error) + // Deletes an object and its metadata. Deletions are permanent if versioning + // is not enabled for the bucket, or if the `generation` parameter is used. + DeleteObject(ctx context.Context, in *DeleteObjectRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) + // Cancels an in-progress resumable upload. + CancelResumableWrite(ctx context.Context, in *CancelResumableWriteRequest, opts ...grpc.CallOption) (*CancelResumableWriteResponse, error) + // Retrieves an object's metadata. + GetObject(ctx context.Context, in *GetObjectRequest, opts ...grpc.CallOption) (*Object, error) + // Reads an object's data. + ReadObject(ctx context.Context, in *ReadObjectRequest, opts ...grpc.CallOption) (Storage_ReadObjectClient, error) + // Updates an object's metadata. + // Equivalent to JSON API's storage.objects.patch. + UpdateObject(ctx context.Context, in *UpdateObjectRequest, opts ...grpc.CallOption) (*Object, error) + // Stores a new object and metadata. + // + // An object can be written either in a single message stream or in a + // resumable sequence of message streams. To write using a single stream, + // the client should include in the first message of the stream an + // `WriteObjectSpec` describing the destination bucket, object, and any + // preconditions. Additionally, the final message must set 'finish_write' to + // true, or else it is an error. + // + // For a resumable write, the client should instead call + // `StartResumableWrite()`, populating a `WriteObjectSpec` into that request. + // They should then attach the returned `upload_id` to the first message of + // each following call to `WriteObject`. If the stream is closed before + // finishing the upload (either explicitly by the client or due to a network + // error or an error response from the server), the client should do as + // follows: + // - Check the result Status of the stream, to determine if writing can be + // resumed on this stream or must be restarted from scratch (by calling + // `StartResumableWrite()`). The resumable errors are DEADLINE_EXCEEDED, + // INTERNAL, and UNAVAILABLE. For each case, the client should use binary + // exponential backoff before retrying. Additionally, writes can be + // resumed after RESOURCE_EXHAUSTED errors, but only after taking + // appropriate measures, which may include reducing aggregate send rate + // across clients and/or requesting a quota increase for your project. + // - If the call to `WriteObject` returns `ABORTED`, that indicates + // concurrent attempts to update the resumable write, caused either by + // multiple racing clients or by a single client where the previous + // request was timed out on the client side but nonetheless reached the + // server. In this case the client should take steps to prevent further + // concurrent writes (e.g., increase the timeouts, stop using more than + // one process to perform the upload, etc.), and then should follow the + // steps below for resuming the upload. + // - For resumable errors, the client should call `QueryWriteStatus()` and + // then continue writing from the returned `persisted_size`. This may be + // less than the amount of data the client previously sent. Note also that + // it is acceptable to send data starting at an offset earlier than the + // returned `persisted_size`; in this case, the service will skip data at + // offsets that were already persisted (without checking that it matches + // the previously written data), and write only the data starting from the + // persisted offset. This behavior can make client-side handling simpler + // in some cases. + // + // The service will not view the object as complete until the client has + // sent a `WriteObjectRequest` with `finish_write` set to `true`. Sending any + // requests on a stream after sending a request with `finish_write` set to + // `true` will cause an error. The client **should** check the response it + // receives to determine how much data the service was able to commit and + // whether the service views the object as complete. + // + // Attempting to resume an already finalized object will result in an OK + // status, with a WriteObjectResponse containing the finalized object's + // metadata. + WriteObject(ctx context.Context, opts ...grpc.CallOption) (Storage_WriteObjectClient, error) + // Retrieves a list of objects matching the criteria. + ListObjects(ctx context.Context, in *ListObjectsRequest, opts ...grpc.CallOption) (*ListObjectsResponse, error) + // Rewrites a source object to a destination object. Optionally overrides + // metadata. + RewriteObject(ctx context.Context, in *RewriteObjectRequest, opts ...grpc.CallOption) (*RewriteResponse, error) + // Starts a resumable write. How long the write operation remains valid, and + // what happens when the write operation becomes invalid, are + // service-dependent. + StartResumableWrite(ctx context.Context, in *StartResumableWriteRequest, opts ...grpc.CallOption) (*StartResumableWriteResponse, error) + // Determines the `persisted_size` for an object that is being written, which + // can then be used as the `write_offset` for the next `Write()` call. + // + // If the object does not exist (i.e., the object has been deleted, or the + // first `Write()` has not yet reached the service), this method returns the + // error `NOT_FOUND`. + // + // The client **may** call `QueryWriteStatus()` at any time to determine how + // much data has been processed for this object. This is useful if the + // client is buffering data and needs to know which data can be safely + // evicted. For any sequence of `QueryWriteStatus()` calls for a given + // object name, the sequence of returned `persisted_size` values will be + // non-decreasing. + QueryWriteStatus(ctx context.Context, in *QueryWriteStatusRequest, opts ...grpc.CallOption) (*QueryWriteStatusResponse, error) + // Retrieves the name of a project's Google Cloud Storage service account. + GetServiceAccount(ctx context.Context, in *GetServiceAccountRequest, opts ...grpc.CallOption) (*ServiceAccount, error) + // Creates a new HMAC key for the given service account. + CreateHmacKey(ctx context.Context, in *CreateHmacKeyRequest, opts ...grpc.CallOption) (*CreateHmacKeyResponse, error) + // Deletes a given HMAC key. Key must be in an INACTIVE state. + DeleteHmacKey(ctx context.Context, in *DeleteHmacKeyRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) + // Gets an existing HMAC key metadata for the given id. + GetHmacKey(ctx context.Context, in *GetHmacKeyRequest, opts ...grpc.CallOption) (*HmacKeyMetadata, error) + // Lists HMAC keys under a given project with the additional filters provided. + ListHmacKeys(ctx context.Context, in *ListHmacKeysRequest, opts ...grpc.CallOption) (*ListHmacKeysResponse, error) + // Updates a given HMAC key state between ACTIVE and INACTIVE. + UpdateHmacKey(ctx context.Context, in *UpdateHmacKeyRequest, opts ...grpc.CallOption) (*HmacKeyMetadata, error) +} + +type storageClient struct { + cc grpc.ClientConnInterface +} + +func NewStorageClient(cc grpc.ClientConnInterface) StorageClient { + return &storageClient{cc} +} + +func (c *storageClient) DeleteBucket(ctx context.Context, in *DeleteBucketRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + out := new(emptypb.Empty) + err := c.cc.Invoke(ctx, "/google.storage.v2.Storage/DeleteBucket", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *storageClient) GetBucket(ctx context.Context, in *GetBucketRequest, opts ...grpc.CallOption) (*Bucket, error) { + out := new(Bucket) + err := c.cc.Invoke(ctx, "/google.storage.v2.Storage/GetBucket", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *storageClient) CreateBucket(ctx context.Context, in *CreateBucketRequest, opts ...grpc.CallOption) (*Bucket, error) { + out := new(Bucket) + err := c.cc.Invoke(ctx, "/google.storage.v2.Storage/CreateBucket", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *storageClient) ListBuckets(ctx context.Context, in *ListBucketsRequest, opts ...grpc.CallOption) (*ListBucketsResponse, error) { + out := new(ListBucketsResponse) + err := c.cc.Invoke(ctx, "/google.storage.v2.Storage/ListBuckets", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *storageClient) LockBucketRetentionPolicy(ctx context.Context, in *LockBucketRetentionPolicyRequest, opts ...grpc.CallOption) (*Bucket, error) { + out := new(Bucket) + err := c.cc.Invoke(ctx, "/google.storage.v2.Storage/LockBucketRetentionPolicy", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *storageClient) GetIamPolicy(ctx context.Context, in *v1.GetIamPolicyRequest, opts ...grpc.CallOption) (*v1.Policy, error) { + out := new(v1.Policy) + err := c.cc.Invoke(ctx, "/google.storage.v2.Storage/GetIamPolicy", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *storageClient) SetIamPolicy(ctx context.Context, in *v1.SetIamPolicyRequest, opts ...grpc.CallOption) (*v1.Policy, error) { + out := new(v1.Policy) + err := c.cc.Invoke(ctx, "/google.storage.v2.Storage/SetIamPolicy", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *storageClient) TestIamPermissions(ctx context.Context, in *v1.TestIamPermissionsRequest, opts ...grpc.CallOption) (*v1.TestIamPermissionsResponse, error) { + out := new(v1.TestIamPermissionsResponse) + err := c.cc.Invoke(ctx, "/google.storage.v2.Storage/TestIamPermissions", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *storageClient) UpdateBucket(ctx context.Context, in *UpdateBucketRequest, opts ...grpc.CallOption) (*Bucket, error) { + out := new(Bucket) + err := c.cc.Invoke(ctx, "/google.storage.v2.Storage/UpdateBucket", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *storageClient) DeleteNotification(ctx context.Context, in *DeleteNotificationRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + out := new(emptypb.Empty) + err := c.cc.Invoke(ctx, "/google.storage.v2.Storage/DeleteNotification", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *storageClient) GetNotification(ctx context.Context, in *GetNotificationRequest, opts ...grpc.CallOption) (*Notification, error) { + out := new(Notification) + err := c.cc.Invoke(ctx, "/google.storage.v2.Storage/GetNotification", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *storageClient) CreateNotification(ctx context.Context, in *CreateNotificationRequest, opts ...grpc.CallOption) (*Notification, error) { + out := new(Notification) + err := c.cc.Invoke(ctx, "/google.storage.v2.Storage/CreateNotification", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *storageClient) ListNotifications(ctx context.Context, in *ListNotificationsRequest, opts ...grpc.CallOption) (*ListNotificationsResponse, error) { + out := new(ListNotificationsResponse) + err := c.cc.Invoke(ctx, "/google.storage.v2.Storage/ListNotifications", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *storageClient) ComposeObject(ctx context.Context, in *ComposeObjectRequest, opts ...grpc.CallOption) (*Object, error) { + out := new(Object) + err := c.cc.Invoke(ctx, "/google.storage.v2.Storage/ComposeObject", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *storageClient) DeleteObject(ctx context.Context, in *DeleteObjectRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + out := new(emptypb.Empty) + err := c.cc.Invoke(ctx, "/google.storage.v2.Storage/DeleteObject", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *storageClient) CancelResumableWrite(ctx context.Context, in *CancelResumableWriteRequest, opts ...grpc.CallOption) (*CancelResumableWriteResponse, error) { + out := new(CancelResumableWriteResponse) + err := c.cc.Invoke(ctx, "/google.storage.v2.Storage/CancelResumableWrite", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *storageClient) GetObject(ctx context.Context, in *GetObjectRequest, opts ...grpc.CallOption) (*Object, error) { + out := new(Object) + err := c.cc.Invoke(ctx, "/google.storage.v2.Storage/GetObject", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *storageClient) ReadObject(ctx context.Context, in *ReadObjectRequest, opts ...grpc.CallOption) (Storage_ReadObjectClient, error) { + stream, err := c.cc.NewStream(ctx, &_Storage_serviceDesc.Streams[0], "/google.storage.v2.Storage/ReadObject", opts...) + if err != nil { + return nil, err + } + x := &storageReadObjectClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type Storage_ReadObjectClient interface { + Recv() (*ReadObjectResponse, error) + grpc.ClientStream +} + +type storageReadObjectClient struct { + grpc.ClientStream +} + +func (x *storageReadObjectClient) Recv() (*ReadObjectResponse, error) { + m := new(ReadObjectResponse) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *storageClient) UpdateObject(ctx context.Context, in *UpdateObjectRequest, opts ...grpc.CallOption) (*Object, error) { + out := new(Object) + err := c.cc.Invoke(ctx, "/google.storage.v2.Storage/UpdateObject", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *storageClient) WriteObject(ctx context.Context, opts ...grpc.CallOption) (Storage_WriteObjectClient, error) { + stream, err := c.cc.NewStream(ctx, &_Storage_serviceDesc.Streams[1], "/google.storage.v2.Storage/WriteObject", opts...) + if err != nil { + return nil, err + } + x := &storageWriteObjectClient{stream} + return x, nil +} + +type Storage_WriteObjectClient interface { + Send(*WriteObjectRequest) error + CloseAndRecv() (*WriteObjectResponse, error) + grpc.ClientStream +} + +type storageWriteObjectClient struct { + grpc.ClientStream +} + +func (x *storageWriteObjectClient) Send(m *WriteObjectRequest) error { + return x.ClientStream.SendMsg(m) +} + +func (x *storageWriteObjectClient) CloseAndRecv() (*WriteObjectResponse, error) { + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + m := new(WriteObjectResponse) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *storageClient) ListObjects(ctx context.Context, in *ListObjectsRequest, opts ...grpc.CallOption) (*ListObjectsResponse, error) { + out := new(ListObjectsResponse) + err := c.cc.Invoke(ctx, "/google.storage.v2.Storage/ListObjects", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *storageClient) RewriteObject(ctx context.Context, in *RewriteObjectRequest, opts ...grpc.CallOption) (*RewriteResponse, error) { + out := new(RewriteResponse) + err := c.cc.Invoke(ctx, "/google.storage.v2.Storage/RewriteObject", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *storageClient) StartResumableWrite(ctx context.Context, in *StartResumableWriteRequest, opts ...grpc.CallOption) (*StartResumableWriteResponse, error) { + out := new(StartResumableWriteResponse) + err := c.cc.Invoke(ctx, "/google.storage.v2.Storage/StartResumableWrite", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *storageClient) QueryWriteStatus(ctx context.Context, in *QueryWriteStatusRequest, opts ...grpc.CallOption) (*QueryWriteStatusResponse, error) { + out := new(QueryWriteStatusResponse) + err := c.cc.Invoke(ctx, "/google.storage.v2.Storage/QueryWriteStatus", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *storageClient) GetServiceAccount(ctx context.Context, in *GetServiceAccountRequest, opts ...grpc.CallOption) (*ServiceAccount, error) { + out := new(ServiceAccount) + err := c.cc.Invoke(ctx, "/google.storage.v2.Storage/GetServiceAccount", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *storageClient) CreateHmacKey(ctx context.Context, in *CreateHmacKeyRequest, opts ...grpc.CallOption) (*CreateHmacKeyResponse, error) { + out := new(CreateHmacKeyResponse) + err := c.cc.Invoke(ctx, "/google.storage.v2.Storage/CreateHmacKey", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *storageClient) DeleteHmacKey(ctx context.Context, in *DeleteHmacKeyRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + out := new(emptypb.Empty) + err := c.cc.Invoke(ctx, "/google.storage.v2.Storage/DeleteHmacKey", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *storageClient) GetHmacKey(ctx context.Context, in *GetHmacKeyRequest, opts ...grpc.CallOption) (*HmacKeyMetadata, error) { + out := new(HmacKeyMetadata) + err := c.cc.Invoke(ctx, "/google.storage.v2.Storage/GetHmacKey", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *storageClient) ListHmacKeys(ctx context.Context, in *ListHmacKeysRequest, opts ...grpc.CallOption) (*ListHmacKeysResponse, error) { + out := new(ListHmacKeysResponse) + err := c.cc.Invoke(ctx, "/google.storage.v2.Storage/ListHmacKeys", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *storageClient) UpdateHmacKey(ctx context.Context, in *UpdateHmacKeyRequest, opts ...grpc.CallOption) (*HmacKeyMetadata, error) { + out := new(HmacKeyMetadata) + err := c.cc.Invoke(ctx, "/google.storage.v2.Storage/UpdateHmacKey", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// StorageServer is the server API for Storage service. +type StorageServer interface { + // Permanently deletes an empty bucket. + DeleteBucket(context.Context, *DeleteBucketRequest) (*emptypb.Empty, error) + // Returns metadata for the specified bucket. + GetBucket(context.Context, *GetBucketRequest) (*Bucket, error) + // Creates a new bucket. + CreateBucket(context.Context, *CreateBucketRequest) (*Bucket, error) + // Retrieves a list of buckets for a given project. + ListBuckets(context.Context, *ListBucketsRequest) (*ListBucketsResponse, error) + // Locks retention policy on a bucket. + LockBucketRetentionPolicy(context.Context, *LockBucketRetentionPolicyRequest) (*Bucket, error) + // Gets the IAM policy for a specified bucket or object. + GetIamPolicy(context.Context, *v1.GetIamPolicyRequest) (*v1.Policy, error) + // Updates an IAM policy for the specified bucket or object. + SetIamPolicy(context.Context, *v1.SetIamPolicyRequest) (*v1.Policy, error) + // Tests a set of permissions on the given bucket or object to see which, if + // any, are held by the caller. + TestIamPermissions(context.Context, *v1.TestIamPermissionsRequest) (*v1.TestIamPermissionsResponse, error) + // Updates a bucket. Equivalent to JSON API's storage.buckets.patch method. + UpdateBucket(context.Context, *UpdateBucketRequest) (*Bucket, error) + // Permanently deletes a notification subscription. + DeleteNotification(context.Context, *DeleteNotificationRequest) (*emptypb.Empty, error) + // View a notification config. + GetNotification(context.Context, *GetNotificationRequest) (*Notification, error) + // Creates a notification subscription for a given bucket. + // These notifications, when triggered, publish messages to the specified + // Pub/Sub topics. + // See https://cloud.google.com/storage/docs/pubsub-notifications. + CreateNotification(context.Context, *CreateNotificationRequest) (*Notification, error) + // Retrieves a list of notification subscriptions for a given bucket. + ListNotifications(context.Context, *ListNotificationsRequest) (*ListNotificationsResponse, error) + // Concatenates a list of existing objects into a new object in the same + // bucket. + ComposeObject(context.Context, *ComposeObjectRequest) (*Object, error) + // Deletes an object and its metadata. Deletions are permanent if versioning + // is not enabled for the bucket, or if the `generation` parameter is used. + DeleteObject(context.Context, *DeleteObjectRequest) (*emptypb.Empty, error) + // Cancels an in-progress resumable upload. + CancelResumableWrite(context.Context, *CancelResumableWriteRequest) (*CancelResumableWriteResponse, error) + // Retrieves an object's metadata. + GetObject(context.Context, *GetObjectRequest) (*Object, error) + // Reads an object's data. + ReadObject(*ReadObjectRequest, Storage_ReadObjectServer) error + // Updates an object's metadata. + // Equivalent to JSON API's storage.objects.patch. + UpdateObject(context.Context, *UpdateObjectRequest) (*Object, error) + // Stores a new object and metadata. + // + // An object can be written either in a single message stream or in a + // resumable sequence of message streams. To write using a single stream, + // the client should include in the first message of the stream an + // `WriteObjectSpec` describing the destination bucket, object, and any + // preconditions. Additionally, the final message must set 'finish_write' to + // true, or else it is an error. + // + // For a resumable write, the client should instead call + // `StartResumableWrite()`, populating a `WriteObjectSpec` into that request. + // They should then attach the returned `upload_id` to the first message of + // each following call to `WriteObject`. If the stream is closed before + // finishing the upload (either explicitly by the client or due to a network + // error or an error response from the server), the client should do as + // follows: + // - Check the result Status of the stream, to determine if writing can be + // resumed on this stream or must be restarted from scratch (by calling + // `StartResumableWrite()`). The resumable errors are DEADLINE_EXCEEDED, + // INTERNAL, and UNAVAILABLE. For each case, the client should use binary + // exponential backoff before retrying. Additionally, writes can be + // resumed after RESOURCE_EXHAUSTED errors, but only after taking + // appropriate measures, which may include reducing aggregate send rate + // across clients and/or requesting a quota increase for your project. + // - If the call to `WriteObject` returns `ABORTED`, that indicates + // concurrent attempts to update the resumable write, caused either by + // multiple racing clients or by a single client where the previous + // request was timed out on the client side but nonetheless reached the + // server. In this case the client should take steps to prevent further + // concurrent writes (e.g., increase the timeouts, stop using more than + // one process to perform the upload, etc.), and then should follow the + // steps below for resuming the upload. + // - For resumable errors, the client should call `QueryWriteStatus()` and + // then continue writing from the returned `persisted_size`. This may be + // less than the amount of data the client previously sent. Note also that + // it is acceptable to send data starting at an offset earlier than the + // returned `persisted_size`; in this case, the service will skip data at + // offsets that were already persisted (without checking that it matches + // the previously written data), and write only the data starting from the + // persisted offset. This behavior can make client-side handling simpler + // in some cases. + // + // The service will not view the object as complete until the client has + // sent a `WriteObjectRequest` with `finish_write` set to `true`. Sending any + // requests on a stream after sending a request with `finish_write` set to + // `true` will cause an error. The client **should** check the response it + // receives to determine how much data the service was able to commit and + // whether the service views the object as complete. + // + // Attempting to resume an already finalized object will result in an OK + // status, with a WriteObjectResponse containing the finalized object's + // metadata. + WriteObject(Storage_WriteObjectServer) error + // Retrieves a list of objects matching the criteria. + ListObjects(context.Context, *ListObjectsRequest) (*ListObjectsResponse, error) + // Rewrites a source object to a destination object. Optionally overrides + // metadata. + RewriteObject(context.Context, *RewriteObjectRequest) (*RewriteResponse, error) + // Starts a resumable write. How long the write operation remains valid, and + // what happens when the write operation becomes invalid, are + // service-dependent. + StartResumableWrite(context.Context, *StartResumableWriteRequest) (*StartResumableWriteResponse, error) + // Determines the `persisted_size` for an object that is being written, which + // can then be used as the `write_offset` for the next `Write()` call. + // + // If the object does not exist (i.e., the object has been deleted, or the + // first `Write()` has not yet reached the service), this method returns the + // error `NOT_FOUND`. + // + // The client **may** call `QueryWriteStatus()` at any time to determine how + // much data has been processed for this object. This is useful if the + // client is buffering data and needs to know which data can be safely + // evicted. For any sequence of `QueryWriteStatus()` calls for a given + // object name, the sequence of returned `persisted_size` values will be + // non-decreasing. + QueryWriteStatus(context.Context, *QueryWriteStatusRequest) (*QueryWriteStatusResponse, error) + // Retrieves the name of a project's Google Cloud Storage service account. + GetServiceAccount(context.Context, *GetServiceAccountRequest) (*ServiceAccount, error) + // Creates a new HMAC key for the given service account. + CreateHmacKey(context.Context, *CreateHmacKeyRequest) (*CreateHmacKeyResponse, error) + // Deletes a given HMAC key. Key must be in an INACTIVE state. + DeleteHmacKey(context.Context, *DeleteHmacKeyRequest) (*emptypb.Empty, error) + // Gets an existing HMAC key metadata for the given id. + GetHmacKey(context.Context, *GetHmacKeyRequest) (*HmacKeyMetadata, error) + // Lists HMAC keys under a given project with the additional filters provided. + ListHmacKeys(context.Context, *ListHmacKeysRequest) (*ListHmacKeysResponse, error) + // Updates a given HMAC key state between ACTIVE and INACTIVE. + UpdateHmacKey(context.Context, *UpdateHmacKeyRequest) (*HmacKeyMetadata, error) +} + +// UnimplementedStorageServer can be embedded to have forward compatible implementations. +type UnimplementedStorageServer struct { +} + +func (*UnimplementedStorageServer) DeleteBucket(context.Context, *DeleteBucketRequest) (*emptypb.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteBucket not implemented") +} +func (*UnimplementedStorageServer) GetBucket(context.Context, *GetBucketRequest) (*Bucket, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetBucket not implemented") +} +func (*UnimplementedStorageServer) CreateBucket(context.Context, *CreateBucketRequest) (*Bucket, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateBucket not implemented") +} +func (*UnimplementedStorageServer) ListBuckets(context.Context, *ListBucketsRequest) (*ListBucketsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListBuckets not implemented") +} +func (*UnimplementedStorageServer) LockBucketRetentionPolicy(context.Context, *LockBucketRetentionPolicyRequest) (*Bucket, error) { + return nil, status.Errorf(codes.Unimplemented, "method LockBucketRetentionPolicy not implemented") +} +func (*UnimplementedStorageServer) GetIamPolicy(context.Context, *v1.GetIamPolicyRequest) (*v1.Policy, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetIamPolicy not implemented") +} +func (*UnimplementedStorageServer) SetIamPolicy(context.Context, *v1.SetIamPolicyRequest) (*v1.Policy, error) { + return nil, status.Errorf(codes.Unimplemented, "method SetIamPolicy not implemented") +} +func (*UnimplementedStorageServer) TestIamPermissions(context.Context, *v1.TestIamPermissionsRequest) (*v1.TestIamPermissionsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method TestIamPermissions not implemented") +} +func (*UnimplementedStorageServer) UpdateBucket(context.Context, *UpdateBucketRequest) (*Bucket, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateBucket not implemented") +} +func (*UnimplementedStorageServer) DeleteNotification(context.Context, *DeleteNotificationRequest) (*emptypb.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteNotification not implemented") +} +func (*UnimplementedStorageServer) GetNotification(context.Context, *GetNotificationRequest) (*Notification, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetNotification not implemented") +} +func (*UnimplementedStorageServer) CreateNotification(context.Context, *CreateNotificationRequest) (*Notification, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateNotification not implemented") +} +func (*UnimplementedStorageServer) ListNotifications(context.Context, *ListNotificationsRequest) (*ListNotificationsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListNotifications not implemented") +} +func (*UnimplementedStorageServer) ComposeObject(context.Context, *ComposeObjectRequest) (*Object, error) { + return nil, status.Errorf(codes.Unimplemented, "method ComposeObject not implemented") +} +func (*UnimplementedStorageServer) DeleteObject(context.Context, *DeleteObjectRequest) (*emptypb.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteObject not implemented") +} +func (*UnimplementedStorageServer) CancelResumableWrite(context.Context, *CancelResumableWriteRequest) (*CancelResumableWriteResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CancelResumableWrite not implemented") +} +func (*UnimplementedStorageServer) GetObject(context.Context, *GetObjectRequest) (*Object, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetObject not implemented") +} +func (*UnimplementedStorageServer) ReadObject(*ReadObjectRequest, Storage_ReadObjectServer) error { + return status.Errorf(codes.Unimplemented, "method ReadObject not implemented") +} +func (*UnimplementedStorageServer) UpdateObject(context.Context, *UpdateObjectRequest) (*Object, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateObject not implemented") +} +func (*UnimplementedStorageServer) WriteObject(Storage_WriteObjectServer) error { + return status.Errorf(codes.Unimplemented, "method WriteObject not implemented") +} +func (*UnimplementedStorageServer) ListObjects(context.Context, *ListObjectsRequest) (*ListObjectsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListObjects not implemented") +} +func (*UnimplementedStorageServer) RewriteObject(context.Context, *RewriteObjectRequest) (*RewriteResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RewriteObject not implemented") +} +func (*UnimplementedStorageServer) StartResumableWrite(context.Context, *StartResumableWriteRequest) (*StartResumableWriteResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method StartResumableWrite not implemented") +} +func (*UnimplementedStorageServer) QueryWriteStatus(context.Context, *QueryWriteStatusRequest) (*QueryWriteStatusResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method QueryWriteStatus not implemented") +} +func (*UnimplementedStorageServer) GetServiceAccount(context.Context, *GetServiceAccountRequest) (*ServiceAccount, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetServiceAccount not implemented") +} +func (*UnimplementedStorageServer) CreateHmacKey(context.Context, *CreateHmacKeyRequest) (*CreateHmacKeyResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateHmacKey not implemented") +} +func (*UnimplementedStorageServer) DeleteHmacKey(context.Context, *DeleteHmacKeyRequest) (*emptypb.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteHmacKey not implemented") +} +func (*UnimplementedStorageServer) GetHmacKey(context.Context, *GetHmacKeyRequest) (*HmacKeyMetadata, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetHmacKey not implemented") +} +func (*UnimplementedStorageServer) ListHmacKeys(context.Context, *ListHmacKeysRequest) (*ListHmacKeysResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListHmacKeys not implemented") +} +func (*UnimplementedStorageServer) UpdateHmacKey(context.Context, *UpdateHmacKeyRequest) (*HmacKeyMetadata, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateHmacKey not implemented") +} + +func RegisterStorageServer(s *grpc.Server, srv StorageServer) { + s.RegisterService(&_Storage_serviceDesc, srv) +} + +func _Storage_DeleteBucket_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteBucketRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StorageServer).DeleteBucket(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/google.storage.v2.Storage/DeleteBucket", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StorageServer).DeleteBucket(ctx, req.(*DeleteBucketRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Storage_GetBucket_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetBucketRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StorageServer).GetBucket(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/google.storage.v2.Storage/GetBucket", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StorageServer).GetBucket(ctx, req.(*GetBucketRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Storage_CreateBucket_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateBucketRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StorageServer).CreateBucket(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/google.storage.v2.Storage/CreateBucket", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StorageServer).CreateBucket(ctx, req.(*CreateBucketRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Storage_ListBuckets_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListBucketsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StorageServer).ListBuckets(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/google.storage.v2.Storage/ListBuckets", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StorageServer).ListBuckets(ctx, req.(*ListBucketsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Storage_LockBucketRetentionPolicy_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(LockBucketRetentionPolicyRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StorageServer).LockBucketRetentionPolicy(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/google.storage.v2.Storage/LockBucketRetentionPolicy", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StorageServer).LockBucketRetentionPolicy(ctx, req.(*LockBucketRetentionPolicyRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Storage_GetIamPolicy_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(v1.GetIamPolicyRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StorageServer).GetIamPolicy(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/google.storage.v2.Storage/GetIamPolicy", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StorageServer).GetIamPolicy(ctx, req.(*v1.GetIamPolicyRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Storage_SetIamPolicy_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(v1.SetIamPolicyRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StorageServer).SetIamPolicy(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/google.storage.v2.Storage/SetIamPolicy", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StorageServer).SetIamPolicy(ctx, req.(*v1.SetIamPolicyRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Storage_TestIamPermissions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(v1.TestIamPermissionsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StorageServer).TestIamPermissions(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/google.storage.v2.Storage/TestIamPermissions", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StorageServer).TestIamPermissions(ctx, req.(*v1.TestIamPermissionsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Storage_UpdateBucket_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateBucketRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StorageServer).UpdateBucket(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/google.storage.v2.Storage/UpdateBucket", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StorageServer).UpdateBucket(ctx, req.(*UpdateBucketRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Storage_DeleteNotification_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteNotificationRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StorageServer).DeleteNotification(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/google.storage.v2.Storage/DeleteNotification", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StorageServer).DeleteNotification(ctx, req.(*DeleteNotificationRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Storage_GetNotification_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetNotificationRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StorageServer).GetNotification(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/google.storage.v2.Storage/GetNotification", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StorageServer).GetNotification(ctx, req.(*GetNotificationRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Storage_CreateNotification_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateNotificationRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StorageServer).CreateNotification(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/google.storage.v2.Storage/CreateNotification", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StorageServer).CreateNotification(ctx, req.(*CreateNotificationRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Storage_ListNotifications_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListNotificationsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StorageServer).ListNotifications(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/google.storage.v2.Storage/ListNotifications", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StorageServer).ListNotifications(ctx, req.(*ListNotificationsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Storage_ComposeObject_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ComposeObjectRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StorageServer).ComposeObject(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/google.storage.v2.Storage/ComposeObject", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StorageServer).ComposeObject(ctx, req.(*ComposeObjectRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Storage_DeleteObject_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteObjectRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StorageServer).DeleteObject(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/google.storage.v2.Storage/DeleteObject", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StorageServer).DeleteObject(ctx, req.(*DeleteObjectRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Storage_CancelResumableWrite_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CancelResumableWriteRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StorageServer).CancelResumableWrite(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/google.storage.v2.Storage/CancelResumableWrite", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StorageServer).CancelResumableWrite(ctx, req.(*CancelResumableWriteRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Storage_GetObject_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetObjectRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StorageServer).GetObject(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/google.storage.v2.Storage/GetObject", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StorageServer).GetObject(ctx, req.(*GetObjectRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Storage_ReadObject_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(ReadObjectRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(StorageServer).ReadObject(m, &storageReadObjectServer{stream}) +} + +type Storage_ReadObjectServer interface { + Send(*ReadObjectResponse) error + grpc.ServerStream +} + +type storageReadObjectServer struct { + grpc.ServerStream +} + +func (x *storageReadObjectServer) Send(m *ReadObjectResponse) error { + return x.ServerStream.SendMsg(m) +} + +func _Storage_UpdateObject_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateObjectRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StorageServer).UpdateObject(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/google.storage.v2.Storage/UpdateObject", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StorageServer).UpdateObject(ctx, req.(*UpdateObjectRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Storage_WriteObject_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(StorageServer).WriteObject(&storageWriteObjectServer{stream}) +} + +type Storage_WriteObjectServer interface { + SendAndClose(*WriteObjectResponse) error + Recv() (*WriteObjectRequest, error) + grpc.ServerStream +} + +type storageWriteObjectServer struct { + grpc.ServerStream +} + +func (x *storageWriteObjectServer) SendAndClose(m *WriteObjectResponse) error { + return x.ServerStream.SendMsg(m) +} + +func (x *storageWriteObjectServer) Recv() (*WriteObjectRequest, error) { + m := new(WriteObjectRequest) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func _Storage_ListObjects_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListObjectsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StorageServer).ListObjects(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/google.storage.v2.Storage/ListObjects", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StorageServer).ListObjects(ctx, req.(*ListObjectsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Storage_RewriteObject_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RewriteObjectRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StorageServer).RewriteObject(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/google.storage.v2.Storage/RewriteObject", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StorageServer).RewriteObject(ctx, req.(*RewriteObjectRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Storage_StartResumableWrite_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(StartResumableWriteRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StorageServer).StartResumableWrite(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/google.storage.v2.Storage/StartResumableWrite", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StorageServer).StartResumableWrite(ctx, req.(*StartResumableWriteRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Storage_QueryWriteStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryWriteStatusRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StorageServer).QueryWriteStatus(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/google.storage.v2.Storage/QueryWriteStatus", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StorageServer).QueryWriteStatus(ctx, req.(*QueryWriteStatusRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Storage_GetServiceAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetServiceAccountRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StorageServer).GetServiceAccount(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/google.storage.v2.Storage/GetServiceAccount", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StorageServer).GetServiceAccount(ctx, req.(*GetServiceAccountRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Storage_CreateHmacKey_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateHmacKeyRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StorageServer).CreateHmacKey(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/google.storage.v2.Storage/CreateHmacKey", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StorageServer).CreateHmacKey(ctx, req.(*CreateHmacKeyRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Storage_DeleteHmacKey_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteHmacKeyRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StorageServer).DeleteHmacKey(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/google.storage.v2.Storage/DeleteHmacKey", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StorageServer).DeleteHmacKey(ctx, req.(*DeleteHmacKeyRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Storage_GetHmacKey_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetHmacKeyRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StorageServer).GetHmacKey(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/google.storage.v2.Storage/GetHmacKey", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StorageServer).GetHmacKey(ctx, req.(*GetHmacKeyRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Storage_ListHmacKeys_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListHmacKeysRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StorageServer).ListHmacKeys(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/google.storage.v2.Storage/ListHmacKeys", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StorageServer).ListHmacKeys(ctx, req.(*ListHmacKeysRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Storage_UpdateHmacKey_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateHmacKeyRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StorageServer).UpdateHmacKey(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/google.storage.v2.Storage/UpdateHmacKey", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StorageServer).UpdateHmacKey(ctx, req.(*UpdateHmacKeyRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Storage_serviceDesc = grpc.ServiceDesc{ + ServiceName: "google.storage.v2.Storage", + HandlerType: (*StorageServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "DeleteBucket", + Handler: _Storage_DeleteBucket_Handler, + }, + { + MethodName: "GetBucket", + Handler: _Storage_GetBucket_Handler, + }, + { + MethodName: "CreateBucket", + Handler: _Storage_CreateBucket_Handler, + }, + { + MethodName: "ListBuckets", + Handler: _Storage_ListBuckets_Handler, + }, + { + MethodName: "LockBucketRetentionPolicy", + Handler: _Storage_LockBucketRetentionPolicy_Handler, + }, + { + MethodName: "GetIamPolicy", + Handler: _Storage_GetIamPolicy_Handler, + }, + { + MethodName: "SetIamPolicy", + Handler: _Storage_SetIamPolicy_Handler, + }, + { + MethodName: "TestIamPermissions", + Handler: _Storage_TestIamPermissions_Handler, + }, + { + MethodName: "UpdateBucket", + Handler: _Storage_UpdateBucket_Handler, + }, + { + MethodName: "DeleteNotification", + Handler: _Storage_DeleteNotification_Handler, + }, + { + MethodName: "GetNotification", + Handler: _Storage_GetNotification_Handler, + }, + { + MethodName: "CreateNotification", + Handler: _Storage_CreateNotification_Handler, + }, + { + MethodName: "ListNotifications", + Handler: _Storage_ListNotifications_Handler, + }, + { + MethodName: "ComposeObject", + Handler: _Storage_ComposeObject_Handler, + }, + { + MethodName: "DeleteObject", + Handler: _Storage_DeleteObject_Handler, + }, + { + MethodName: "CancelResumableWrite", + Handler: _Storage_CancelResumableWrite_Handler, + }, + { + MethodName: "GetObject", + Handler: _Storage_GetObject_Handler, + }, + { + MethodName: "UpdateObject", + Handler: _Storage_UpdateObject_Handler, + }, + { + MethodName: "ListObjects", + Handler: _Storage_ListObjects_Handler, + }, + { + MethodName: "RewriteObject", + Handler: _Storage_RewriteObject_Handler, + }, + { + MethodName: "StartResumableWrite", + Handler: _Storage_StartResumableWrite_Handler, + }, + { + MethodName: "QueryWriteStatus", + Handler: _Storage_QueryWriteStatus_Handler, + }, + { + MethodName: "GetServiceAccount", + Handler: _Storage_GetServiceAccount_Handler, + }, + { + MethodName: "CreateHmacKey", + Handler: _Storage_CreateHmacKey_Handler, + }, + { + MethodName: "DeleteHmacKey", + Handler: _Storage_DeleteHmacKey_Handler, + }, + { + MethodName: "GetHmacKey", + Handler: _Storage_GetHmacKey_Handler, + }, + { + MethodName: "ListHmacKeys", + Handler: _Storage_ListHmacKeys_Handler, + }, + { + MethodName: "UpdateHmacKey", + Handler: _Storage_UpdateHmacKey_Handler, + }, + }, + Streams: []grpc.StreamDesc{ + { + StreamName: "ReadObject", + Handler: _Storage_ReadObject_Handler, + ServerStreams: true, + }, + { + StreamName: "WriteObject", + Handler: _Storage_WriteObject_Handler, + ClientStreams: true, + }, + }, + Metadata: "google/storage/v2/storage.proto", +} diff --git a/vendor/cloud.google.com/go/storage/internal/apiv2/version.go b/vendor/cloud.google.com/go/storage/internal/apiv2/version.go new file mode 100644 index 00000000000..fd9c94596c8 --- /dev/null +++ b/vendor/cloud.google.com/go/storage/internal/apiv2/version.go @@ -0,0 +1,23 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by gapicgen. DO NOT EDIT. + +package storage + +import "cloud.google.com/go/storage/internal" + +func init() { + versionClient = internal.Version +} diff --git a/vendor/cloud.google.com/go/storage/internal/version.go b/vendor/cloud.google.com/go/storage/internal/version.go new file mode 100644 index 00000000000..008568b4058 --- /dev/null +++ b/vendor/cloud.google.com/go/storage/internal/version.go @@ -0,0 +1,18 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package internal + +// Version is the current tagged release of the library. +const Version = "1.28.1" diff --git a/vendor/cloud.google.com/go/storage/invoke.go b/vendor/cloud.google.com/go/storage/invoke.go index e755f197de8..810d64285d0 100644 --- a/vendor/cloud.google.com/go/storage/invoke.go +++ b/vendor/cloud.google.com/go/storage/invoke.go @@ -16,22 +16,131 @@ package storage import ( "context" + "errors" + "fmt" + "io" + "net" + "net/http" + "net/url" + "strings" "cloud.google.com/go/internal" + "cloud.google.com/go/internal/version" + sinternal "cloud.google.com/go/storage/internal" + "github.com/google/uuid" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) -// runWithRetry calls the function until it returns nil or a non-retryable error, or -// the context is done. -func runWithRetry(ctx context.Context, call func() error) error { - return internal.Retry(ctx, gax.Backoff{}, func() (stop bool, err error) { +var defaultRetry *retryConfig = &retryConfig{} +var xGoogDefaultHeader = fmt.Sprintf("gl-go/%s gccl/%s", version.Go(), sinternal.Version) + +// run determines whether a retry is necessary based on the config and +// idempotency information. It then calls the function with or without retries +// as appropriate, using the configured settings. +func run(ctx context.Context, call func() error, retry *retryConfig, isIdempotent bool, setHeader func(string, int)) error { + attempts := 1 + invocationID := uuid.New().String() + + if retry == nil { + retry = defaultRetry + } + if (retry.policy == RetryIdempotent && !isIdempotent) || retry.policy == RetryNever { + setHeader(invocationID, attempts) + return call() + } + bo := gax.Backoff{} + if retry.backoff != nil { + bo.Multiplier = retry.backoff.Multiplier + bo.Initial = retry.backoff.Initial + bo.Max = retry.backoff.Max + } + var errorFunc func(err error) bool = ShouldRetry + if retry.shouldRetry != nil { + errorFunc = retry.shouldRetry + } + + return internal.Retry(ctx, bo, func() (stop bool, err error) { + setHeader(invocationID, attempts) err = call() - if err == nil { - return true, nil + attempts++ + return !errorFunc(err), err + }) +} + +func setRetryHeaderHTTP(req interface{ Header() http.Header }) func(string, int) { + return func(invocationID string, attempts int) { + if req == nil { + return } - if shouldRetry(err) { - return false, nil + header := req.Header() + invocationHeader := fmt.Sprintf("gccl-invocation-id/%v gccl-attempt-count/%v", invocationID, attempts) + xGoogHeader := strings.Join([]string{invocationHeader, xGoogDefaultHeader}, " ") + header.Set("x-goog-api-client", xGoogHeader) + } +} + +// TODO: Implement method setting header via context for gRPC +func setRetryHeaderGRPC(_ context.Context) func(string, int) { + return func(_ string, _ int) { + return + } +} + +// ShouldRetry returns true if an error is retryable, based on best practice +// guidance from GCS. See +// https://cloud.google.com/storage/docs/retry-strategy#go for more information +// on what errors are considered retryable. +// +// If you would like to customize retryable errors, use the WithErrorFunc to +// supply a RetryOption to your library calls. For example, to retry additional +// errors, you can write a custom func that wraps ShouldRetry and also specifies +// additional errors that should return true. +func ShouldRetry(err error) bool { + if err == nil { + return false + } + if errors.Is(err, io.ErrUnexpectedEOF) { + return true + } + + switch e := err.(type) { + case *net.OpError: + if strings.Contains(e.Error(), "use of closed network connection") { + // TODO: check against net.ErrClosed (go 1.16+) instead of string + return true } - return true, err - }) + case *googleapi.Error: + // Retry on 408, 429, and 5xx, according to + // https://cloud.google.com/storage/docs/exponential-backoff. + return e.Code == 408 || e.Code == 429 || (e.Code >= 500 && e.Code < 600) + case *url.Error: + // Retry socket-level errors ECONNREFUSED and ECONNRESET (from syscall). + // Unfortunately the error type is unexported, so we resort to string + // matching. + retriable := []string{"connection refused", "connection reset"} + for _, s := range retriable { + if strings.Contains(e.Error(), s) { + return true + } + } + case interface{ Temporary() bool }: + if e.Temporary() { + return true + } + } + // HTTP 429, 502, 503, and 504 all map to gRPC UNAVAILABLE per + // https://grpc.github.io/grpc/core/md_doc_http-grpc-status-mapping.html. + // + // This is only necessary for the experimental gRPC-based media operations. + if st, ok := status.FromError(err); ok && st.Code() == codes.Unavailable { + return true + } + // Unwrap is only supported in go1.13.x+ + if e, ok := err.(interface{ Unwrap() error }); ok { + return ShouldRetry(e.Unwrap()) + } + return false } diff --git a/vendor/cloud.google.com/go/storage/not_go110.go b/vendor/cloud.google.com/go/storage/not_go110.go deleted file mode 100644 index 66fa45bea2f..00000000000 --- a/vendor/cloud.google.com/go/storage/not_go110.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2017 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// +build !go1.10 - -package storage - -import ( - "net/url" - "strings" - - "google.golang.org/api/googleapi" -) - -func shouldRetry(err error) bool { - switch e := err.(type) { - case *googleapi.Error: - // Retry on 429 and 5xx, according to - // https://cloud.google.com/storage/docs/exponential-backoff. - return e.Code == 429 || (e.Code >= 500 && e.Code < 600) - case *url.Error: - // Retry on REFUSED_STREAM. - // Unfortunately the error type is unexported, so we resort to string - // matching. - return strings.Contains(e.Error(), "REFUSED_STREAM") - case interface{ Temporary() bool }: - return e.Temporary() - default: - return false - } -} diff --git a/vendor/cloud.google.com/go/storage/notifications.go b/vendor/cloud.google.com/go/storage/notifications.go index 84619b6d58c..614feb7b6da 100644 --- a/vendor/cloud.google.com/go/storage/notifications.go +++ b/vendor/cloud.google.com/go/storage/notifications.go @@ -21,6 +21,7 @@ import ( "regexp" "cloud.google.com/go/internal/trace" + storagepb "cloud.google.com/go/storage/internal/apiv2/stubs" raw "google.golang.org/api/storage/v1" ) @@ -91,6 +92,30 @@ func toNotification(rn *raw.Notification) *Notification { return n } +func toNotificationFromProto(pbn *storagepb.Notification) *Notification { + n := &Notification{ + ID: pbn.GetName(), + EventTypes: pbn.GetEventTypes(), + ObjectNamePrefix: pbn.GetObjectNamePrefix(), + CustomAttributes: pbn.GetCustomAttributes(), + PayloadFormat: pbn.GetPayloadFormat(), + } + n.TopicProjectID, n.TopicID = parseNotificationTopic(pbn.Topic) + return n +} + +func toProtoNotification(n *Notification) *storagepb.Notification { + return &storagepb.Notification{ + Name: n.ID, + Topic: fmt.Sprintf("//pubsub.googleapis.com/projects/%s/topics/%s", + n.TopicProjectID, n.TopicID), + EventTypes: n.EventTypes, + ObjectNamePrefix: n.ObjectNamePrefix, + CustomAttributes: n.CustomAttributes, + PayloadFormat: n.PayloadFormat, + } +} + var topicRE = regexp.MustCompile("^//pubsub.googleapis.com/projects/([^/]+)/topics/([^/]+)") // parseNotificationTopic extracts the project and topic IDs from from the full @@ -132,16 +157,10 @@ func (b *BucketHandle) AddNotification(ctx context.Context, n *Notification) (re if n.TopicID == "" { return nil, errors.New("storage: AddNotification: missing TopicID") } - call := b.c.raw.Notifications.Insert(b.name, toRawNotification(n)) - setClientHeader(call.Header()) - if b.userProject != "" { - call.UserProject(b.userProject) - } - rn, err := call.Context(ctx).Do() - if err != nil { - return nil, err - } - return toNotification(rn), nil + + opts := makeStorageOpts(false, b.retry, b.userProject) + ret, err = b.c.tc.CreateNotification(ctx, b.name, n, opts...) + return ret, err } // Notifications returns all the Notifications configured for this bucket, as a map @@ -150,20 +169,9 @@ func (b *BucketHandle) Notifications(ctx context.Context) (n map[string]*Notific ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Notifications") defer func() { trace.EndSpan(ctx, err) }() - call := b.c.raw.Notifications.List(b.name) - setClientHeader(call.Header()) - if b.userProject != "" { - call.UserProject(b.userProject) - } - var res *raw.Notifications - err = runWithRetry(ctx, func() error { - res, err = call.Context(ctx).Do() - return err - }) - if err != nil { - return nil, err - } - return notificationsToMap(res.Items), nil + opts := makeStorageOpts(true, b.retry, b.userProject) + n, err = b.c.tc.ListNotifications(ctx, b.name, opts...) + return n, err } func notificationsToMap(rns []*raw.Notification) map[string]*Notification { @@ -174,15 +182,19 @@ func notificationsToMap(rns []*raw.Notification) map[string]*Notification { return m } +func notificationsToMapFromProto(ns []*storagepb.Notification) map[string]*Notification { + m := map[string]*Notification{} + for _, n := range ns { + m[n.Name] = toNotificationFromProto(n) + } + return m +} + // DeleteNotification deletes the notification with the given ID. func (b *BucketHandle) DeleteNotification(ctx context.Context, id string) (err error) { ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.DeleteNotification") defer func() { trace.EndSpan(ctx, err) }() - call := b.c.raw.Notifications.Delete(b.name, id) - setClientHeader(call.Header()) - if b.userProject != "" { - call.UserProject(b.userProject) - } - return call.Context(ctx).Do() + opts := makeStorageOpts(true, b.retry, b.userProject) + return b.c.tc.DeleteNotification(ctx, b.name, id, opts...) } diff --git a/vendor/cloud.google.com/go/storage/post_policy_v4.go b/vendor/cloud.google.com/go/storage/post_policy_v4.go index b9df7db9581..2961aca2062 100644 --- a/vendor/cloud.google.com/go/storage/post_policy_v4.go +++ b/vendor/cloud.google.com/go/storage/post_policy_v4.go @@ -52,22 +52,38 @@ type PostPolicyV4Options struct { // Exactly one of PrivateKey or SignBytes must be non-nil. PrivateKey []byte - // SignBytes is a function for implementing custom signing. For example, if + // SignBytes is a function for implementing custom signing. + // + // Deprecated: Use SignRawBytes. If both SignBytes and SignRawBytes are defined, + // SignBytes will be ignored. + // This SignBytes function expects the bytes it receives to be hashed, while + // SignRawBytes accepts the raw bytes without hashing, allowing more flexibility. + // Add the following to the top of your signing function to hash the bytes + // to use SignRawBytes instead: + // shaSum := sha256.Sum256(bytes) + // bytes = shaSum[:] + // + SignBytes func(hashBytes []byte) (signature []byte, err error) + + // SignRawBytes is a function for implementing custom signing. For example, if // your application is running on Google App Engine, you can use // appengine's internal signing function: - // ctx := appengine.NewContext(request) - // acc, _ := appengine.ServiceAccount(ctx) - // url, err := SignedURL("bucket", "object", &SignedURLOptions{ - // GoogleAccessID: acc, - // SignBytes: func(b []byte) ([]byte, error) { - // _, signedBytes, err := appengine.SignBytes(ctx, b) - // return signedBytes, err - // }, - // // etc. - // }) + // ctx := appengine.NewContext(request) + // acc, _ := appengine.ServiceAccount(ctx) + // &PostPolicyV4Options{ + // GoogleAccessID: acc, + // SignRawBytes: func(b []byte) ([]byte, error) { + // _, signedBytes, err := appengine.SignBytes(ctx, b) + // return signedBytes, err + // }, + // // etc. + // }) // - // Exactly one of PrivateKey or SignBytes must be non-nil. - SignBytes func(hashBytes []byte) (signature []byte, err error) + // SignRawBytes is equivalent to the SignBytes field on SignedURLOptions; + // that is, you may use the same signing function for the two. + // + // Exactly one of PrivateKey or SignRawBytes must be non-nil. + SignRawBytes func(bytes []byte) (signature []byte, err error) // Expires is the expiration time on the signed URL. // It must be a time in the future. @@ -96,6 +112,23 @@ type PostPolicyV4Options struct { // a 4XX status code, back with the message describing the problem. // Optional. Conditions []PostPolicyV4Condition + + shouldHashSignBytes bool +} + +func (opts *PostPolicyV4Options) clone() *PostPolicyV4Options { + return &PostPolicyV4Options{ + GoogleAccessID: opts.GoogleAccessID, + PrivateKey: opts.PrivateKey, + SignBytes: opts.SignBytes, + SignRawBytes: opts.SignRawBytes, + Expires: opts.Expires, + Style: opts.Style, + Insecure: opts.Insecure, + Fields: opts.Fields, + Conditions: opts.Conditions, + shouldHashSignBytes: opts.shouldHashSignBytes, + } } // PolicyV4Fields describes the attributes for a PostPolicyV4 request. @@ -206,6 +239,8 @@ func conditionStatusCodeOnSuccess(statusCode int) PostPolicyV4Condition { // GenerateSignedPostPolicyV4 generates a PostPolicyV4 value from bucket, object and opts. // The generated URL and fields will then allow an unauthenticated client to perform multipart uploads. +// If initializing a Storage Client, instead use the Bucket.GenerateSignedPostPolicyV4 +// method which uses the Client's credentials to handle authentication. func GenerateSignedPostPolicyV4(bucket, object string, opts *PostPolicyV4Options) (*PostPolicyV4, error) { if bucket == "" { return nil, errors.New("storage: bucket must be non-empty") @@ -220,20 +255,22 @@ func GenerateSignedPostPolicyV4(bucket, object string, opts *PostPolicyV4Options var signingFn func(hashedBytes []byte) ([]byte, error) switch { - case opts.SignBytes != nil: + case opts.SignRawBytes != nil: + signingFn = opts.SignRawBytes + case opts.shouldHashSignBytes: signingFn = opts.SignBytes - case len(opts.PrivateKey) != 0: parsedRSAPrivKey, err := parseKey(opts.PrivateKey) if err != nil { return nil, err } - signingFn = func(hashedBytes []byte) ([]byte, error) { - return rsa.SignPKCS1v15(rand.Reader, parsedRSAPrivKey, crypto.SHA256, hashedBytes) + signingFn = func(b []byte) ([]byte, error) { + sum := sha256.Sum256(b) + return rsa.SignPKCS1v15(rand.Reader, parsedRSAPrivKey, crypto.SHA256, sum[:]) } default: - return nil, errors.New("storage: exactly one of PrivateKey or SignedBytes must be set") + return nil, errors.New("storage: exactly one of PrivateKey or SignRawBytes must be set") } var descFields PolicyV4Fields @@ -249,10 +286,16 @@ func GenerateSignedPostPolicyV4(bucket, object string, opts *PostPolicyV4Options conds := make([]PostPolicyV4Condition, len(opts.Conditions)) copy(conds, opts.Conditions) conds = append(conds, - conditionRedirectToURLOnSuccess(descFields.RedirectToURLOnSuccess), - conditionStatusCodeOnSuccess(descFields.StatusCodeOnSuccess), + // These are ordered lexicographically. Technically the order doesn't matter + // for creating the policy, but we use this order to match the + // cross-language conformance tests for this feature. &singleValueCondition{"acl", descFields.ACL}, &singleValueCondition{"cache-control", descFields.CacheControl}, + &singleValueCondition{"content-disposition", descFields.ContentDisposition}, + &singleValueCondition{"content-encoding", descFields.ContentEncoding}, + &singleValueCondition{"content-type", descFields.ContentType}, + conditionRedirectToURLOnSuccess(descFields.RedirectToURLOnSuccess), + conditionStatusCodeOnSuccess(descFields.StatusCodeOnSuccess), ) YYYYMMDD := now.Format(yearMonthDay) @@ -261,8 +304,12 @@ func GenerateSignedPostPolicyV4(bucket, object string, opts *PostPolicyV4Options "x-goog-date": now.Format(iso8601), "x-goog-credential": opts.GoogleAccessID + "/" + YYYYMMDD + "/auto/storage/goog4_request", "x-goog-algorithm": "GOOG4-RSA-SHA256", - "success_action_redirect": descFields.RedirectToURLOnSuccess, "acl": descFields.ACL, + "cache-control": descFields.CacheControl, + "content-disposition": descFields.ContentDisposition, + "content-encoding": descFields.ContentEncoding, + "content-type": descFields.ContentType, + "success_action_redirect": descFields.RedirectToURLOnSuccess, } for key, value := range descFields.Metadata { conds = append(conds, &singleValueCondition{key, value}) @@ -293,14 +340,22 @@ func GenerateSignedPostPolicyV4(bucket, object string, opts *PostPolicyV4Options "expiration": opts.Expires.Format(time.RFC3339), }) if err != nil { - return nil, fmt.Errorf("storage: PostPolicyV4 JSON serialization failed: %v", err) + return nil, fmt.Errorf("storage: PostPolicyV4 JSON serialization failed: %w", err) } b64Policy := base64.StdEncoding.EncodeToString(condsAsJSON) - shaSum := sha256.Sum256([]byte(b64Policy)) - signature, err := signingFn(shaSum[:]) - if err != nil { - return nil, err + var signature []byte + var signErr error + + if opts.shouldHashSignBytes { + // SignBytes expects hashed bytes as input instead of raw bytes, so we hash them + shaSum := sha256.Sum256([]byte(b64Policy)) + signature, signErr = signingFn(shaSum[:]) + } else { + signature, signErr = signingFn([]byte(b64Policy)) + } + if signErr != nil { + return nil, signErr } policyFields["policy"] = b64Policy @@ -338,15 +393,16 @@ func GenerateSignedPostPolicyV4(bucket, object string, opts *PostPolicyV4Options // validatePostPolicyV4Options checks that: // * GoogleAccessID is set -// * either but not both PrivateKey and SignBytes are set or nil, but not both -// * Expires, the deadline is not in the past +// * either PrivateKey or SignRawBytes/SignBytes is set, but not both +// * the deadline set in Expires is not in the past // * if Style is not set, it'll use PathStyle +// * sets shouldHashSignBytes to true if opts.SignBytes should be used func validatePostPolicyV4Options(opts *PostPolicyV4Options, now time.Time) error { if opts == nil || opts.GoogleAccessID == "" { return errors.New("storage: missing required GoogleAccessID") } - if privBlank, signBlank := len(opts.PrivateKey) == 0, opts.SignBytes == nil; privBlank == signBlank { - return errors.New("storage: exactly one of PrivateKey or SignedBytes must be set") + if privBlank, signBlank := len(opts.PrivateKey) == 0, opts.SignBytes == nil && opts.SignRawBytes == nil; privBlank == signBlank { + return errors.New("storage: exactly one of PrivateKey or SignRawBytes must be set") } if opts.Expires.Before(now) { return errors.New("storage: expecting Expires to be in the future") @@ -354,6 +410,9 @@ func validatePostPolicyV4Options(opts *PostPolicyV4Options, now time.Time) error if opts.Style == nil { opts.Style = PathStyle() } + if opts.SignRawBytes == nil && opts.SignBytes != nil { + opts.shouldHashSignBytes = true + } return nil } diff --git a/vendor/cloud.google.com/go/storage/reader.go b/vendor/cloud.google.com/go/storage/reader.go index d64f5ec778c..46487d2b77d 100644 --- a/vendor/cloud.google.com/go/storage/reader.go +++ b/vendor/cloud.google.com/go/storage/reader.go @@ -16,20 +16,15 @@ package storage import ( "context" - "errors" "fmt" "hash/crc32" "io" "io/ioutil" "net/http" - "net/url" - "reflect" - "strconv" "strings" "time" "cloud.google.com/go/internal/trace" - "google.golang.org/api/googleapi" ) var crc32cTable = crc32.MakeTable(crc32.Castagnoli) @@ -106,194 +101,31 @@ func (o *ObjectHandle) NewRangeReader(ctx context.Context, offset, length int64) return nil, err } } - u := &url.URL{ - Scheme: o.c.scheme, - Host: o.c.readHost, - Path: fmt.Sprintf("/%s/%s", o.bucket, o.object), - } - verb := "GET" - if length == 0 { - verb = "HEAD" - } - req, err := http.NewRequest(verb, u.String(), nil) - if err != nil { - return nil, err - } - req = req.WithContext(ctx) - if o.userProject != "" { - req.Header.Set("X-Goog-User-Project", o.userProject) - } - if o.readCompressed { - req.Header.Set("Accept-Encoding", "gzip") - } - if err := setEncryptionHeaders(req.Header, o.encryptionKey, false); err != nil { - return nil, err - } - - gen := o.gen - - // Define a function that initiates a Read with offset and length, assuming we - // have already read seen bytes. - reopen := func(seen int64) (*http.Response, error) { - start := offset + seen - if length < 0 && start < 0 { - req.Header.Set("Range", fmt.Sprintf("bytes=%d", start)) - } else if length < 0 && start > 0 { - req.Header.Set("Range", fmt.Sprintf("bytes=%d-", start)) - } else if length > 0 { - // The end character isn't affected by how many bytes we've seen. - req.Header.Set("Range", fmt.Sprintf("bytes=%d-%d", start, offset+length-1)) - } - // We wait to assign conditions here because the generation number can change in between reopen() runs. - req.URL.RawQuery = conditionsQuery(gen, o.conds) - var res *http.Response - err = runWithRetry(ctx, func() error { - res, err = o.c.hc.Do(req) - if err != nil { - return err - } - if res.StatusCode == http.StatusNotFound { - res.Body.Close() - return ErrObjectNotExist - } - if res.StatusCode < 200 || res.StatusCode > 299 { - body, _ := ioutil.ReadAll(res.Body) - res.Body.Close() - return &googleapi.Error{ - Code: res.StatusCode, - Header: res.Header, - Body: string(body), - } - } - - partialContentNotSatisfied := - !decompressiveTranscoding(res) && - start > 0 && length != 0 && - res.StatusCode != http.StatusPartialContent - - if partialContentNotSatisfied { - res.Body.Close() - return errors.New("storage: partial request not satisfied") - } - - // With "Content-Encoding": "gzip" aka decompressive transcoding, GCS serves - // back the whole file regardless of the range count passed in as per: - // https://cloud.google.com/storage/docs/transcoding#range, - // thus we have to manually move the body forward by seen bytes. - if decompressiveTranscoding(res) && seen > 0 { - _, _ = io.CopyN(ioutil.Discard, res.Body, seen) - } - - // If a generation hasn't been specified, and this is the first response we get, let's record the - // generation. In future requests we'll use this generation as a precondition to avoid data races. - if gen < 0 && res.Header.Get("X-Goog-Generation") != "" { - gen64, err := strconv.ParseInt(res.Header.Get("X-Goog-Generation"), 10, 64) - if err != nil { - return err - } - gen = gen64 - } - return nil - }) - if err != nil { - return nil, err - } - return res, nil - } - - res, err := reopen(0) - if err != nil { - return nil, err - } - var ( - size int64 // total size of object, even if a range was requested. - checkCRC bool - crc uint32 - startOffset int64 // non-zero if range request. - ) - if res.StatusCode == http.StatusPartialContent { - cr := strings.TrimSpace(res.Header.Get("Content-Range")) - if !strings.HasPrefix(cr, "bytes ") || !strings.Contains(cr, "/") { - return nil, fmt.Errorf("storage: invalid Content-Range %q", cr) - } - size, err = strconv.ParseInt(cr[strings.LastIndex(cr, "/")+1:], 10, 64) - if err != nil { - return nil, fmt.Errorf("storage: invalid Content-Range %q", cr) - } - - dashIndex := strings.Index(cr, "-") - if dashIndex >= 0 { - startOffset, err = strconv.ParseInt(cr[len("bytes="):dashIndex], 10, 64) - if err != nil { - return nil, fmt.Errorf("storage: invalid Content-Range %q: %v", cr, err) - } - } - } else { - size = res.ContentLength - // Check the CRC iff all of the following hold: - // - We asked for content (length != 0). - // - We got all the content (status != PartialContent). - // - The server sent a CRC header. - // - The Go http stack did not uncompress the file. - // - We were not served compressed data that was uncompressed on download. - // The problem with the last two cases is that the CRC will not match -- GCS - // computes it on the compressed contents, but we compute it on the - // uncompressed contents. - if length != 0 && !res.Uncompressed && !uncompressedByServer(res) { - crc, checkCRC = parseCRC32c(res) - } - } - remain := res.ContentLength - body := res.Body - if length == 0 { - remain = 0 - body.Close() - body = emptyBody - } - var metaGen int64 - if res.Header.Get("X-Goog-Metageneration") != "" { - metaGen, err = strconv.ParseInt(res.Header.Get("X-Goog-Metageneration"), 10, 64) - if err != nil { - return nil, err - } + opts := makeStorageOpts(true, o.retry, o.userProject) + + params := &newRangeReaderParams{ + bucket: o.bucket, + object: o.object, + gen: o.gen, + offset: offset, + length: length, + encryptionKey: o.encryptionKey, + conds: o.conds, + readCompressed: o.readCompressed, } - var lm time.Time - if res.Header.Get("Last-Modified") != "" { - lm, err = http.ParseTime(res.Header.Get("Last-Modified")) - if err != nil { - return nil, err - } - } + r, err = o.c.tc.NewRangeReader(ctx, params, opts...) - attrs := ReaderObjectAttrs{ - Size: size, - ContentType: res.Header.Get("Content-Type"), - ContentEncoding: res.Header.Get("Content-Encoding"), - CacheControl: res.Header.Get("Cache-Control"), - LastModified: lm, - StartOffset: startOffset, - Generation: gen, - Metageneration: metaGen, - } - return &Reader{ - Attrs: attrs, - body: body, - size: size, - remain: remain, - wantCRC: crc, - checkCRC: checkCRC, - reopen: reopen, - }, nil + return r, err } // decompressiveTranscoding returns true if the request was served decompressed // and different than its original storage form. This happens when the "Content-Encoding" // header is "gzip". // See: -// * https://cloud.google.com/storage/docs/transcoding#transcoding_and_gzip -// * https://github.com/googleapis/google-cloud-go/issues/1800 +// - https://cloud.google.com/storage/docs/transcoding#transcoding_and_gzip +// - https://github.com/googleapis/google-cloud-go/issues/1800 func decompressiveTranscoding(res *http.Response) bool { // Decompressive Transcoding. return res.Header.Get("Content-Encoding") == "gzip" || @@ -320,6 +152,34 @@ func parseCRC32c(res *http.Response) (uint32, bool) { return 0, false } +// setConditionsHeaders sets precondition request headers for downloads +// using the XML API. It assumes that the conditions have been validated. +func setConditionsHeaders(headers http.Header, conds *Conditions) error { + if conds == nil { + return nil + } + if conds.MetagenerationMatch != 0 { + headers.Set("x-goog-if-metageneration-match", fmt.Sprint(conds.MetagenerationMatch)) + } + switch { + case conds.GenerationMatch != 0: + headers.Set("x-goog-if-generation-match", fmt.Sprint(conds.GenerationMatch)) + case conds.DoesNotExist: + headers.Set("x-goog-if-generation-match", "0") + } + return nil +} + +// Wrap a request to look similar to an apiary library request, in order to +// be used by run(). +type readerRequestWrapper struct { + req *http.Request +} + +func (w *readerRequestWrapper) Header() http.Header { + return w.req.Header +} + var emptyBody = ioutil.NopCloser(strings.NewReader("")) // Reader reads a Cloud Storage object. @@ -330,21 +190,21 @@ var emptyBody = ioutil.NopCloser(strings.NewReader("")) // is skipped if transcoding occurs. See https://cloud.google.com/storage/docs/transcoding. type Reader struct { Attrs ReaderObjectAttrs - body io.ReadCloser seen, remain, size int64 checkCRC bool // should we check the CRC? wantCRC uint32 // the CRC32c value the server sent in the header gotCRC uint32 // running crc - reopen func(seen int64) (*http.Response, error) + + reader io.ReadCloser } // Close closes the Reader. It must be called when done reading. func (r *Reader) Close() error { - return r.body.Close() + return r.reader.Close() } func (r *Reader) Read(p []byte) (int, error) { - n, err := r.readWithRetry(p) + n, err := r.reader.Read(p) if r.remain != -1 { r.remain -= int64(n) } @@ -363,35 +223,6 @@ func (r *Reader) Read(p []byte) (int, error) { return n, err } -func (r *Reader) readWithRetry(p []byte) (int, error) { - n := 0 - for len(p[n:]) > 0 { - m, err := r.body.Read(p[n:]) - n += m - r.seen += int64(m) - if !shouldRetryRead(err) { - return n, err - } - // Read failed, but we will try again. Send a ranged read request that takes - // into account the number of bytes we've already seen. - res, err := r.reopen(r.seen) - if err != nil { - // reopen already retries - return n, err - } - r.body.Close() - r.body = res.Body - } - return n, nil -} - -func shouldRetryRead(err error) bool { - if err == nil { - return false - } - return strings.HasSuffix(err.Error(), "INTERNAL_ERROR") && strings.Contains(reflect.TypeOf(err).String(), "http2") -} - // Size returns the size of the object in bytes. // The returned value is always the same and is not affected by // calls to Read or Close. diff --git a/vendor/cloud.google.com/go/storage/storage.go b/vendor/cloud.google.com/go/storage/storage.go index 20d9518a42d..b5c10efc8a7 100644 --- a/vendor/cloud.google.com/go/storage/storage.go +++ b/vendor/cloud.google.com/go/storage/storage.go @@ -40,11 +40,20 @@ import ( "cloud.google.com/go/internal/optional" "cloud.google.com/go/internal/trace" - "cloud.google.com/go/internal/version" + "cloud.google.com/go/storage/internal" + storagepb "cloud.google.com/go/storage/internal/apiv2/stubs" + "github.com/googleapis/gax-go/v2" + "golang.org/x/oauth2/google" "google.golang.org/api/googleapi" "google.golang.org/api/option" + "google.golang.org/api/option/internaloption" raw "google.golang.org/api/storage/v1" + "google.golang.org/api/transport" htransport "google.golang.org/api/transport/http" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protoreflect" + "google.golang.org/protobuf/types/known/fieldmaskpb" + "google.golang.org/protobuf/types/known/timestamppb" ) // Methods which can be used in signed URLs. @@ -55,11 +64,14 @@ var ( ErrBucketNotExist = errors.New("storage: bucket doesn't exist") // ErrObjectNotExist indicates that the object does not exist. ErrObjectNotExist = errors.New("storage: object doesn't exist") + // errMethodNotSupported indicates that the method called is not currently supported by the client. + // TODO: Export this error when launching the transport-agnostic client. + errMethodNotSupported = errors.New("storage: method is not currently supported") // errMethodNotValid indicates that given HTTP method is not valid. errMethodNotValid = fmt.Errorf("storage: HTTP method should be one of %v", reflect.ValueOf(signedURLMethods).MapKeys()) ) -var userAgent = fmt.Sprintf("gcloud-golang-storage/%s", version.Repo) +var userAgent = fmt.Sprintf("gcloud-golang-storage/%s", internal.Version) const ( // ScopeFullControl grants permissions to manage your @@ -73,12 +85,19 @@ const ( // ScopeReadWrite grants permissions to manage your // data in Google Cloud Storage. ScopeReadWrite = raw.DevstorageReadWriteScope -) -var xGoogHeader = fmt.Sprintf("gl-go/%s gccl/%s", version.Go(), version.Repo) + // aes256Algorithm is the AES256 encryption algorithm used with the + // Customer-Supplied Encryption Keys feature. + aes256Algorithm = "AES256" + + // defaultGen indicates the latest object generation by default, + // using a negative value. + defaultGen = int64(-1) +) +// TODO: remove this once header with invocation ID is applied to all methods. func setClientHeader(headers http.Header) { - headers.Set("x-goog-api-client", xGoogHeader) + headers.Set("x-goog-api-client", xGoogDefaultHeader) } // Client is a client for interacting with Google Cloud Storage. @@ -90,62 +109,127 @@ type Client struct { raw *raw.Service // Scheme describes the scheme under the current host. scheme string - // EnvHost is the host set on the STORAGE_EMULATOR_HOST variable. - envHost string // ReadHost is the default host used on the reader. readHost string + // May be nil. + creds *google.Credentials + retry *retryConfig + + // tc is the transport-agnostic client implemented with either gRPC or HTTP. + tc storageClient + // useGRPC flags whether the client uses gRPC. This is needed while the + // integration piece is only partially complete. + // TODO: remove before merging to main. + useGRPC bool } // NewClient creates a new Google Cloud Storage client. -// The default scope is ScopeFullControl. To use a different scope, like ScopeReadOnly, use option.WithScopes. +// The default scope is ScopeFullControl. To use a different scope, like +// ScopeReadOnly, use option.WithScopes. +// +// Clients should be reused instead of created as needed. The methods of Client +// are safe for concurrent use by multiple goroutines. func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { - var host, readHost, scheme string - if host = os.Getenv("STORAGE_EMULATOR_HOST"); host == "" { - scheme = "https" - readHost = "storage.googleapis.com" + // Use the experimental gRPC client if the env var is set. + // This is an experimental API and not intended for public use. + if withGRPC := os.Getenv("STORAGE_USE_GRPC"); withGRPC != "" { + return newGRPCClient(ctx, opts...) + } + + var creds *google.Credentials + // In general, it is recommended to use raw.NewService instead of htransport.NewClient + // since raw.NewService configures the correct default endpoints when initializing the + // internal http client. However, in our case, "NewRangeReader" in reader.go needs to + // access the http client directly to make requests, so we create the client manually + // here so it can be re-used by both reader.go and raw.NewService. This means we need to + // manually configure the default endpoint options on the http client. Furthermore, we + // need to account for STORAGE_EMULATOR_HOST override when setting the default endpoints. + if host := os.Getenv("STORAGE_EMULATOR_HOST"); host == "" { // Prepend default options to avoid overriding options passed by the user. - opts = append([]option.ClientOption{option.WithScopes(ScopeFullControl), option.WithUserAgent(userAgent)}, opts...) + opts = append([]option.ClientOption{option.WithScopes(ScopeFullControl, "https://www.googleapis.com/auth/cloud-platform"), option.WithUserAgent(userAgent)}, opts...) + + opts = append(opts, internaloption.WithDefaultEndpoint("https://storage.googleapis.com/storage/v1/")) + opts = append(opts, internaloption.WithDefaultMTLSEndpoint("https://storage.mtls.googleapis.com/storage/v1/")) + + // Don't error out here. The user may have passed in their own HTTP + // client which does not auth with ADC or other common conventions. + c, err := transport.Creds(ctx, opts...) + if err == nil { + creds = c + opts = append(opts, internaloption.WithCredentials(creds)) + } } else { - scheme = "http" - readHost = host + var hostURL *url.URL + if strings.Contains(host, "://") { + h, err := url.Parse(host) + if err != nil { + return nil, err + } + hostURL = h + } else { + // Add scheme for user if not supplied in STORAGE_EMULATOR_HOST + // URL is only parsed correctly if it has a scheme, so we build it ourselves + hostURL = &url.URL{Scheme: "http", Host: host} + } + + hostURL.Path = "storage/v1/" + endpoint := hostURL.String() + + // Append the emulator host as default endpoint for the user opts = append([]option.ClientOption{option.WithoutAuthentication()}, opts...) + + opts = append(opts, internaloption.WithDefaultEndpoint(endpoint)) + opts = append(opts, internaloption.WithDefaultMTLSEndpoint(endpoint)) } + // htransport selects the correct endpoint among WithEndpoint (user override), WithDefaultEndpoint, and WithDefaultMTLSEndpoint. hc, ep, err := htransport.NewClient(ctx, opts...) if err != nil { - return nil, fmt.Errorf("dialing: %v", err) + return nil, fmt.Errorf("dialing: %w", err) } - rawService, err := raw.NewService(ctx, option.WithHTTPClient(hc)) + // RawService should be created with the chosen endpoint to take account of user override. + rawService, err := raw.NewService(ctx, option.WithEndpoint(ep), option.WithHTTPClient(hc)) if err != nil { - return nil, fmt.Errorf("storage client: %v", err) + return nil, fmt.Errorf("storage client: %w", err) } - if ep == "" { - // Override the default value for BasePath from the raw client. - // TODO: remove when the raw client uses this endpoint as its default (~end of 2020) - rawService.BasePath = "https://storage.googleapis.com/storage/v1/" - } else { - // If the endpoint has been set explicitly, use this for the BasePath - // as well as readHost - rawService.BasePath = ep - u, err := url.Parse(ep) - if err != nil { - return nil, fmt.Errorf("supplied endpoint %v is not valid: %v", ep, err) - } - readHost = u.Host + // Update readHost and scheme with the chosen endpoint. + u, err := url.Parse(ep) + if err != nil { + return nil, fmt.Errorf("supplied endpoint %q is not valid: %w", ep, err) + } + + tc, err := newHTTPStorageClient(ctx, withClientOptions(opts...)) + if err != nil { + return nil, fmt.Errorf("storage: %w", err) } return &Client{ hc: hc, raw: rawService, - scheme: scheme, - envHost: host, - readHost: readHost, + scheme: u.Scheme, + readHost: u.Host, + creds: creds, + tc: tc, }, nil } +// newGRPCClient creates a new Storage client that initializes a gRPC-based +// client. Calls that have not been implemented in gRPC will panic. +// +// This is an experimental API and not intended for public use. +func newGRPCClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + opts = append(defaultGRPCOptions(), opts...) + tc, err := newGRPCStorageClient(ctx, withClientOptions(opts...)) + if err != nil { + return nil, err + } + + return &Client{tc: tc, useGRPC: true}, nil +} + // Close closes the Client. // // Close need not be called at program exit. @@ -153,6 +237,10 @@ func (c *Client) Close() error { // Set fields to nil so that subsequent uses will panic. c.hc = nil c.raw = nil + c.creds = nil + if c.tc != nil { + return c.tc.Close() + } return nil } @@ -193,10 +281,18 @@ type bucketBoundHostname struct { } func (s pathStyle) host(bucket string) string { + if host := os.Getenv("STORAGE_EMULATOR_HOST"); host != "" { + return stripScheme(host) + } + return "storage.googleapis.com" } func (s virtualHostedStyle) host(bucket string) string { + if host := os.Getenv("STORAGE_EMULATOR_HOST"); host != "" { + return bucket + "." + stripScheme(host) + } + return bucket + ".storage.googleapis.com" } @@ -244,6 +340,14 @@ func BucketBoundHostname(hostname string) URLStyle { return bucketBoundHostname{hostname: hostname} } +// Strips the scheme from a host if it contains it +func stripScheme(host string) string { + if strings.Contains(host, "://") { + host = strings.SplitN(host, "://", 2)[1] + } + return host +} + // SignedURLOptions allows you to restrict the access to the signed URL. type SignedURLOptions struct { // GoogleAccessID represents the authorizer of the signed URL generation. @@ -336,6 +440,23 @@ type SignedURLOptions struct { Scheme SigningScheme } +func (opts *SignedURLOptions) clone() *SignedURLOptions { + return &SignedURLOptions{ + GoogleAccessID: opts.GoogleAccessID, + SignBytes: opts.SignBytes, + PrivateKey: opts.PrivateKey, + Method: opts.Method, + Expires: opts.Expires, + ContentType: opts.ContentType, + Headers: opts.Headers, + QueryParameters: opts.QueryParameters, + MD5: opts.MD5, + Style: opts.Style, + Insecure: opts.Insecure, + Scheme: opts.Scheme, + } +} + var ( tabRegex = regexp.MustCompile(`[\t]+`) // I was tempted to call this spacex. :) @@ -349,7 +470,7 @@ var ( ) // v2SanitizeHeaders applies the specifications for canonical extension headers at -// https://cloud.google.com/storage/docs/access-control/signed-urls#about-canonical-extension-headers. +// https://cloud.google.com/storage/docs/access-control/signed-urls-v2#about-canonical-extension-headers func v2SanitizeHeaders(hdrs []string) []string { headerMap := map[string][]string{} for _, hdr := range hdrs { @@ -397,16 +518,16 @@ func v2SanitizeHeaders(hdrs []string) []string { } // v4SanitizeHeaders applies the specifications for canonical extension headers -// at https://cloud.google.com/storage/docs/access-control/signed-urls#about-canonical-extension-headers. +// at https://cloud.google.com/storage/docs/authentication/canonical-requests#about-headers. // // V4 does a couple things differently from V2: -// - Headers get sorted by key, instead of by key:value. We do this in -// signedURLV4. -// - There's no canonical regexp: we simply split headers on :. -// - We don't exclude canonical headers. -// - We replace leading and trailing spaces in header values, like v2, but also -// all intermediate space duplicates get stripped. That is, there's only ever -// a single consecutive space. +// - Headers get sorted by key, instead of by key:value. We do this in +// signedURLV4. +// - There's no canonical regexp: we simply split headers on :. +// - We don't exclude canonical headers. +// - We replace leading and trailing spaces in header values, like v2, but also +// all intermediate space duplicates get stripped. That is, there's only ever +// a single consecutive space. func v4SanitizeHeaders(hdrs []string) []string { headerMap := map[string][]string{} for _, hdr := range hdrs { @@ -449,11 +570,13 @@ func v4SanitizeHeaders(hdrs []string) []string { return sanitizedHeaders } -// SignedURL returns a URL for the specified object. Signed URLs allow -// the users access to a restricted resource for a limited time without having a -// Google account or signing in. For more information about the signed -// URLs, see https://cloud.google.com/storage/docs/accesscontrol#Signed-URLs. -func SignedURL(bucket, name string, opts *SignedURLOptions) (string, error) { +// SignedURL returns a URL for the specified object. Signed URLs allow anyone +// access to a restricted resource for a limited time without needing a +// Google account or signing in. For more information about signed URLs, see +// https://cloud.google.com/storage/docs/accesscontrol#signed_urls_query_string_authentication +// If initializing a Storage Client, instead use the Bucket.SignedURL method +// which uses the Client's credentials to handle authentication. +func SignedURL(bucket, object string, opts *SignedURLOptions) (string, error) { now := utcNow() if err := validateOptions(opts, now); err != nil { return "", err @@ -462,13 +585,13 @@ func SignedURL(bucket, name string, opts *SignedURLOptions) (string, error) { switch opts.Scheme { case SigningSchemeV2: opts.Headers = v2SanitizeHeaders(opts.Headers) - return signedURLV2(bucket, name, opts) + return signedURLV2(bucket, object, opts) case SigningSchemeV4: opts.Headers = v4SanitizeHeaders(opts.Headers) - return signedURLV4(bucket, name, opts, now) + return signedURLV4(bucket, object, opts, now) default: // SigningSchemeDefault opts.Headers = v2SanitizeHeaders(opts.Headers) - return signedURLV2(bucket, name, opts) + return signedURLV2(bucket, object, opts) } } @@ -583,8 +706,10 @@ func signedURLV4(bucket, name string, opts *SignedURLOptions, now time.Time) (st for k, v := range opts.QueryParameters { canonicalQueryString[k] = append(canonicalQueryString[k], v...) } - - fmt.Fprintf(buf, "%s\n", canonicalQueryString.Encode()) + // url.Values.Encode escaping is correct, except that a space must be replaced + // by `%20` rather than `+`. + escapedQuery := strings.Replace(canonicalQueryString.Encode(), "+", "%20", -1) + fmt.Fprintf(buf, "%s\n", escapedQuery) // Fill in the hostname based on the desired URL style. u.Host = opts.Style.host(bucket) @@ -721,7 +846,7 @@ func signedURLV2(bucket, name string, opts *SignedURLOptions) (string, error) { } encoded := base64.StdEncoding.EncodeToString(b) u.Scheme = "https" - u.Host = "storage.googleapis.com" + u.Host = PathStyle().host(bucket) q := u.Query() q.Set("GoogleAccessId", opts.GoogleAccessID) q.Set("Expires", fmt.Sprintf("%d", opts.Expires.Unix())) @@ -742,6 +867,7 @@ type ObjectHandle struct { encryptionKey []byte // AES-256 key userProject string // for requester-pays buckets readCompressed bool // Accept-Encoding: gzip + retry *retryConfig } // ACL provides access to the object's access control list. @@ -793,30 +919,12 @@ func (o *ObjectHandle) Attrs(ctx context.Context) (attrs *ObjectAttrs, err error if err := o.validate(); err != nil { return nil, err } - call := o.c.raw.Objects.Get(o.bucket, o.object).Projection("full").Context(ctx) - if err := applyConds("Attrs", o.gen, o.conds, call); err != nil { - return nil, err - } - if o.userProject != "" { - call.UserProject(o.userProject) - } - if err := setEncryptionHeaders(call.Header(), o.encryptionKey, false); err != nil { - return nil, err - } - var obj *raw.Object - setClientHeader(call.Header()) - err = runWithRetry(ctx, func() error { obj, err = call.Do(); return err }) - if e, ok := err.(*googleapi.Error); ok && e.Code == http.StatusNotFound { - return nil, ErrObjectNotExist - } - if err != nil { - return nil, err - } - return newObject(obj), nil + opts := makeStorageOpts(true, o.retry, o.userProject) + return o.c.tc.GetObject(ctx, o.bucket, o.object, o.gen, o.encryptionKey, o.conds, opts...) } -// Update updates an object with the provided attributes. -// All zero-value attributes are ignored. +// Update updates an object with the provided attributes. See +// ObjectAttrsToUpdate docs for details on treatment of zero values. // ErrObjectNotExist will be returned if the object is not found. func (o *ObjectHandle) Update(ctx context.Context, uattrs ObjectAttrsToUpdate) (oa *ObjectAttrs, err error) { ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Object.Update") @@ -825,90 +933,9 @@ func (o *ObjectHandle) Update(ctx context.Context, uattrs ObjectAttrsToUpdate) ( if err := o.validate(); err != nil { return nil, err } - var attrs ObjectAttrs - // Lists of fields to send, and set to null, in the JSON. - var forceSendFields, nullFields []string - if uattrs.ContentType != nil { - attrs.ContentType = optional.ToString(uattrs.ContentType) - // For ContentType, sending the empty string is a no-op. - // Instead we send a null. - if attrs.ContentType == "" { - nullFields = append(nullFields, "ContentType") - } else { - forceSendFields = append(forceSendFields, "ContentType") - } - } - if uattrs.ContentLanguage != nil { - attrs.ContentLanguage = optional.ToString(uattrs.ContentLanguage) - // For ContentLanguage it's an error to send the empty string. - // Instead we send a null. - if attrs.ContentLanguage == "" { - nullFields = append(nullFields, "ContentLanguage") - } else { - forceSendFields = append(forceSendFields, "ContentLanguage") - } - } - if uattrs.ContentEncoding != nil { - attrs.ContentEncoding = optional.ToString(uattrs.ContentEncoding) - forceSendFields = append(forceSendFields, "ContentEncoding") - } - if uattrs.ContentDisposition != nil { - attrs.ContentDisposition = optional.ToString(uattrs.ContentDisposition) - forceSendFields = append(forceSendFields, "ContentDisposition") - } - if uattrs.CacheControl != nil { - attrs.CacheControl = optional.ToString(uattrs.CacheControl) - forceSendFields = append(forceSendFields, "CacheControl") - } - if uattrs.EventBasedHold != nil { - attrs.EventBasedHold = optional.ToBool(uattrs.EventBasedHold) - forceSendFields = append(forceSendFields, "EventBasedHold") - } - if uattrs.TemporaryHold != nil { - attrs.TemporaryHold = optional.ToBool(uattrs.TemporaryHold) - forceSendFields = append(forceSendFields, "TemporaryHold") - } - if uattrs.Metadata != nil { - attrs.Metadata = uattrs.Metadata - if len(attrs.Metadata) == 0 { - // Sending the empty map is a no-op. We send null instead. - nullFields = append(nullFields, "Metadata") - } else { - forceSendFields = append(forceSendFields, "Metadata") - } - } - if uattrs.ACL != nil { - attrs.ACL = uattrs.ACL - // It's an error to attempt to delete the ACL, so - // we don't append to nullFields here. - forceSendFields = append(forceSendFields, "Acl") - } - rawObj := attrs.toRawObject(o.bucket) - rawObj.ForceSendFields = forceSendFields - rawObj.NullFields = nullFields - call := o.c.raw.Objects.Patch(o.bucket, o.object, rawObj).Projection("full").Context(ctx) - if err := applyConds("Update", o.gen, o.conds, call); err != nil { - return nil, err - } - if o.userProject != "" { - call.UserProject(o.userProject) - } - if uattrs.PredefinedACL != "" { - call.PredefinedAcl(uattrs.PredefinedACL) - } - if err := setEncryptionHeaders(call.Header(), o.encryptionKey, false); err != nil { - return nil, err - } - var obj *raw.Object - setClientHeader(call.Header()) - err = runWithRetry(ctx, func() error { obj, err = call.Do(); return err }) - if e, ok := err.(*googleapi.Error); ok && e.Code == http.StatusNotFound { - return nil, ErrObjectNotExist - } - if err != nil { - return nil, err - } - return newObject(obj), nil + isIdempotent := o.conds != nil && o.conds.MetagenerationMatch != 0 + opts := makeStorageOpts(isIdempotent, o.retry, o.userProject) + return o.c.tc.UpdateObject(ctx, o.bucket, o.object, &uattrs, o.gen, o.encryptionKey, o.conds, opts...) } // BucketName returns the name of the bucket. @@ -923,15 +950,17 @@ func (o *ObjectHandle) ObjectName() string { // ObjectAttrsToUpdate is used to update the attributes of an object. // Only fields set to non-nil values will be updated. -// Set a field to its zero value to delete it. +// For all fields except CustomTime, set the field to its zero value to delete +// it. CustomTime cannot be deleted or changed to an earlier time once set. // // For example, to change ContentType and delete ContentEncoding and // Metadata, use -// ObjectAttrsToUpdate{ -// ContentType: "text/html", -// ContentEncoding: "", -// Metadata: map[string]string{}, -// } +// +// ObjectAttrsToUpdate{ +// ContentType: "text/html", +// ContentEncoding: "", +// Metadata: map[string]string{}, +// } type ObjectAttrsToUpdate struct { EventBasedHold optional.Bool TemporaryHold optional.Bool @@ -940,7 +969,8 @@ type ObjectAttrsToUpdate struct { ContentEncoding optional.String ContentDisposition optional.String CacheControl optional.String - Metadata map[string]string // set to map[string]string{} to delete + CustomTime time.Time // Cannot be deleted or backdated from its current value. + Metadata map[string]string // Set to map[string]string{} to delete. ACL []ACLRule // If not empty, applies a predefined set of access controls. ACL must be nil. @@ -953,25 +983,11 @@ func (o *ObjectHandle) Delete(ctx context.Context) error { if err := o.validate(); err != nil { return err } - call := o.c.raw.Objects.Delete(o.bucket, o.object).Context(ctx) - if err := applyConds("Delete", o.gen, o.conds, call); err != nil { - return err - } - if o.userProject != "" { - call.UserProject(o.userProject) - } - // Encryption doesn't apply to Delete. - setClientHeader(call.Header()) - err := runWithRetry(ctx, func() error { return call.Do() }) - switch e := err.(type) { - case nil: - return nil - case *googleapi.Error: - if e.Code == http.StatusNotFound { - return ErrObjectNotExist - } - } - return err + // Delete is idempotent if GenerationMatch or Generation have been passed in. + // The default generation is negative to get the latest version of the object. + isIdempotent := (o.conds != nil && o.conds.GenerationMatch != 0) || o.gen >= 0 + opts := makeStorageOpts(isIdempotent, o.retry, o.userProject) + return o.c.tc.DeleteObject(ctx, o.bucket, o.object, o.gen, o.conds, opts...) } // ReadCompressed when true causes the read to happen without decompressing. @@ -994,6 +1010,9 @@ func (o *ObjectHandle) ReadCompressed(compressed bool) *ObjectHandle { // attribute is specified, the content type will be automatically sniffed // using net/http.DetectContentType. // +// Note that each Writer allocates an internal buffer of size Writer.ChunkSize. +// See the ChunkSize docs for more information. +// // It is the caller's responsibility to call Close when writing is done. To // stop writing without saving the data, cancel the context. func (o *ObjectHandle) NewWriter(ctx context.Context) *Writer { @@ -1047,6 +1066,10 @@ func (o *ObjectAttrs) toRawObject(bucket string) *raw.Object { if !o.RetentionExpirationTime.IsZero() { ret = o.RetentionExpirationTime.Format(time.RFC3339) } + var ct string + if !o.CustomTime.IsZero() { + ct = o.CustomTime.Format(time.RFC3339) + } return &raw.Object{ Bucket: bucket, Name: o.Name, @@ -1061,7 +1084,84 @@ func (o *ObjectAttrs) toRawObject(bucket string) *raw.Object { StorageClass: o.StorageClass, Acl: toRawObjectACL(o.ACL), Metadata: o.Metadata, + CustomTime: ct, + } +} + +// toProtoObject copies the editable attributes from o to the proto library's Object type. +func (o *ObjectAttrs) toProtoObject(b string) *storagepb.Object { + // For now, there are only globally unique buckets, and "_" is the alias + // project ID for such buckets. If the bucket is not provided, like in the + // destination ObjectAttrs of a Copy, do not attempt to format it. + if b != "" { + b = bucketResourceName(globalProjectAlias, b) + } + + return &storagepb.Object{ + Bucket: b, + Name: o.Name, + EventBasedHold: proto.Bool(o.EventBasedHold), + TemporaryHold: o.TemporaryHold, + ContentType: o.ContentType, + ContentEncoding: o.ContentEncoding, + ContentLanguage: o.ContentLanguage, + CacheControl: o.CacheControl, + ContentDisposition: o.ContentDisposition, + StorageClass: o.StorageClass, + Acl: toProtoObjectACL(o.ACL), + Metadata: o.Metadata, + CreateTime: toProtoTimestamp(o.Created), + CustomTime: toProtoTimestamp(o.CustomTime), + DeleteTime: toProtoTimestamp(o.Deleted), + RetentionExpireTime: toProtoTimestamp(o.RetentionExpirationTime), + UpdateTime: toProtoTimestamp(o.Updated), + KmsKey: o.KMSKeyName, + Generation: o.Generation, + Size: o.Size, + } +} + +// toProtoObject copies the attributes to update from uattrs to the proto library's Object type. +func (uattrs *ObjectAttrsToUpdate) toProtoObject(bucket, object string) *storagepb.Object { + o := &storagepb.Object{ + Name: object, + Bucket: bucket, + } + if uattrs == nil { + return o + } + + if uattrs.EventBasedHold != nil { + o.EventBasedHold = proto.Bool(optional.ToBool(uattrs.EventBasedHold)) + } + if uattrs.TemporaryHold != nil { + o.TemporaryHold = optional.ToBool(uattrs.TemporaryHold) + } + if uattrs.ContentType != nil { + o.ContentType = optional.ToString(uattrs.ContentType) + } + if uattrs.ContentLanguage != nil { + o.ContentLanguage = optional.ToString(uattrs.ContentLanguage) + } + if uattrs.ContentEncoding != nil { + o.ContentEncoding = optional.ToString(uattrs.ContentEncoding) } + if uattrs.ContentDisposition != nil { + o.ContentDisposition = optional.ToString(uattrs.ContentDisposition) + } + if uattrs.CacheControl != nil { + o.CacheControl = optional.ToString(uattrs.CacheControl) + } + if !uattrs.CustomTime.IsZero() { + o.CustomTime = toProtoTimestamp(uattrs.CustomTime) + } + if uattrs.ACL != nil { + o.Acl = toProtoObjectACL(uattrs.ACL) + } + + // TODO(cathyo): Handle metadata. Pending b/230510191. + + return o } // ObjectAttrs represents the metadata for a Google Cloud Storage (GCS) object. @@ -1135,6 +1235,9 @@ type ObjectAttrs struct { // Composer. In those cases, if the SendCRC32C field in the Writer or Composer // is set to is true, the uploaded data is rejected if its CRC32C hash does // not match this field. + // + // Note: For a Writer, SendCRC32C must be set to true BEFORE the first call to + // Writer.Write() in order to send the checksum. CRC32C uint32 // MediaLink is an URL to the object's content. This field is read-only. @@ -1142,6 +1245,10 @@ type ObjectAttrs struct { // Metadata represents user-provided metadata, in key/value pairs. // It can be nil if no metadata is provided. + // + // For object downloads using Reader, metadata keys are sent as headers. + // Therefore, avoid setting metadata keys using characters that are not valid + // for headers. See https://www.rfc-editor.org/rfc/rfc7230#section-3.2.6. Metadata map[string]string // Generation is the generation number of the object's content. @@ -1199,6 +1306,15 @@ type ObjectAttrs struct { // Etag is the HTTP/1.1 Entity tag for the object. // This field is read-only. Etag string + + // A user-specified timestamp which can be applied to an object. This is + // typically set in order to use the CustomTimeBefore and DaysSinceCustomTime + // LifecycleConditions to manage object lifecycles. + // + // CustomTime cannot be removed once set on an object. It can be updated to a + // later value but not to an earlier one. For more information see + // https://cloud.google.com/storage/docs/metadata#custom-time . + CustomTime time.Time } // convertTime converts a time in RFC3339 format to time.Time. @@ -1211,6 +1327,22 @@ func convertTime(t string) time.Time { return r } +func convertProtoTime(t *timestamppb.Timestamp) time.Time { + var r time.Time + if t != nil { + r = t.AsTime() + } + return r +} + +func toProtoTimestamp(t time.Time) *timestamppb.Timestamp { + if t.IsZero() { + return nil + } + + return timestamppb.New(t) +} + func newObject(o *raw.Object) *ObjectAttrs { if o == nil { return nil @@ -1252,6 +1384,41 @@ func newObject(o *raw.Object) *ObjectAttrs { Deleted: convertTime(o.TimeDeleted), Updated: convertTime(o.Updated), Etag: o.Etag, + CustomTime: convertTime(o.CustomTime), + } +} + +func newObjectFromProto(o *storagepb.Object) *ObjectAttrs { + if o == nil { + return nil + } + return &ObjectAttrs{ + Bucket: parseBucketName(o.Bucket), + Name: o.Name, + ContentType: o.ContentType, + ContentLanguage: o.ContentLanguage, + CacheControl: o.CacheControl, + EventBasedHold: o.GetEventBasedHold(), + TemporaryHold: o.TemporaryHold, + RetentionExpirationTime: convertProtoTime(o.GetRetentionExpireTime()), + ACL: toObjectACLRulesFromProto(o.GetAcl()), + Owner: o.GetOwner().GetEntity(), + ContentEncoding: o.ContentEncoding, + ContentDisposition: o.ContentDisposition, + Size: int64(o.Size), + MD5: o.GetChecksums().GetMd5Hash(), + CRC32C: o.GetChecksums().GetCrc32C(), + Metadata: o.Metadata, + Generation: o.Generation, + Metageneration: o.Metageneration, + StorageClass: o.StorageClass, + // CustomerKeySHA256 needs to be presented as base64 encoded, but the response from gRPC is not. + CustomerKeySHA256: base64.StdEncoding.EncodeToString(o.GetCustomerEncryption().GetKeySha256Bytes()), + KMSKeyName: o.GetKmsKey(), + Created: convertProtoTime(o.GetCreateTime()), + Deleted: convertProtoTime(o.GetDeleteTime()), + Updated: convertProtoTime(o.GetUpdateTime()), + CustomTime: convertProtoTime(o.GetCustomTime()), } } @@ -1273,6 +1440,31 @@ func encodeUint32(u uint32) string { return base64.StdEncoding.EncodeToString(b) } +// Projection is enumerated type for Query.Projection. +type Projection int + +const ( + // ProjectionDefault returns all fields of objects. + ProjectionDefault Projection = iota + + // ProjectionFull returns all fields of objects. + ProjectionFull + + // ProjectionNoACL returns all fields of objects except for Owner and ACL. + ProjectionNoACL +) + +func (p Projection) String() string { + switch p { + case ProjectionFull: + return "full" + case ProjectionNoACL: + return "noAcl" + default: + return "" + } +} + // Query represents a query to filter objects from a bucket. type Query struct { // Delimiter returns results in a directory-like fashion. @@ -1293,10 +1485,35 @@ type Query struct { // object will be included in the results. Versions bool - // fieldSelection is used to select only specific fields to be returned by - // the query. It's used internally and is populated for the user by - // calling Query.SetAttrSelection - fieldSelection string + // attrSelection is used to select only specific fields to be returned by + // the query. It is set by the user calling calling SetAttrSelection. These + // are used by toFieldMask and toFieldSelection for gRPC and HTTP/JSON + // clients repsectively. + attrSelection []string + + // StartOffset is used to filter results to objects whose names are + // lexicographically equal to or after startOffset. If endOffset is also set, + // the objects listed will have names between startOffset (inclusive) and + // endOffset (exclusive). + StartOffset string + + // EndOffset is used to filter results to objects whose names are + // lexicographically before endOffset. If startOffset is also set, the objects + // listed will have names between startOffset (inclusive) and endOffset (exclusive). + EndOffset string + + // Projection defines the set of properties to return. It will default to ProjectionFull, + // which returns all properties. Passing ProjectionNoACL will omit Owner and ACL, + // which may improve performance when listing many objects. + Projection Projection + + // IncludeTrailingDelimiter controls how objects which end in a single + // instance of Delimiter (for example, if Query.Delimiter = "/" and the + // object name is "foo/bar/") are included in the results. By default, these + // objects only show up as prefixes. If IncludeTrailingDelimiter is set to + // true, they will also be included as objects and their metadata will be + // populated in the returned ObjectAttrs. + IncludeTrailingDelimiter bool } // attrToFieldMap maps the field names of ObjectAttrs to the underlying field @@ -1329,6 +1546,40 @@ var attrToFieldMap = map[string]string{ "Deleted": "timeDeleted", "Updated": "updated", "Etag": "etag", + "CustomTime": "customTime", +} + +// attrToProtoFieldMap maps the field names of ObjectAttrs to the underlying field +// names in the protobuf Object message. +var attrToProtoFieldMap = map[string]string{ + "Name": "name", + "Bucket": "bucket", + "Etag": "etag", + "Generation": "generation", + "Metageneration": "metageneration", + "StorageClass": "storage_class", + "Size": "size", + "ContentEncoding": "content_encoding", + "ContentDisposition": "content_disposition", + "CacheControl": "cache_control", + "ACL": "acl", + "ContentLanguage": "content_language", + "Deleted": "delete_time", + "ContentType": "content_type", + "Created": "create_time", + "CRC32C": "checksums.crc32c", + "MD5": "checksums.md5_hash", + "Updated": "update_time", + "KMSKeyName": "kms_key", + "TemporaryHold": "temporary_hold", + "RetentionExpirationTime": "retention_expire_time", + "Metadata": "metadata", + "EventBasedHold": "event_based_hold", + "Owner": "owner", + "CustomerKeySHA256": "customer_encryption", + "CustomTime": "custom_time", + // MediaLink was explicitly excluded from the proto as it is an HTTP-ism. + // "MediaLink": "mediaLink", } // SetAttrSelection makes the query populate only specific attributes of @@ -1339,19 +1590,45 @@ var attrToFieldMap = map[string]string{ // optimization; for more information, see // https://cloud.google.com/storage/docs/json_api/v1/how-tos/performance func (q *Query) SetAttrSelection(attrs []string) error { + // Validate selections. + for _, attr := range attrs { + // If the attr is acceptable for one of the two sets, then it is OK. + // If it is not acceptable for either, then return an error. + // The respective masking implementations ignore unknown attrs which + // makes switching between transports a little easier. + _, okJSON := attrToFieldMap[attr] + _, okGRPC := attrToProtoFieldMap[attr] + + if !okJSON && !okGRPC { + return fmt.Errorf("storage: attr %v is not valid", attr) + } + } + + q.attrSelection = attrs + + return nil +} + +func (q *Query) toFieldSelection() string { + if q == nil || len(q.attrSelection) == 0 { + return "" + } fieldSet := make(map[string]bool) - for _, attr := range attrs { + for _, attr := range q.attrSelection { field, ok := attrToFieldMap[attr] if !ok { - return fmt.Errorf("storage: attr %v is not valid", attr) + // Future proofing, skip unknown fields, let SetAttrSelection handle + // error modes. + continue } fieldSet[field] = true } + var s string if len(fieldSet) > 0 { var b bytes.Buffer - b.WriteString("items(") + b.WriteString("prefixes,items(") first := true for field := range fieldSet { if !first { @@ -1361,9 +1638,50 @@ func (q *Query) SetAttrSelection(attrs []string) error { b.WriteString(field) } b.WriteString(")") - q.fieldSelection = b.String() + s = b.String() } - return nil + return s +} + +func (q *Query) toFieldMask() *fieldmaskpb.FieldMask { + // The default behavior with no Query is ProjectionDefault (i.e. ProjectionFull). + if q == nil { + return &fieldmaskpb.FieldMask{Paths: []string{"*"}} + } + + // User selected attributes via q.SetAttrSeleciton. This takes precedence + // over the Projection. + if numSelected := len(q.attrSelection); numSelected > 0 { + protoFieldPaths := make([]string, 0, numSelected) + + for _, attr := range q.attrSelection { + pf, ok := attrToProtoFieldMap[attr] + if !ok { + // Future proofing, skip unknown fields, let SetAttrSelection + // handle error modes. + continue + } + protoFieldPaths = append(protoFieldPaths, pf) + } + + return &fieldmaskpb.FieldMask{Paths: protoFieldPaths} + } + + // ProjectDefault == ProjectionFull which means all fields. + fm := &fieldmaskpb.FieldMask{Paths: []string{"*"}} + if q.Projection == ProjectionNoACL { + paths := make([]string, 0, len(attrToProtoFieldMap)-2) // omitting two fields + for _, f := range attrToProtoFieldMap { + // Skip the acl and owner fields for "NoACL". + if f == "acl" || f == "owner" { + continue + } + paths = append(paths, f) + } + fm.Paths = paths + } + + return fm } // Conditions constrain methods to act on specific generations of @@ -1507,6 +1825,33 @@ func applySourceConds(gen int64, conds *Conditions, call *raw.ObjectsRewriteCall return nil } +func applySourceCondsProto(gen int64, conds *Conditions, call *storagepb.RewriteObjectRequest) error { + if gen >= 0 { + call.SourceGeneration = gen + } + if conds == nil { + return nil + } + if err := conds.validate("CopyTo source"); err != nil { + return err + } + switch { + case conds.GenerationMatch != 0: + call.IfSourceGenerationMatch = proto.Int64(conds.GenerationMatch) + case conds.GenerationNotMatch != 0: + call.IfSourceGenerationNotMatch = proto.Int64(conds.GenerationNotMatch) + case conds.DoesNotExist: + call.IfSourceGenerationMatch = proto.Int64(0) + } + switch { + case conds.MetagenerationMatch != 0: + call.IfSourceMetagenerationMatch = proto.Int64(conds.MetagenerationMatch) + case conds.MetagenerationNotMatch != 0: + call.IfSourceMetagenerationNotMatch = proto.Int64(conds.MetagenerationNotMatch) + } + return nil +} + // setConditionField sets a field on a *raw.WhateverCall. // We can't use anonymous interfaces because the return type is // different, since the field setters are builders. @@ -1519,42 +1864,168 @@ func setConditionField(call reflect.Value, name string, value interface{}) bool return true } -// conditionsQuery returns the generation and conditions as a URL query -// string suitable for URL.RawQuery. It assumes that the conditions -// have been validated. -func conditionsQuery(gen int64, conds *Conditions) string { - // URL escapes are elided because integer strings are URL-safe. - var buf []byte +// Retryer returns an object handle that is configured with custom retry +// behavior as specified by the options that are passed to it. All operations +// on the new handle will use the customized retry configuration. +// These retry options will merge with the bucket's retryer (if set) for the +// returned handle. Options passed into this method will take precedence over +// retry options on the bucket and client. Note that you must explicitly pass in +// each option you want to override. +func (o *ObjectHandle) Retryer(opts ...RetryOption) *ObjectHandle { + o2 := *o + var retry *retryConfig + if o.retry != nil { + // merge the options with the existing retry + retry = o.retry + } else { + retry = &retryConfig{} + } + for _, opt := range opts { + opt.apply(retry) + } + o2.retry = retry + o2.acl.retry = retry + return &o2 +} - appendParam := func(s string, n int64) { - if len(buf) > 0 { - buf = append(buf, '&') - } - buf = append(buf, s...) - buf = strconv.AppendInt(buf, n, 10) +// SetRetry configures the client with custom retry behavior as specified by the +// options that are passed to it. All operations using this client will use the +// customized retry configuration. +// This should be called once before using the client for network operations, as +// there could be indeterminate behaviour with operations in progress. +// Retry options set on a bucket or object handle will take precedence over +// these options. +func (c *Client) SetRetry(opts ...RetryOption) { + var retry *retryConfig + if c.retry != nil { + // merge the options with the existing retry + retry = c.retry + } else { + retry = &retryConfig{} } + for _, opt := range opts { + opt.apply(retry) + } + c.retry = retry +} - if gen >= 0 { - appendParam("generation=", gen) +// RetryOption allows users to configure non-default retry behavior for API +// calls made to GCS. +type RetryOption interface { + apply(config *retryConfig) +} + +// WithBackoff allows configuration of the backoff timing used for retries. +// Available configuration options (Initial, Max and Multiplier) are described +// at https://pkg.go.dev/github.com/googleapis/gax-go/v2#Backoff. If any fields +// are not supplied by the user, gax default values will be used. +func WithBackoff(backoff gax.Backoff) RetryOption { + return &withBackoff{ + backoff: backoff, } - if conds == nil { - return string(buf) +} + +type withBackoff struct { + backoff gax.Backoff +} + +func (wb *withBackoff) apply(config *retryConfig) { + config.backoff = &wb.backoff +} + +// RetryPolicy describes the available policies for which operations should be +// retried. The default is `RetryIdempotent`. +type RetryPolicy int + +const ( + // RetryIdempotent causes only idempotent operations to be retried when the + // service returns a transient error. Using this policy, fully idempotent + // operations (such as `ObjectHandle.Attrs()`) will always be retried. + // Conditionally idempotent operations (for example `ObjectHandle.Update()`) + // will be retried only if the necessary conditions have been supplied (in + // the case of `ObjectHandle.Update()` this would mean supplying a + // `Conditions.MetagenerationMatch` condition is required). + RetryIdempotent RetryPolicy = iota + + // RetryAlways causes all operations to be retried when the service returns a + // transient error, regardless of idempotency considerations. + RetryAlways + + // RetryNever causes the client to not perform retries on failed operations. + RetryNever +) + +// WithPolicy allows the configuration of which operations should be performed +// with retries for transient errors. +func WithPolicy(policy RetryPolicy) RetryOption { + return &withPolicy{ + policy: policy, } - switch { - case conds.GenerationMatch != 0: - appendParam("ifGenerationMatch=", conds.GenerationMatch) - case conds.GenerationNotMatch != 0: - appendParam("ifGenerationNotMatch=", conds.GenerationNotMatch) - case conds.DoesNotExist: - appendParam("ifGenerationMatch=", 0) +} + +type withPolicy struct { + policy RetryPolicy +} + +func (ws *withPolicy) apply(config *retryConfig) { + config.policy = ws.policy +} + +// WithErrorFunc allows users to pass a custom function to the retryer. Errors +// will be retried if and only if `shouldRetry(err)` returns true. +// By default, the following errors are retried (see ShouldRetry for the default +// function): +// +// - HTTP responses with codes 408, 429, 502, 503, and 504. +// +// - Transient network errors such as connection reset and io.ErrUnexpectedEOF. +// +// - Errors which are considered transient using the Temporary() interface. +// +// - Wrapped versions of these errors. +// +// This option can be used to retry on a different set of errors than the +// default. Users can use the default ShouldRetry function inside their custom +// function if they only want to make minor modifications to default behavior. +func WithErrorFunc(shouldRetry func(err error) bool) RetryOption { + return &withErrorFunc{ + shouldRetry: shouldRetry, } - switch { - case conds.MetagenerationMatch != 0: - appendParam("ifMetagenerationMatch=", conds.MetagenerationMatch) - case conds.MetagenerationNotMatch != 0: - appendParam("ifMetagenerationNotMatch=", conds.MetagenerationNotMatch) +} + +type withErrorFunc struct { + shouldRetry func(err error) bool +} + +func (wef *withErrorFunc) apply(config *retryConfig) { + config.shouldRetry = wef.shouldRetry +} + +type retryConfig struct { + backoff *gax.Backoff + policy RetryPolicy + shouldRetry func(err error) bool +} + +func (r *retryConfig) clone() *retryConfig { + if r == nil { + return nil + } + + var bo *gax.Backoff + if r.backoff != nil { + bo = &gax.Backoff{ + Initial: r.backoff.Initial, + Max: r.backoff.Max, + Multiplier: r.backoff.Multiplier, + } + } + + return &retryConfig{ + backoff: bo, + policy: r.policy, + shouldRetry: r.shouldRetry, } - return string(buf) } // composeSourceObj wraps a *raw.ComposeRequestSourceObjects, but adds the methods @@ -1588,19 +2059,127 @@ func setEncryptionHeaders(headers http.Header, key []byte, copySource bool) erro if copySource { cs = "copy-source-" } - headers.Set("x-goog-"+cs+"encryption-algorithm", "AES256") + headers.Set("x-goog-"+cs+"encryption-algorithm", aes256Algorithm) headers.Set("x-goog-"+cs+"encryption-key", base64.StdEncoding.EncodeToString(key)) keyHash := sha256.Sum256(key) headers.Set("x-goog-"+cs+"encryption-key-sha256", base64.StdEncoding.EncodeToString(keyHash[:])) return nil } +// toProtoCommonObjectRequestParams sets customer-supplied encryption to the proto library's CommonObjectRequestParams. +func toProtoCommonObjectRequestParams(key []byte) *storagepb.CommonObjectRequestParams { + if key == nil { + return nil + } + keyHash := sha256.Sum256(key) + return &storagepb.CommonObjectRequestParams{ + EncryptionAlgorithm: aes256Algorithm, + EncryptionKeyBytes: key, + EncryptionKeySha256Bytes: keyHash[:], + } +} + // ServiceAccount fetches the email address of the given project's Google Cloud Storage service account. func (c *Client) ServiceAccount(ctx context.Context, projectID string) (string, error) { - r := c.raw.Projects.ServiceAccount.Get(projectID) - res, err := r.Context(ctx).Do() - if err != nil { - return "", err + o := makeStorageOpts(true, c.retry, "") + return c.tc.GetServiceAccount(ctx, projectID, o...) + +} + +// bucketResourceName formats the given project ID and bucketResourceName ID +// into a Bucket resource name. This is the format necessary for the gRPC API as +// it conforms to the Resource-oriented design practices in https://google.aip.dev/121. +func bucketResourceName(p, b string) string { + return fmt.Sprintf("projects/%s/buckets/%s", p, b) +} + +// parseBucketName strips the leading resource path segment and returns the +// bucket ID, which is the simple Bucket name typical of the v1 API. +func parseBucketName(b string) string { + sep := strings.LastIndex(b, "/") + return b[sep+1:] +} + +// parseProjectNumber consume the given resource name and parses out the project +// number if one is present i.e. it is not a project ID. +func parseProjectNumber(r string) uint64 { + projectID := regexp.MustCompile(`projects\/([0-9]+)\/?`) + if matches := projectID.FindStringSubmatch(r); len(matches) > 0 { + // Capture group follows the matched segment. For example: + // input: projects/123/bars/456 + // output: [projects/123/, 123] + number, err := strconv.ParseUint(matches[1], 10, 64) + if err != nil { + return 0 + } + return number } - return res.EmailAddress, nil + + return 0 +} + +// toProjectResource accepts a project ID and formats it as a Project resource +// name. +func toProjectResource(project string) string { + return fmt.Sprintf("projects/%s", project) +} + +// setConditionProtoField uses protobuf reflection to set named condition field +// to the given condition value if supported on the protobuf message. +// +// This is an experimental API and not intended for public use. +func setConditionProtoField(m protoreflect.Message, f string, v int64) bool { + fields := m.Descriptor().Fields() + if rf := fields.ByName(protoreflect.Name(f)); rf != nil { + m.Set(rf, protoreflect.ValueOfInt64(v)) + return true + } + + return false +} + +// applyCondsProto validates and attempts to set the conditions on a protobuf +// message using protobuf reflection. +// +// This is an experimental API and not intended for public use. +func applyCondsProto(method string, gen int64, conds *Conditions, msg proto.Message) error { + rmsg := msg.ProtoReflect() + + if gen >= 0 { + if !setConditionProtoField(rmsg, "generation", gen) { + return fmt.Errorf("storage: %s: generation not supported", method) + } + } + if conds == nil { + return nil + } + if err := conds.validate(method); err != nil { + return err + } + + switch { + case conds.GenerationMatch != 0: + if !setConditionProtoField(rmsg, "if_generation_match", conds.GenerationMatch) { + return fmt.Errorf("storage: %s: ifGenerationMatch not supported", method) + } + case conds.GenerationNotMatch != 0: + if !setConditionProtoField(rmsg, "if_generation_not_match", conds.GenerationNotMatch) { + return fmt.Errorf("storage: %s: ifGenerationNotMatch not supported", method) + } + case conds.DoesNotExist: + if !setConditionProtoField(rmsg, "if_generation_match", int64(0)) { + return fmt.Errorf("storage: %s: DoesNotExist not supported", method) + } + } + switch { + case conds.MetagenerationMatch != 0: + if !setConditionProtoField(rmsg, "if_metageneration_match", conds.MetagenerationMatch) { + return fmt.Errorf("storage: %s: ifMetagenerationMatch not supported", method) + } + case conds.MetagenerationNotMatch != 0: + if !setConditionProtoField(rmsg, "if_metageneration_not_match", conds.MetagenerationNotMatch) { + return fmt.Errorf("storage: %s: ifMetagenerationNotMatch not supported", method) + } + } + return nil } diff --git a/vendor/cloud.google.com/go/storage/writer.go b/vendor/cloud.google.com/go/storage/writer.go index 1843a814155..3a6a1ce0f56 100644 --- a/vendor/cloud.google.com/go/storage/writer.go +++ b/vendor/cloud.google.com/go/storage/writer.go @@ -16,15 +16,12 @@ package storage import ( "context" - "encoding/base64" "errors" "fmt" "io" "sync" + "time" "unicode/utf8" - - "google.golang.org/api/googleapi" - raw "google.golang.org/api/storage/v1" ) // A Writer writes a Cloud Storage object. @@ -34,35 +31,61 @@ type Writer struct { // attributes are ignored. ObjectAttrs - // SendCRC specifies whether to transmit a CRC32C field. It should be set + // SendCRC32C specifies whether to transmit a CRC32C field. It should be set // to true in addition to setting the Writer's CRC32C field, because zero // is a valid CRC and normally a zero would not be transmitted. // If a CRC32C is sent, and the data written does not match the checksum, // the write will be rejected. + // + // Note: SendCRC32C must be set to true BEFORE the first call to + // Writer.Write() in order to send the checksum. If it is set after that + // point, the checksum will be ignored. SendCRC32C bool // ChunkSize controls the maximum number of bytes of the object that the // Writer will attempt to send to the server in a single request. Objects // smaller than the size will be sent in a single request, while larger - // objects will be split over multiple requests. The size will be rounded up - // to the nearest multiple of 256K. + // objects will be split over multiple requests. The value will be rounded up + // to the nearest multiple of 256K. The default ChunkSize is 16MiB. + // + // Each Writer will internally allocate a buffer of size ChunkSize. This is + // used to buffer input data and allow for the input to be sent again if a + // request must be retried. // - // ChunkSize will default to a reasonable value. If you perform many - // concurrent writes of small objects (under ~8MB), you may wish set ChunkSize - // to a value that matches your objects' sizes to avoid consuming large - // amounts of memory. See + // If you upload small objects (< 16MiB), you should set ChunkSize + // to a value slightly larger than the objects' sizes to avoid memory bloat. + // This is especially important if you are uploading many small objects + // concurrently. See // https://cloud.google.com/storage/docs/json_api/v1/how-tos/upload#size // for more information about performance trade-offs related to ChunkSize. // // If ChunkSize is set to zero, chunking will be disabled and the object will // be uploaded in a single request without the use of a buffer. This will // further reduce memory used during uploads, but will also prevent the writer - // from retrying in case of a transient error from the server, since a buffer - // is required in order to retry the failed request. + // from retrying in case of a transient error from the server or resuming an + // upload that fails midway through, since the buffer is required in order to + // retry the failed request. // // ChunkSize must be set before the first Write call. ChunkSize int + // ChunkRetryDeadline sets a per-chunk retry deadline for multi-chunk + // resumable uploads. + // + // For uploads of larger files, the Writer will attempt to retry if the + // request to upload a particular chunk fails with a transient error. + // If a single chunk has been attempting to upload for longer than this + // deadline and the request fails, it will no longer be retried, and the error + // will be returned to the caller. This is only applicable for files which are + // large enough to require a multi-chunk resumable upload. The default value + // is 32s. Users may want to pick a longer deadline if they are using larger + // values for ChunkSize or if they expect to have a slow or unreliable + // internet connection. + // + // To set a deadline on the entire upload, use context timeout or + // cancellation. + ChunkRetryDeadline time.Duration + // ProgressFunc can be used to monitor the progress of a large write. // operation. If ProgressFunc is not nil and writing requires multiple // calls to the underlying service (see @@ -86,96 +109,6 @@ type Writer struct { err error } -func (w *Writer) open() error { - attrs := w.ObjectAttrs - // Check the developer didn't change the object Name (this is unfortunate, but - // we don't want to store an object under the wrong name). - if attrs.Name != w.o.object { - return fmt.Errorf("storage: Writer.Name %q does not match object name %q", attrs.Name, w.o.object) - } - if !utf8.ValidString(attrs.Name) { - return fmt.Errorf("storage: object name %q is not valid UTF-8", attrs.Name) - } - if attrs.KMSKeyName != "" && w.o.encryptionKey != nil { - return errors.New("storage: cannot use KMSKeyName with a customer-supplied encryption key") - } - pr, pw := io.Pipe() - w.pw = pw - w.opened = true - - go w.monitorCancel() - - if w.ChunkSize < 0 { - return errors.New("storage: Writer.ChunkSize must be non-negative") - } - mediaOpts := []googleapi.MediaOption{ - googleapi.ChunkSize(w.ChunkSize), - } - if c := attrs.ContentType; c != "" { - mediaOpts = append(mediaOpts, googleapi.ContentType(c)) - } - - go func() { - defer close(w.donec) - - rawObj := attrs.toRawObject(w.o.bucket) - if w.SendCRC32C { - rawObj.Crc32c = encodeUint32(attrs.CRC32C) - } - if w.MD5 != nil { - rawObj.Md5Hash = base64.StdEncoding.EncodeToString(w.MD5) - } - if w.o.c.envHost != "" { - w.o.c.raw.BasePath = fmt.Sprintf("%s://%s", w.o.c.scheme, w.o.c.envHost) - } - call := w.o.c.raw.Objects.Insert(w.o.bucket, rawObj). - Media(pr, mediaOpts...). - Projection("full"). - Context(w.ctx). - Name(w.o.object) - - if w.ProgressFunc != nil { - call.ProgressUpdater(func(n, _ int64) { w.ProgressFunc(n) }) - } - if attrs.KMSKeyName != "" { - call.KmsKeyName(attrs.KMSKeyName) - } - if attrs.PredefinedACL != "" { - call.PredefinedAcl(attrs.PredefinedACL) - } - if err := setEncryptionHeaders(call.Header(), w.o.encryptionKey, false); err != nil { - w.mu.Lock() - w.err = err - w.mu.Unlock() - pr.CloseWithError(err) - return - } - var resp *raw.Object - err := applyConds("NewWriter", w.o.gen, w.o.conds, call) - if err == nil { - if w.o.userProject != "" { - call.UserProject(w.o.userProject) - } - setClientHeader(call.Header()) - - // The internals that perform call.Do automatically retry both the initial - // call to set up the upload as well as calls to upload individual chunks - // for a resumable upload (as long as the chunk size is non-zero). Hence - // there is no need to add retries here. - resp, err = call.Do() - } - if err != nil { - w.mu.Lock() - w.err = err - w.mu.Unlock() - pr.CloseWithError(err) - return - } - w.obj = newObject(resp) - }() - return nil -} - // Write appends to w. It implements the io.Writer interface. // // Since writes happen asynchronously, Write may return a nil @@ -193,7 +126,7 @@ func (w *Writer) Write(p []byte) (n int, err error) { return 0, werr } if !w.opened { - if err := w.open(); err != nil { + if err := w.openWriter(); err != nil { return 0, err } } @@ -205,7 +138,7 @@ func (w *Writer) Write(p []byte) (n int, err error) { // Preserve existing functionality that when context is canceled, Write will return // context.Canceled instead of "io: read/write on closed pipe". This hides the // pipe implementation detail from users and makes Write seem as though it's an RPC. - if werr == context.Canceled || werr == context.DeadlineExceeded { + if errors.Is(werr, context.Canceled) || errors.Is(werr, context.DeadlineExceeded) { return n, werr } } @@ -217,7 +150,7 @@ func (w *Writer) Write(p []byte) (n int, err error) { // can be retrieved by calling Attrs. func (w *Writer) Close() error { if !w.opened { - if err := w.open(); err != nil { + if err := w.openWriter(); err != nil { return err } } @@ -233,6 +166,43 @@ func (w *Writer) Close() error { return w.err } +func (w *Writer) openWriter() (err error) { + if err := w.validateWriteAttrs(); err != nil { + return err + } + if w.o.gen != defaultGen { + return fmt.Errorf("storage: generation not supported on Writer, got %v", w.o.gen) + } + + isIdempotent := w.o.conds != nil && (w.o.conds.GenerationMatch >= 0 || w.o.conds.DoesNotExist == true) + opts := makeStorageOpts(isIdempotent, w.o.retry, w.o.userProject) + params := &openWriterParams{ + ctx: w.ctx, + chunkSize: w.ChunkSize, + chunkRetryDeadline: w.ChunkRetryDeadline, + bucket: w.o.bucket, + attrs: &w.ObjectAttrs, + conds: w.o.conds, + encryptionKey: w.o.encryptionKey, + sendCRC32C: w.SendCRC32C, + donec: w.donec, + setError: w.error, + progress: w.progress, + setObj: func(o *ObjectAttrs) { w.obj = o }, + } + if err := w.ctx.Err(); err != nil { + return err // short-circuit + } + w.pw, err = w.o.c.tc.OpenWriter(params, opts...) + if err != nil { + return err + } + w.opened = true + go w.monitorCancel() + + return nil +} + // monitorCancel is intended to be used as a background goroutine. It monitors the // context, and when it observes that the context has been canceled, it manually // closes things that do not take a context. @@ -266,3 +236,38 @@ func (w *Writer) CloseWithError(err error) error { func (w *Writer) Attrs() *ObjectAttrs { return w.obj } + +func (w *Writer) validateWriteAttrs() error { + attrs := w.ObjectAttrs + // Check the developer didn't change the object Name (this is unfortunate, but + // we don't want to store an object under the wrong name). + if attrs.Name != w.o.object { + return fmt.Errorf("storage: Writer.Name %q does not match object name %q", attrs.Name, w.o.object) + } + if !utf8.ValidString(attrs.Name) { + return fmt.Errorf("storage: object name %q is not valid UTF-8", attrs.Name) + } + if attrs.KMSKeyName != "" && w.o.encryptionKey != nil { + return errors.New("storage: cannot use KMSKeyName with a customer-supplied encryption key") + } + if w.ChunkSize < 0 { + return errors.New("storage: Writer.ChunkSize must be non-negative") + } + return nil +} + +// progress is a convenience wrapper that reports write progress to the Writer +// ProgressFunc if it is set and progress is non-zero. +func (w *Writer) progress(p int64) { + if w.ProgressFunc != nil && p != 0 { + w.ProgressFunc(p) + } +} + +// error acquires the Writer's lock, sets the Writer's err to the given error, +// then relinquishes the lock. +func (w *Writer) error(err error) { + w.mu.Lock() + w.err = err + w.mu.Unlock() +} diff --git a/vendor/cloud.google.com/go/testing.md b/vendor/cloud.google.com/go/testing.md deleted file mode 100644 index 03867d561af..00000000000 --- a/vendor/cloud.google.com/go/testing.md +++ /dev/null @@ -1,236 +0,0 @@ -# Testing Code that depends on Go Client Libraries - -The Go client libraries generated as a part of `cloud.google.com/go` all take -the approach of returning concrete types instead of interfaces. That way, new -fields and methods can be added to the libraries without breaking users. This -document will go over some patterns that can be used to test code that depends -on the Go client libraries. - -## Testing gRPC services using fakes - -*Note*: You can see the full -[example code using a fake here](https://github.com/googleapis/google-cloud-go/tree/master/internal/examples/fake). - -The clients found in `cloud.google.com/go` are gRPC based, with a couple of -notable exceptions being the [`storage`](https://pkg.go.dev/cloud.google.com/go/storage) -and [`bigquery`](https://pkg.go.dev/cloud.google.com/go/bigquery) clients. -Interactions with gRPC services can be faked by serving up your own in-memory -server within your test. One benefit of using this approach is that you don’t -need to define an interface in your runtime code; you can keep using -concrete struct types. You instead define a fake server in your test code. For -example, take a look at the following function: - -```go -import ( - "context" - "fmt" - "log" - "os" - - translate "cloud.google.com/go/translate/apiv3" - "github.com/googleapis/gax-go/v2" - translatepb "google.golang.org/genproto/googleapis/cloud/translate/v3" -) - -func TranslateTextWithConcreteClient(client *translate.TranslationClient, text string, targetLang string) (string, error) { - ctx := context.Background() - log.Printf("Translating %q to %q", text, targetLang) - req := &translatepb.TranslateTextRequest{ - Parent: fmt.Sprintf("projects/%s/locations/global", os.Getenv("GOOGLE_CLOUD_PROJECT")), - TargetLanguageCode: "en-US", - Contents: []string{text}, - } - resp, err := client.TranslateText(ctx, req) - if err != nil { - return "", fmt.Errorf("unable to translate text: %v", err) - } - translations := resp.GetTranslations() - if len(translations) != 1 { - return "", fmt.Errorf("expected only one result, got %d", len(translations)) - } - return translations[0].TranslatedText, nil -} -``` - -Here is an example of what a fake server implementation would look like for -faking the interactions above: - -```go -import ( - "context" - - translatepb "google.golang.org/genproto/googleapis/cloud/translate/v3" -) - -type fakeTranslationServer struct { - translatepb.UnimplementedTranslationServiceServer -} - -func (f *fakeTranslationServer) TranslateText(ctx context.Context, req *translatepb.TranslateTextRequest) (*translatepb.TranslateTextResponse, error) { - resp := &translatepb.TranslateTextResponse{ - Translations: []*translatepb.Translation{ - &translatepb.Translation{ - TranslatedText: "Hello World", - }, - }, - } - return resp, nil -} -``` - -All of the generated protobuf code found in [google.golang.org/genproto](https://pkg.go.dev/google.golang.org/genproto) -contains a similar `package.UnimplmentedFooServer` type that is useful for -creating fakes. By embedding the unimplemented server in the -`fakeTranslationServer`, the fake will “inherit” all of the RPCs the server -exposes. Then, by providing our own `fakeTranslationServer.TranslateText` -method you can “override” the default unimplemented behavior of the one RPC that -you would like to be faked. - -The test itself does require a little bit of setup: start up a `net.Listener`, -register the server, and tell the client library to call the server: - -```go -import ( - "context" - "net" - "testing" - - translate "cloud.google.com/go/translate/apiv3" - "google.golang.org/api/option" - translatepb "google.golang.org/genproto/googleapis/cloud/translate/v3" - "google.golang.org/grpc" -) - -func TestTranslateTextWithConcreteClient(t *testing.T) { - ctx := context.Background() - - // Setup the fake server. - fakeTranslationServer := &fakeTranslationServer{} - l, err := net.Listen("tcp", "localhost:0") - if err != nil { - t.Fatal(err) - } - gsrv := grpc.NewServer() - translatepb.RegisterTranslationServiceServer(gsrv, fakeTranslationServer) - fakeServerAddr := l.Addr().String() - go func() { - if err := gsrv.Serve(l); err != nil { - panic(err) - } - }() - - // Create a client. - client, err := translate.NewTranslationClient(ctx, - option.WithEndpoint(fakeServerAddr), - option.WithoutAuthentication(), - option.WithGRPCDialOption(grpc.WithInsecure()), - ) - if err != nil { - t.Fatal(err) - } - - // Run the test. - text, err := TranslateTextWithConcreteClient(client, "Hola Mundo", "en-US") - if err != nil { - t.Fatal(err) - } - if text != "Hello World" { - t.Fatalf("got %q, want Hello World", text) - } -} -``` - -## Testing using mocks - -*Note*: You can see the full -[example code using a mock here](https://github.com/googleapis/google-cloud-go/tree/master/internal/examples/mock). - -When mocking code you need to work with interfaces. Let’s create an interface -for the `cloud.google.com/go/translate/apiv3` client used in the -`TranslateTextWithConcreteClient` function mentioned in the previous section. -The `translate.Client` has over a dozen methods but this code only uses one of -them. Here is an interface that satisfies the interactions of the -`translate.Client` in this function. - -```go -type TranslationClient interface { - TranslateText(ctx context.Context, req *translatepb.TranslateTextRequest, opts ...gax.CallOption) (*translatepb.TranslateTextResponse, error) -} -``` - -Now that we have an interface that satisfies the method being used we can -rewrite the function signature to take the interface instead of the concrete -type. - -```go -func TranslateTextWithInterfaceClient(client TranslationClient, text string, targetLang string) (string, error) { -// ... -} -``` - -This allows a real `translate.Client` to be passed to the method in production -and for a mock implementation to be passed in during testing. This pattern can -be applied to any Go code, not just `cloud.google.com/go`. This is because -interfaces in Go are implicitly satisfied. Structs in the client libraries can -implicitly implement interfaces defined in your codebase. Let’s take a look at -what it might look like to define a lightweight mock for the `TranslationClient` -interface. - -```go -import ( - "context" - "testing" - - "github.com/googleapis/gax-go/v2" - translatepb "google.golang.org/genproto/googleapis/cloud/translate/v3" -) - -type mockClient struct{} - -func (*mockClient) TranslateText(_ context.Context, req *translatepb.TranslateTextRequest, opts ...gax.CallOption) (*translatepb.TranslateTextResponse, error) { - resp := &translatepb.TranslateTextResponse{ - Translations: []*translatepb.Translation{ - &translatepb.Translation{ - TranslatedText: "Hello World", - }, - }, - } - return resp, nil -} - -func TestTranslateTextWithAbstractClient(t *testing.T) { - client := &mockClient{} - text, err := TranslateTextWithInterfaceClient(client, "Hola Mundo", "en-US") - if err != nil { - t.Fatal(err) - } - if text != "Hello World" { - t.Fatalf("got %q, want Hello World", text) - } -} -``` - -If you prefer to not write your own mocks there are mocking frameworks such as -[golang/mock](https://github.com/golang/mock) which can generate mocks for you -from an interface. As a word of caution though, try to not -[overuse mocks](https://testing.googleblog.com/2013/05/testing-on-toilet-dont-overuse-mocks.html). - -## Testing using emulators - -Some of the client libraries provided in `cloud.google.com/go` support running -against a service emulator. The concept is similar to that of using fakes, -mentioned above, but the server is managed for you. You just need to start it up -and instruct the client library to talk to the emulator by setting a service -specific emulator environment variable. Current services/environment-variables -are: - -- bigtable: `BIGTABLE_EMULATOR_HOST` -- datastore: `DATASTORE_EMULATOR_HOST` -- firestore: `FIRESTORE_EMULATOR_HOST` -- pubsub: `PUBSUB_EMULATOR_HOST` -- spanner: `SPANNER_EMULATOR_HOST` -- storage: `STORAGE_EMULATOR_HOST` - - Although the storage client supports an emulator environment variable there is no official emulator provided by gcloud. - -For more information on emulators please refer to the -[gcloud documentation](https://cloud.google.com/sdk/gcloud/reference/beta/emulators). diff --git a/vendor/cloud.google.com/go/tools.go b/vendor/cloud.google.com/go/tools.go deleted file mode 100644 index da5ca585d48..00000000000 --- a/vendor/cloud.google.com/go/tools.go +++ /dev/null @@ -1,31 +0,0 @@ -// +build tools - -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// This package exists to cause `go mod` and `go get` to believe these tools -// are dependencies, even though they are not runtime dependencies of any -// package (these are tools used by our CI builds). This means they will appear -// in our `go.mod` file, but will not be a part of the build. Also, since the -// build target is something non-existent, these should not be included in any -// binaries. - -package cloud - -import ( - _ "github.com/golang/protobuf/protoc-gen-go" - _ "github.com/jstemmer/go-junit-report" - _ "golang.org/x/lint/golint" - _ "golang.org/x/tools/cmd/goimports" -) diff --git a/vendor/github.com/golang/protobuf/internal/gengogrpc/grpc.go b/vendor/github.com/golang/protobuf/internal/gengogrpc/grpc.go deleted file mode 100644 index fd2f51d8901..00000000000 --- a/vendor/github.com/golang/protobuf/internal/gengogrpc/grpc.go +++ /dev/null @@ -1,398 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package gengogrpc contains the gRPC code generator. -package gengogrpc - -import ( - "fmt" - "strconv" - "strings" - - "google.golang.org/protobuf/compiler/protogen" - - "google.golang.org/protobuf/types/descriptorpb" -) - -const ( - contextPackage = protogen.GoImportPath("context") - grpcPackage = protogen.GoImportPath("google.golang.org/grpc") - codesPackage = protogen.GoImportPath("google.golang.org/grpc/codes") - statusPackage = protogen.GoImportPath("google.golang.org/grpc/status") -) - -// GenerateFile generates a _grpc.pb.go file containing gRPC service definitions. -func GenerateFile(gen *protogen.Plugin, file *protogen.File) *protogen.GeneratedFile { - if len(file.Services) == 0 { - return nil - } - filename := file.GeneratedFilenamePrefix + "_grpc.pb.go" - g := gen.NewGeneratedFile(filename, file.GoImportPath) - g.P("// Code generated by protoc-gen-go-grpc. DO NOT EDIT.") - g.P() - g.P("package ", file.GoPackageName) - g.P() - GenerateFileContent(gen, file, g) - return g -} - -// GenerateFileContent generates the gRPC service definitions, excluding the package statement. -func GenerateFileContent(gen *protogen.Plugin, file *protogen.File, g *protogen.GeneratedFile) { - if len(file.Services) == 0 { - return - } - - // TODO: Remove this. We don't need to include these references any more. - g.P("// Reference imports to suppress errors if they are not otherwise used.") - g.P("var _ ", contextPackage.Ident("Context")) - g.P("var _ ", grpcPackage.Ident("ClientConnInterface")) - g.P() - - g.P("// This is a compile-time assertion to ensure that this generated file") - g.P("// is compatible with the grpc package it is being compiled against.") - g.P("const _ = ", grpcPackage.Ident("SupportPackageIsVersion6")) - g.P() - for _, service := range file.Services { - genService(gen, file, g, service) - } -} - -func genService(gen *protogen.Plugin, file *protogen.File, g *protogen.GeneratedFile, service *protogen.Service) { - clientName := service.GoName + "Client" - - g.P("// ", clientName, " is the client API for ", service.GoName, " service.") - g.P("//") - g.P("// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.") - - // Client interface. - if service.Desc.Options().(*descriptorpb.ServiceOptions).GetDeprecated() { - g.P("//") - g.P(deprecationComment) - } - g.Annotate(clientName, service.Location) - g.P("type ", clientName, " interface {") - for _, method := range service.Methods { - g.Annotate(clientName+"."+method.GoName, method.Location) - if method.Desc.Options().(*descriptorpb.MethodOptions).GetDeprecated() { - g.P(deprecationComment) - } - g.P(method.Comments.Leading, - clientSignature(g, method)) - } - g.P("}") - g.P() - - // Client structure. - g.P("type ", unexport(clientName), " struct {") - g.P("cc ", grpcPackage.Ident("ClientConnInterface")) - g.P("}") - g.P() - - // NewClient factory. - if service.Desc.Options().(*descriptorpb.ServiceOptions).GetDeprecated() { - g.P(deprecationComment) - } - g.P("func New", clientName, " (cc ", grpcPackage.Ident("ClientConnInterface"), ") ", clientName, " {") - g.P("return &", unexport(clientName), "{cc}") - g.P("}") - g.P() - - var methodIndex, streamIndex int - // Client method implementations. - for _, method := range service.Methods { - if !method.Desc.IsStreamingServer() && !method.Desc.IsStreamingClient() { - // Unary RPC method - genClientMethod(gen, file, g, method, methodIndex) - methodIndex++ - } else { - // Streaming RPC method - genClientMethod(gen, file, g, method, streamIndex) - streamIndex++ - } - } - - // Server interface. - serverType := service.GoName + "Server" - g.P("// ", serverType, " is the server API for ", service.GoName, " service.") - if service.Desc.Options().(*descriptorpb.ServiceOptions).GetDeprecated() { - g.P("//") - g.P(deprecationComment) - } - g.Annotate(serverType, service.Location) - g.P("type ", serverType, " interface {") - for _, method := range service.Methods { - g.Annotate(serverType+"."+method.GoName, method.Location) - if method.Desc.Options().(*descriptorpb.MethodOptions).GetDeprecated() { - g.P(deprecationComment) - } - g.P(method.Comments.Leading, - serverSignature(g, method)) - } - g.P("}") - g.P() - - // Server Unimplemented struct for forward compatibility. - g.P("// Unimplemented", serverType, " can be embedded to have forward compatible implementations.") - g.P("type Unimplemented", serverType, " struct {") - g.P("}") - g.P() - for _, method := range service.Methods { - nilArg := "" - if !method.Desc.IsStreamingClient() && !method.Desc.IsStreamingServer() { - nilArg = "nil," - } - g.P("func (*Unimplemented", serverType, ") ", serverSignature(g, method), "{") - g.P("return ", nilArg, statusPackage.Ident("Errorf"), "(", codesPackage.Ident("Unimplemented"), `, "method `, method.GoName, ` not implemented")`) - g.P("}") - } - g.P() - - // Server registration. - if service.Desc.Options().(*descriptorpb.ServiceOptions).GetDeprecated() { - g.P(deprecationComment) - } - serviceDescVar := "_" + service.GoName + "_serviceDesc" - g.P("func Register", service.GoName, "Server(s *", grpcPackage.Ident("Server"), ", srv ", serverType, ") {") - g.P("s.RegisterService(&", serviceDescVar, `, srv)`) - g.P("}") - g.P() - - // Server handler implementations. - var handlerNames []string - for _, method := range service.Methods { - hname := genServerMethod(gen, file, g, method) - handlerNames = append(handlerNames, hname) - } - - // Service descriptor. - g.P("var ", serviceDescVar, " = ", grpcPackage.Ident("ServiceDesc"), " {") - g.P("ServiceName: ", strconv.Quote(string(service.Desc.FullName())), ",") - g.P("HandlerType: (*", serverType, ")(nil),") - g.P("Methods: []", grpcPackage.Ident("MethodDesc"), "{") - for i, method := range service.Methods { - if method.Desc.IsStreamingClient() || method.Desc.IsStreamingServer() { - continue - } - g.P("{") - g.P("MethodName: ", strconv.Quote(string(method.Desc.Name())), ",") - g.P("Handler: ", handlerNames[i], ",") - g.P("},") - } - g.P("},") - g.P("Streams: []", grpcPackage.Ident("StreamDesc"), "{") - for i, method := range service.Methods { - if !method.Desc.IsStreamingClient() && !method.Desc.IsStreamingServer() { - continue - } - g.P("{") - g.P("StreamName: ", strconv.Quote(string(method.Desc.Name())), ",") - g.P("Handler: ", handlerNames[i], ",") - if method.Desc.IsStreamingServer() { - g.P("ServerStreams: true,") - } - if method.Desc.IsStreamingClient() { - g.P("ClientStreams: true,") - } - g.P("},") - } - g.P("},") - g.P("Metadata: \"", file.Desc.Path(), "\",") - g.P("}") - g.P() -} - -func clientSignature(g *protogen.GeneratedFile, method *protogen.Method) string { - s := method.GoName + "(ctx " + g.QualifiedGoIdent(contextPackage.Ident("Context")) - if !method.Desc.IsStreamingClient() { - s += ", in *" + g.QualifiedGoIdent(method.Input.GoIdent) - } - s += ", opts ..." + g.QualifiedGoIdent(grpcPackage.Ident("CallOption")) + ") (" - if !method.Desc.IsStreamingClient() && !method.Desc.IsStreamingServer() { - s += "*" + g.QualifiedGoIdent(method.Output.GoIdent) - } else { - s += method.Parent.GoName + "_" + method.GoName + "Client" - } - s += ", error)" - return s -} - -func genClientMethod(gen *protogen.Plugin, file *protogen.File, g *protogen.GeneratedFile, method *protogen.Method, index int) { - service := method.Parent - sname := fmt.Sprintf("/%s/%s", service.Desc.FullName(), method.Desc.Name()) - - if method.Desc.Options().(*descriptorpb.MethodOptions).GetDeprecated() { - g.P(deprecationComment) - } - g.P("func (c *", unexport(service.GoName), "Client) ", clientSignature(g, method), "{") - if !method.Desc.IsStreamingServer() && !method.Desc.IsStreamingClient() { - g.P("out := new(", method.Output.GoIdent, ")") - g.P(`err := c.cc.Invoke(ctx, "`, sname, `", in, out, opts...)`) - g.P("if err != nil { return nil, err }") - g.P("return out, nil") - g.P("}") - g.P() - return - } - streamType := unexport(service.GoName) + method.GoName + "Client" - serviceDescVar := "_" + service.GoName + "_serviceDesc" - g.P("stream, err := c.cc.NewStream(ctx, &", serviceDescVar, ".Streams[", index, `], "`, sname, `", opts...)`) - g.P("if err != nil { return nil, err }") - g.P("x := &", streamType, "{stream}") - if !method.Desc.IsStreamingClient() { - g.P("if err := x.ClientStream.SendMsg(in); err != nil { return nil, err }") - g.P("if err := x.ClientStream.CloseSend(); err != nil { return nil, err }") - } - g.P("return x, nil") - g.P("}") - g.P() - - genSend := method.Desc.IsStreamingClient() - genRecv := method.Desc.IsStreamingServer() - genCloseAndRecv := !method.Desc.IsStreamingServer() - - // Stream auxiliary types and methods. - g.P("type ", service.GoName, "_", method.GoName, "Client interface {") - if genSend { - g.P("Send(*", method.Input.GoIdent, ") error") - } - if genRecv { - g.P("Recv() (*", method.Output.GoIdent, ", error)") - } - if genCloseAndRecv { - g.P("CloseAndRecv() (*", method.Output.GoIdent, ", error)") - } - g.P(grpcPackage.Ident("ClientStream")) - g.P("}") - g.P() - - g.P("type ", streamType, " struct {") - g.P(grpcPackage.Ident("ClientStream")) - g.P("}") - g.P() - - if genSend { - g.P("func (x *", streamType, ") Send(m *", method.Input.GoIdent, ") error {") - g.P("return x.ClientStream.SendMsg(m)") - g.P("}") - g.P() - } - if genRecv { - g.P("func (x *", streamType, ") Recv() (*", method.Output.GoIdent, ", error) {") - g.P("m := new(", method.Output.GoIdent, ")") - g.P("if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err }") - g.P("return m, nil") - g.P("}") - g.P() - } - if genCloseAndRecv { - g.P("func (x *", streamType, ") CloseAndRecv() (*", method.Output.GoIdent, ", error) {") - g.P("if err := x.ClientStream.CloseSend(); err != nil { return nil, err }") - g.P("m := new(", method.Output.GoIdent, ")") - g.P("if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err }") - g.P("return m, nil") - g.P("}") - g.P() - } -} - -func serverSignature(g *protogen.GeneratedFile, method *protogen.Method) string { - var reqArgs []string - ret := "error" - if !method.Desc.IsStreamingClient() && !method.Desc.IsStreamingServer() { - reqArgs = append(reqArgs, g.QualifiedGoIdent(contextPackage.Ident("Context"))) - ret = "(*" + g.QualifiedGoIdent(method.Output.GoIdent) + ", error)" - } - if !method.Desc.IsStreamingClient() { - reqArgs = append(reqArgs, "*"+g.QualifiedGoIdent(method.Input.GoIdent)) - } - if method.Desc.IsStreamingClient() || method.Desc.IsStreamingServer() { - reqArgs = append(reqArgs, method.Parent.GoName+"_"+method.GoName+"Server") - } - return method.GoName + "(" + strings.Join(reqArgs, ", ") + ") " + ret -} - -func genServerMethod(gen *protogen.Plugin, file *protogen.File, g *protogen.GeneratedFile, method *protogen.Method) string { - service := method.Parent - hname := fmt.Sprintf("_%s_%s_Handler", service.GoName, method.GoName) - - if !method.Desc.IsStreamingClient() && !method.Desc.IsStreamingServer() { - g.P("func ", hname, "(srv interface{}, ctx ", contextPackage.Ident("Context"), ", dec func(interface{}) error, interceptor ", grpcPackage.Ident("UnaryServerInterceptor"), ") (interface{}, error) {") - g.P("in := new(", method.Input.GoIdent, ")") - g.P("if err := dec(in); err != nil { return nil, err }") - g.P("if interceptor == nil { return srv.(", service.GoName, "Server).", method.GoName, "(ctx, in) }") - g.P("info := &", grpcPackage.Ident("UnaryServerInfo"), "{") - g.P("Server: srv,") - g.P("FullMethod: ", strconv.Quote(fmt.Sprintf("/%s/%s", service.Desc.FullName(), method.GoName)), ",") - g.P("}") - g.P("handler := func(ctx ", contextPackage.Ident("Context"), ", req interface{}) (interface{}, error) {") - g.P("return srv.(", service.GoName, "Server).", method.GoName, "(ctx, req.(*", method.Input.GoIdent, "))") - g.P("}") - g.P("return interceptor(ctx, in, info, handler)") - g.P("}") - g.P() - return hname - } - streamType := unexport(service.GoName) + method.GoName + "Server" - g.P("func ", hname, "(srv interface{}, stream ", grpcPackage.Ident("ServerStream"), ") error {") - if !method.Desc.IsStreamingClient() { - g.P("m := new(", method.Input.GoIdent, ")") - g.P("if err := stream.RecvMsg(m); err != nil { return err }") - g.P("return srv.(", service.GoName, "Server).", method.GoName, "(m, &", streamType, "{stream})") - } else { - g.P("return srv.(", service.GoName, "Server).", method.GoName, "(&", streamType, "{stream})") - } - g.P("}") - g.P() - - genSend := method.Desc.IsStreamingServer() - genSendAndClose := !method.Desc.IsStreamingServer() - genRecv := method.Desc.IsStreamingClient() - - // Stream auxiliary types and methods. - g.P("type ", service.GoName, "_", method.GoName, "Server interface {") - if genSend { - g.P("Send(*", method.Output.GoIdent, ") error") - } - if genSendAndClose { - g.P("SendAndClose(*", method.Output.GoIdent, ") error") - } - if genRecv { - g.P("Recv() (*", method.Input.GoIdent, ", error)") - } - g.P(grpcPackage.Ident("ServerStream")) - g.P("}") - g.P() - - g.P("type ", streamType, " struct {") - g.P(grpcPackage.Ident("ServerStream")) - g.P("}") - g.P() - - if genSend { - g.P("func (x *", streamType, ") Send(m *", method.Output.GoIdent, ") error {") - g.P("return x.ServerStream.SendMsg(m)") - g.P("}") - g.P() - } - if genSendAndClose { - g.P("func (x *", streamType, ") SendAndClose(m *", method.Output.GoIdent, ") error {") - g.P("return x.ServerStream.SendMsg(m)") - g.P("}") - g.P() - } - if genRecv { - g.P("func (x *", streamType, ") Recv() (*", method.Input.GoIdent, ", error) {") - g.P("m := new(", method.Input.GoIdent, ")") - g.P("if err := x.ServerStream.RecvMsg(m); err != nil { return nil, err }") - g.P("return m, nil") - g.P("}") - g.P() - } - - return hname -} - -const deprecationComment = "// Deprecated: Do not use." - -func unexport(s string) string { return strings.ToLower(s[:1]) + s[1:] } diff --git a/vendor/github.com/golang/protobuf/jsonpb/decode.go b/vendor/github.com/golang/protobuf/jsonpb/decode.go new file mode 100644 index 00000000000..c6f66f10393 --- /dev/null +++ b/vendor/github.com/golang/protobuf/jsonpb/decode.go @@ -0,0 +1,531 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package jsonpb + +import ( + "encoding/json" + "errors" + "fmt" + "io" + "math" + "reflect" + "strconv" + "strings" + "time" + + "github.com/golang/protobuf/proto" + "google.golang.org/protobuf/encoding/protojson" + protoV2 "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protoreflect" + "google.golang.org/protobuf/reflect/protoregistry" +) + +const wrapJSONUnmarshalV2 = false + +// UnmarshalNext unmarshals the next JSON object from d into m. +func UnmarshalNext(d *json.Decoder, m proto.Message) error { + return new(Unmarshaler).UnmarshalNext(d, m) +} + +// Unmarshal unmarshals a JSON object from r into m. +func Unmarshal(r io.Reader, m proto.Message) error { + return new(Unmarshaler).Unmarshal(r, m) +} + +// UnmarshalString unmarshals a JSON object from s into m. +func UnmarshalString(s string, m proto.Message) error { + return new(Unmarshaler).Unmarshal(strings.NewReader(s), m) +} + +// Unmarshaler is a configurable object for converting from a JSON +// representation to a protocol buffer object. +type Unmarshaler struct { + // AllowUnknownFields specifies whether to allow messages to contain + // unknown JSON fields, as opposed to failing to unmarshal. + AllowUnknownFields bool + + // AnyResolver is used to resolve the google.protobuf.Any well-known type. + // If unset, the global registry is used by default. + AnyResolver AnyResolver +} + +// JSONPBUnmarshaler is implemented by protobuf messages that customize the way +// they are unmarshaled from JSON. Messages that implement this should also +// implement JSONPBMarshaler so that the custom format can be produced. +// +// The JSON unmarshaling must follow the JSON to proto specification: +// +// https://developers.google.com/protocol-buffers/docs/proto3#json +// +// Deprecated: Custom types should implement protobuf reflection instead. +type JSONPBUnmarshaler interface { + UnmarshalJSONPB(*Unmarshaler, []byte) error +} + +// Unmarshal unmarshals a JSON object from r into m. +func (u *Unmarshaler) Unmarshal(r io.Reader, m proto.Message) error { + return u.UnmarshalNext(json.NewDecoder(r), m) +} + +// UnmarshalNext unmarshals the next JSON object from d into m. +func (u *Unmarshaler) UnmarshalNext(d *json.Decoder, m proto.Message) error { + if m == nil { + return errors.New("invalid nil message") + } + + // Parse the next JSON object from the stream. + raw := json.RawMessage{} + if err := d.Decode(&raw); err != nil { + return err + } + + // Check for custom unmarshalers first since they may not properly + // implement protobuf reflection that the logic below relies on. + if jsu, ok := m.(JSONPBUnmarshaler); ok { + return jsu.UnmarshalJSONPB(u, raw) + } + + mr := proto.MessageReflect(m) + + // NOTE: For historical reasons, a top-level null is treated as a noop. + // This is incorrect, but kept for compatibility. + if string(raw) == "null" && mr.Descriptor().FullName() != "google.protobuf.Value" { + return nil + } + + if wrapJSONUnmarshalV2 { + // NOTE: If input message is non-empty, we need to preserve merge semantics + // of the old jsonpb implementation. These semantics are not supported by + // the protobuf JSON specification. + isEmpty := true + mr.Range(func(protoreflect.FieldDescriptor, protoreflect.Value) bool { + isEmpty = false // at least one iteration implies non-empty + return false + }) + if !isEmpty { + // Perform unmarshaling into a newly allocated, empty message. + mr = mr.New() + + // Use a defer to copy all unmarshaled fields into the original message. + dst := proto.MessageReflect(m) + defer mr.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool { + dst.Set(fd, v) + return true + }) + } + + // Unmarshal using the v2 JSON unmarshaler. + opts := protojson.UnmarshalOptions{ + DiscardUnknown: u.AllowUnknownFields, + } + if u.AnyResolver != nil { + opts.Resolver = anyResolver{u.AnyResolver} + } + return opts.Unmarshal(raw, mr.Interface()) + } else { + if err := u.unmarshalMessage(mr, raw); err != nil { + return err + } + return protoV2.CheckInitialized(mr.Interface()) + } +} + +func (u *Unmarshaler) unmarshalMessage(m protoreflect.Message, in []byte) error { + md := m.Descriptor() + fds := md.Fields() + + if jsu, ok := proto.MessageV1(m.Interface()).(JSONPBUnmarshaler); ok { + return jsu.UnmarshalJSONPB(u, in) + } + + if string(in) == "null" && md.FullName() != "google.protobuf.Value" { + return nil + } + + switch wellKnownType(md.FullName()) { + case "Any": + var jsonObject map[string]json.RawMessage + if err := json.Unmarshal(in, &jsonObject); err != nil { + return err + } + + rawTypeURL, ok := jsonObject["@type"] + if !ok { + return errors.New("Any JSON doesn't have '@type'") + } + typeURL, err := unquoteString(string(rawTypeURL)) + if err != nil { + return fmt.Errorf("can't unmarshal Any's '@type': %q", rawTypeURL) + } + m.Set(fds.ByNumber(1), protoreflect.ValueOfString(typeURL)) + + var m2 protoreflect.Message + if u.AnyResolver != nil { + mi, err := u.AnyResolver.Resolve(typeURL) + if err != nil { + return err + } + m2 = proto.MessageReflect(mi) + } else { + mt, err := protoregistry.GlobalTypes.FindMessageByURL(typeURL) + if err != nil { + if err == protoregistry.NotFound { + return fmt.Errorf("could not resolve Any message type: %v", typeURL) + } + return err + } + m2 = mt.New() + } + + if wellKnownType(m2.Descriptor().FullName()) != "" { + rawValue, ok := jsonObject["value"] + if !ok { + return errors.New("Any JSON doesn't have 'value'") + } + if err := u.unmarshalMessage(m2, rawValue); err != nil { + return fmt.Errorf("can't unmarshal Any nested proto %v: %v", typeURL, err) + } + } else { + delete(jsonObject, "@type") + rawJSON, err := json.Marshal(jsonObject) + if err != nil { + return fmt.Errorf("can't generate JSON for Any's nested proto to be unmarshaled: %v", err) + } + if err = u.unmarshalMessage(m2, rawJSON); err != nil { + return fmt.Errorf("can't unmarshal Any nested proto %v: %v", typeURL, err) + } + } + + rawWire, err := protoV2.Marshal(m2.Interface()) + if err != nil { + return fmt.Errorf("can't marshal proto %v into Any.Value: %v", typeURL, err) + } + m.Set(fds.ByNumber(2), protoreflect.ValueOfBytes(rawWire)) + return nil + case "BoolValue", "BytesValue", "StringValue", + "Int32Value", "UInt32Value", "FloatValue", + "Int64Value", "UInt64Value", "DoubleValue": + fd := fds.ByNumber(1) + v, err := u.unmarshalValue(m.NewField(fd), in, fd) + if err != nil { + return err + } + m.Set(fd, v) + return nil + case "Duration": + v, err := unquoteString(string(in)) + if err != nil { + return err + } + d, err := time.ParseDuration(v) + if err != nil { + return fmt.Errorf("bad Duration: %v", err) + } + + sec := d.Nanoseconds() / 1e9 + nsec := d.Nanoseconds() % 1e9 + m.Set(fds.ByNumber(1), protoreflect.ValueOfInt64(int64(sec))) + m.Set(fds.ByNumber(2), protoreflect.ValueOfInt32(int32(nsec))) + return nil + case "Timestamp": + v, err := unquoteString(string(in)) + if err != nil { + return err + } + t, err := time.Parse(time.RFC3339Nano, v) + if err != nil { + return fmt.Errorf("bad Timestamp: %v", err) + } + + sec := t.Unix() + nsec := t.Nanosecond() + m.Set(fds.ByNumber(1), protoreflect.ValueOfInt64(int64(sec))) + m.Set(fds.ByNumber(2), protoreflect.ValueOfInt32(int32(nsec))) + return nil + case "Value": + switch { + case string(in) == "null": + m.Set(fds.ByNumber(1), protoreflect.ValueOfEnum(0)) + case string(in) == "true": + m.Set(fds.ByNumber(4), protoreflect.ValueOfBool(true)) + case string(in) == "false": + m.Set(fds.ByNumber(4), protoreflect.ValueOfBool(false)) + case hasPrefixAndSuffix('"', in, '"'): + s, err := unquoteString(string(in)) + if err != nil { + return fmt.Errorf("unrecognized type for Value %q", in) + } + m.Set(fds.ByNumber(3), protoreflect.ValueOfString(s)) + case hasPrefixAndSuffix('[', in, ']'): + v := m.Mutable(fds.ByNumber(6)) + return u.unmarshalMessage(v.Message(), in) + case hasPrefixAndSuffix('{', in, '}'): + v := m.Mutable(fds.ByNumber(5)) + return u.unmarshalMessage(v.Message(), in) + default: + f, err := strconv.ParseFloat(string(in), 0) + if err != nil { + return fmt.Errorf("unrecognized type for Value %q", in) + } + m.Set(fds.ByNumber(2), protoreflect.ValueOfFloat64(f)) + } + return nil + case "ListValue": + var jsonArray []json.RawMessage + if err := json.Unmarshal(in, &jsonArray); err != nil { + return fmt.Errorf("bad ListValue: %v", err) + } + + lv := m.Mutable(fds.ByNumber(1)).List() + for _, raw := range jsonArray { + ve := lv.NewElement() + if err := u.unmarshalMessage(ve.Message(), raw); err != nil { + return err + } + lv.Append(ve) + } + return nil + case "Struct": + var jsonObject map[string]json.RawMessage + if err := json.Unmarshal(in, &jsonObject); err != nil { + return fmt.Errorf("bad StructValue: %v", err) + } + + mv := m.Mutable(fds.ByNumber(1)).Map() + for key, raw := range jsonObject { + kv := protoreflect.ValueOf(key).MapKey() + vv := mv.NewValue() + if err := u.unmarshalMessage(vv.Message(), raw); err != nil { + return fmt.Errorf("bad value in StructValue for key %q: %v", key, err) + } + mv.Set(kv, vv) + } + return nil + } + + var jsonObject map[string]json.RawMessage + if err := json.Unmarshal(in, &jsonObject); err != nil { + return err + } + + // Handle known fields. + for i := 0; i < fds.Len(); i++ { + fd := fds.Get(i) + if fd.IsWeak() && fd.Message().IsPlaceholder() { + continue // weak reference is not linked in + } + + // Search for any raw JSON value associated with this field. + var raw json.RawMessage + name := string(fd.Name()) + if fd.Kind() == protoreflect.GroupKind { + name = string(fd.Message().Name()) + } + if v, ok := jsonObject[name]; ok { + delete(jsonObject, name) + raw = v + } + name = string(fd.JSONName()) + if v, ok := jsonObject[name]; ok { + delete(jsonObject, name) + raw = v + } + + field := m.NewField(fd) + // Unmarshal the field value. + if raw == nil || (string(raw) == "null" && !isSingularWellKnownValue(fd) && !isSingularJSONPBUnmarshaler(field, fd)) { + continue + } + v, err := u.unmarshalValue(field, raw, fd) + if err != nil { + return err + } + m.Set(fd, v) + } + + // Handle extension fields. + for name, raw := range jsonObject { + if !strings.HasPrefix(name, "[") || !strings.HasSuffix(name, "]") { + continue + } + + // Resolve the extension field by name. + xname := protoreflect.FullName(name[len("[") : len(name)-len("]")]) + xt, _ := protoregistry.GlobalTypes.FindExtensionByName(xname) + if xt == nil && isMessageSet(md) { + xt, _ = protoregistry.GlobalTypes.FindExtensionByName(xname.Append("message_set_extension")) + } + if xt == nil { + continue + } + delete(jsonObject, name) + fd := xt.TypeDescriptor() + if fd.ContainingMessage().FullName() != m.Descriptor().FullName() { + return fmt.Errorf("extension field %q does not extend message %q", xname, m.Descriptor().FullName()) + } + + field := m.NewField(fd) + // Unmarshal the field value. + if raw == nil || (string(raw) == "null" && !isSingularWellKnownValue(fd) && !isSingularJSONPBUnmarshaler(field, fd)) { + continue + } + v, err := u.unmarshalValue(field, raw, fd) + if err != nil { + return err + } + m.Set(fd, v) + } + + if !u.AllowUnknownFields && len(jsonObject) > 0 { + for name := range jsonObject { + return fmt.Errorf("unknown field %q in %v", name, md.FullName()) + } + } + return nil +} + +func isSingularWellKnownValue(fd protoreflect.FieldDescriptor) bool { + if fd.Cardinality() == protoreflect.Repeated { + return false + } + if md := fd.Message(); md != nil { + return md.FullName() == "google.protobuf.Value" + } + if ed := fd.Enum(); ed != nil { + return ed.FullName() == "google.protobuf.NullValue" + } + return false +} + +func isSingularJSONPBUnmarshaler(v protoreflect.Value, fd protoreflect.FieldDescriptor) bool { + if fd.Message() != nil && fd.Cardinality() != protoreflect.Repeated { + _, ok := proto.MessageV1(v.Interface()).(JSONPBUnmarshaler) + return ok + } + return false +} + +func (u *Unmarshaler) unmarshalValue(v protoreflect.Value, in []byte, fd protoreflect.FieldDescriptor) (protoreflect.Value, error) { + switch { + case fd.IsList(): + var jsonArray []json.RawMessage + if err := json.Unmarshal(in, &jsonArray); err != nil { + return v, err + } + lv := v.List() + for _, raw := range jsonArray { + ve, err := u.unmarshalSingularValue(lv.NewElement(), raw, fd) + if err != nil { + return v, err + } + lv.Append(ve) + } + return v, nil + case fd.IsMap(): + var jsonObject map[string]json.RawMessage + if err := json.Unmarshal(in, &jsonObject); err != nil { + return v, err + } + kfd := fd.MapKey() + vfd := fd.MapValue() + mv := v.Map() + for key, raw := range jsonObject { + var kv protoreflect.MapKey + if kfd.Kind() == protoreflect.StringKind { + kv = protoreflect.ValueOf(key).MapKey() + } else { + v, err := u.unmarshalSingularValue(kfd.Default(), []byte(key), kfd) + if err != nil { + return v, err + } + kv = v.MapKey() + } + + vv, err := u.unmarshalSingularValue(mv.NewValue(), raw, vfd) + if err != nil { + return v, err + } + mv.Set(kv, vv) + } + return v, nil + default: + return u.unmarshalSingularValue(v, in, fd) + } +} + +var nonFinite = map[string]float64{ + `"NaN"`: math.NaN(), + `"Infinity"`: math.Inf(+1), + `"-Infinity"`: math.Inf(-1), +} + +func (u *Unmarshaler) unmarshalSingularValue(v protoreflect.Value, in []byte, fd protoreflect.FieldDescriptor) (protoreflect.Value, error) { + switch fd.Kind() { + case protoreflect.BoolKind: + return unmarshalValue(in, new(bool)) + case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind: + return unmarshalValue(trimQuote(in), new(int32)) + case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: + return unmarshalValue(trimQuote(in), new(int64)) + case protoreflect.Uint32Kind, protoreflect.Fixed32Kind: + return unmarshalValue(trimQuote(in), new(uint32)) + case protoreflect.Uint64Kind, protoreflect.Fixed64Kind: + return unmarshalValue(trimQuote(in), new(uint64)) + case protoreflect.FloatKind: + if f, ok := nonFinite[string(in)]; ok { + return protoreflect.ValueOfFloat32(float32(f)), nil + } + return unmarshalValue(trimQuote(in), new(float32)) + case protoreflect.DoubleKind: + if f, ok := nonFinite[string(in)]; ok { + return protoreflect.ValueOfFloat64(float64(f)), nil + } + return unmarshalValue(trimQuote(in), new(float64)) + case protoreflect.StringKind: + return unmarshalValue(in, new(string)) + case protoreflect.BytesKind: + return unmarshalValue(in, new([]byte)) + case protoreflect.EnumKind: + if hasPrefixAndSuffix('"', in, '"') { + vd := fd.Enum().Values().ByName(protoreflect.Name(trimQuote(in))) + if vd == nil { + return v, fmt.Errorf("unknown value %q for enum %s", in, fd.Enum().FullName()) + } + return protoreflect.ValueOfEnum(vd.Number()), nil + } + return unmarshalValue(in, new(protoreflect.EnumNumber)) + case protoreflect.MessageKind, protoreflect.GroupKind: + err := u.unmarshalMessage(v.Message(), in) + return v, err + default: + panic(fmt.Sprintf("invalid kind %v", fd.Kind())) + } +} + +func unmarshalValue(in []byte, v interface{}) (protoreflect.Value, error) { + err := json.Unmarshal(in, v) + return protoreflect.ValueOf(reflect.ValueOf(v).Elem().Interface()), err +} + +func unquoteString(in string) (out string, err error) { + err = json.Unmarshal([]byte(in), &out) + return out, err +} + +func hasPrefixAndSuffix(prefix byte, in []byte, suffix byte) bool { + if len(in) >= 2 && in[0] == prefix && in[len(in)-1] == suffix { + return true + } + return false +} + +// trimQuote is like unquoteString but simply strips surrounding quotes. +// This is incorrect, but is behavior done by the legacy implementation. +func trimQuote(in []byte) []byte { + if len(in) >= 2 && in[0] == '"' && in[len(in)-1] == '"' { + in = in[1 : len(in)-1] + } + return in +} diff --git a/vendor/github.com/golang/protobuf/jsonpb/encode.go b/vendor/github.com/golang/protobuf/jsonpb/encode.go new file mode 100644 index 00000000000..e9438a93f33 --- /dev/null +++ b/vendor/github.com/golang/protobuf/jsonpb/encode.go @@ -0,0 +1,560 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package jsonpb + +import ( + "encoding/json" + "errors" + "fmt" + "io" + "math" + "reflect" + "sort" + "strconv" + "strings" + "time" + + "github.com/golang/protobuf/proto" + "google.golang.org/protobuf/encoding/protojson" + protoV2 "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protoreflect" + "google.golang.org/protobuf/reflect/protoregistry" +) + +const wrapJSONMarshalV2 = false + +// Marshaler is a configurable object for marshaling protocol buffer messages +// to the specified JSON representation. +type Marshaler struct { + // OrigName specifies whether to use the original protobuf name for fields. + OrigName bool + + // EnumsAsInts specifies whether to render enum values as integers, + // as opposed to string values. + EnumsAsInts bool + + // EmitDefaults specifies whether to render fields with zero values. + EmitDefaults bool + + // Indent controls whether the output is compact or not. + // If empty, the output is compact JSON. Otherwise, every JSON object + // entry and JSON array value will be on its own line. + // Each line will be preceded by repeated copies of Indent, where the + // number of copies is the current indentation depth. + Indent string + + // AnyResolver is used to resolve the google.protobuf.Any well-known type. + // If unset, the global registry is used by default. + AnyResolver AnyResolver +} + +// JSONPBMarshaler is implemented by protobuf messages that customize the +// way they are marshaled to JSON. Messages that implement this should also +// implement JSONPBUnmarshaler so that the custom format can be parsed. +// +// The JSON marshaling must follow the proto to JSON specification: +// +// https://developers.google.com/protocol-buffers/docs/proto3#json +// +// Deprecated: Custom types should implement protobuf reflection instead. +type JSONPBMarshaler interface { + MarshalJSONPB(*Marshaler) ([]byte, error) +} + +// Marshal serializes a protobuf message as JSON into w. +func (jm *Marshaler) Marshal(w io.Writer, m proto.Message) error { + b, err := jm.marshal(m) + if len(b) > 0 { + if _, err := w.Write(b); err != nil { + return err + } + } + return err +} + +// MarshalToString serializes a protobuf message as JSON in string form. +func (jm *Marshaler) MarshalToString(m proto.Message) (string, error) { + b, err := jm.marshal(m) + if err != nil { + return "", err + } + return string(b), nil +} + +func (jm *Marshaler) marshal(m proto.Message) ([]byte, error) { + v := reflect.ValueOf(m) + if m == nil || (v.Kind() == reflect.Ptr && v.IsNil()) { + return nil, errors.New("Marshal called with nil") + } + + // Check for custom marshalers first since they may not properly + // implement protobuf reflection that the logic below relies on. + if jsm, ok := m.(JSONPBMarshaler); ok { + return jsm.MarshalJSONPB(jm) + } + + if wrapJSONMarshalV2 { + opts := protojson.MarshalOptions{ + UseProtoNames: jm.OrigName, + UseEnumNumbers: jm.EnumsAsInts, + EmitUnpopulated: jm.EmitDefaults, + Indent: jm.Indent, + } + if jm.AnyResolver != nil { + opts.Resolver = anyResolver{jm.AnyResolver} + } + return opts.Marshal(proto.MessageReflect(m).Interface()) + } else { + // Check for unpopulated required fields first. + m2 := proto.MessageReflect(m) + if err := protoV2.CheckInitialized(m2.Interface()); err != nil { + return nil, err + } + + w := jsonWriter{Marshaler: jm} + err := w.marshalMessage(m2, "", "") + return w.buf, err + } +} + +type jsonWriter struct { + *Marshaler + buf []byte +} + +func (w *jsonWriter) write(s string) { + w.buf = append(w.buf, s...) +} + +func (w *jsonWriter) marshalMessage(m protoreflect.Message, indent, typeURL string) error { + if jsm, ok := proto.MessageV1(m.Interface()).(JSONPBMarshaler); ok { + b, err := jsm.MarshalJSONPB(w.Marshaler) + if err != nil { + return err + } + if typeURL != "" { + // we are marshaling this object to an Any type + var js map[string]*json.RawMessage + if err = json.Unmarshal(b, &js); err != nil { + return fmt.Errorf("type %T produced invalid JSON: %v", m.Interface(), err) + } + turl, err := json.Marshal(typeURL) + if err != nil { + return fmt.Errorf("failed to marshal type URL %q to JSON: %v", typeURL, err) + } + js["@type"] = (*json.RawMessage)(&turl) + if b, err = json.Marshal(js); err != nil { + return err + } + } + w.write(string(b)) + return nil + } + + md := m.Descriptor() + fds := md.Fields() + + // Handle well-known types. + const secondInNanos = int64(time.Second / time.Nanosecond) + switch wellKnownType(md.FullName()) { + case "Any": + return w.marshalAny(m, indent) + case "BoolValue", "BytesValue", "StringValue", + "Int32Value", "UInt32Value", "FloatValue", + "Int64Value", "UInt64Value", "DoubleValue": + fd := fds.ByNumber(1) + return w.marshalValue(fd, m.Get(fd), indent) + case "Duration": + const maxSecondsInDuration = 315576000000 + // "Generated output always contains 0, 3, 6, or 9 fractional digits, + // depending on required precision." + s := m.Get(fds.ByNumber(1)).Int() + ns := m.Get(fds.ByNumber(2)).Int() + if s < -maxSecondsInDuration || s > maxSecondsInDuration { + return fmt.Errorf("seconds out of range %v", s) + } + if ns <= -secondInNanos || ns >= secondInNanos { + return fmt.Errorf("ns out of range (%v, %v)", -secondInNanos, secondInNanos) + } + if (s > 0 && ns < 0) || (s < 0 && ns > 0) { + return errors.New("signs of seconds and nanos do not match") + } + var sign string + if s < 0 || ns < 0 { + sign, s, ns = "-", -1*s, -1*ns + } + x := fmt.Sprintf("%s%d.%09d", sign, s, ns) + x = strings.TrimSuffix(x, "000") + x = strings.TrimSuffix(x, "000") + x = strings.TrimSuffix(x, ".000") + w.write(fmt.Sprintf(`"%vs"`, x)) + return nil + case "Timestamp": + // "RFC 3339, where generated output will always be Z-normalized + // and uses 0, 3, 6 or 9 fractional digits." + s := m.Get(fds.ByNumber(1)).Int() + ns := m.Get(fds.ByNumber(2)).Int() + if ns < 0 || ns >= secondInNanos { + return fmt.Errorf("ns out of range [0, %v)", secondInNanos) + } + t := time.Unix(s, ns).UTC() + // time.RFC3339Nano isn't exactly right (we need to get 3/6/9 fractional digits). + x := t.Format("2006-01-02T15:04:05.000000000") + x = strings.TrimSuffix(x, "000") + x = strings.TrimSuffix(x, "000") + x = strings.TrimSuffix(x, ".000") + w.write(fmt.Sprintf(`"%vZ"`, x)) + return nil + case "Value": + // JSON value; which is a null, number, string, bool, object, or array. + od := md.Oneofs().Get(0) + fd := m.WhichOneof(od) + if fd == nil { + return errors.New("nil Value") + } + return w.marshalValue(fd, m.Get(fd), indent) + case "Struct", "ListValue": + // JSON object or array. + fd := fds.ByNumber(1) + return w.marshalValue(fd, m.Get(fd), indent) + } + + w.write("{") + if w.Indent != "" { + w.write("\n") + } + + firstField := true + if typeURL != "" { + if err := w.marshalTypeURL(indent, typeURL); err != nil { + return err + } + firstField = false + } + + for i := 0; i < fds.Len(); { + fd := fds.Get(i) + if od := fd.ContainingOneof(); od != nil { + fd = m.WhichOneof(od) + i += od.Fields().Len() + if fd == nil { + continue + } + } else { + i++ + } + + v := m.Get(fd) + + if !m.Has(fd) { + if !w.EmitDefaults || fd.ContainingOneof() != nil { + continue + } + if fd.Cardinality() != protoreflect.Repeated && (fd.Message() != nil || fd.Syntax() == protoreflect.Proto2) { + v = protoreflect.Value{} // use "null" for singular messages or proto2 scalars + } + } + + if !firstField { + w.writeComma() + } + if err := w.marshalField(fd, v, indent); err != nil { + return err + } + firstField = false + } + + // Handle proto2 extensions. + if md.ExtensionRanges().Len() > 0 { + // Collect a sorted list of all extension descriptor and values. + type ext struct { + desc protoreflect.FieldDescriptor + val protoreflect.Value + } + var exts []ext + m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool { + if fd.IsExtension() { + exts = append(exts, ext{fd, v}) + } + return true + }) + sort.Slice(exts, func(i, j int) bool { + return exts[i].desc.Number() < exts[j].desc.Number() + }) + + for _, ext := range exts { + if !firstField { + w.writeComma() + } + if err := w.marshalField(ext.desc, ext.val, indent); err != nil { + return err + } + firstField = false + } + } + + if w.Indent != "" { + w.write("\n") + w.write(indent) + } + w.write("}") + return nil +} + +func (w *jsonWriter) writeComma() { + if w.Indent != "" { + w.write(",\n") + } else { + w.write(",") + } +} + +func (w *jsonWriter) marshalAny(m protoreflect.Message, indent string) error { + // "If the Any contains a value that has a special JSON mapping, + // it will be converted as follows: {"@type": xxx, "value": yyy}. + // Otherwise, the value will be converted into a JSON object, + // and the "@type" field will be inserted to indicate the actual data type." + md := m.Descriptor() + typeURL := m.Get(md.Fields().ByNumber(1)).String() + rawVal := m.Get(md.Fields().ByNumber(2)).Bytes() + + var m2 protoreflect.Message + if w.AnyResolver != nil { + mi, err := w.AnyResolver.Resolve(typeURL) + if err != nil { + return err + } + m2 = proto.MessageReflect(mi) + } else { + mt, err := protoregistry.GlobalTypes.FindMessageByURL(typeURL) + if err != nil { + return err + } + m2 = mt.New() + } + + if err := protoV2.Unmarshal(rawVal, m2.Interface()); err != nil { + return err + } + + if wellKnownType(m2.Descriptor().FullName()) == "" { + return w.marshalMessage(m2, indent, typeURL) + } + + w.write("{") + if w.Indent != "" { + w.write("\n") + } + if err := w.marshalTypeURL(indent, typeURL); err != nil { + return err + } + w.writeComma() + if w.Indent != "" { + w.write(indent) + w.write(w.Indent) + w.write(`"value": `) + } else { + w.write(`"value":`) + } + if err := w.marshalMessage(m2, indent+w.Indent, ""); err != nil { + return err + } + if w.Indent != "" { + w.write("\n") + w.write(indent) + } + w.write("}") + return nil +} + +func (w *jsonWriter) marshalTypeURL(indent, typeURL string) error { + if w.Indent != "" { + w.write(indent) + w.write(w.Indent) + } + w.write(`"@type":`) + if w.Indent != "" { + w.write(" ") + } + b, err := json.Marshal(typeURL) + if err != nil { + return err + } + w.write(string(b)) + return nil +} + +// marshalField writes field description and value to the Writer. +func (w *jsonWriter) marshalField(fd protoreflect.FieldDescriptor, v protoreflect.Value, indent string) error { + if w.Indent != "" { + w.write(indent) + w.write(w.Indent) + } + w.write(`"`) + switch { + case fd.IsExtension(): + // For message set, use the fname of the message as the extension name. + name := string(fd.FullName()) + if isMessageSet(fd.ContainingMessage()) { + name = strings.TrimSuffix(name, ".message_set_extension") + } + + w.write("[" + name + "]") + case w.OrigName: + name := string(fd.Name()) + if fd.Kind() == protoreflect.GroupKind { + name = string(fd.Message().Name()) + } + w.write(name) + default: + w.write(string(fd.JSONName())) + } + w.write(`":`) + if w.Indent != "" { + w.write(" ") + } + return w.marshalValue(fd, v, indent) +} + +func (w *jsonWriter) marshalValue(fd protoreflect.FieldDescriptor, v protoreflect.Value, indent string) error { + switch { + case fd.IsList(): + w.write("[") + comma := "" + lv := v.List() + for i := 0; i < lv.Len(); i++ { + w.write(comma) + if w.Indent != "" { + w.write("\n") + w.write(indent) + w.write(w.Indent) + w.write(w.Indent) + } + if err := w.marshalSingularValue(fd, lv.Get(i), indent+w.Indent); err != nil { + return err + } + comma = "," + } + if w.Indent != "" { + w.write("\n") + w.write(indent) + w.write(w.Indent) + } + w.write("]") + return nil + case fd.IsMap(): + kfd := fd.MapKey() + vfd := fd.MapValue() + mv := v.Map() + + // Collect a sorted list of all map keys and values. + type entry struct{ key, val protoreflect.Value } + var entries []entry + mv.Range(func(k protoreflect.MapKey, v protoreflect.Value) bool { + entries = append(entries, entry{k.Value(), v}) + return true + }) + sort.Slice(entries, func(i, j int) bool { + switch kfd.Kind() { + case protoreflect.BoolKind: + return !entries[i].key.Bool() && entries[j].key.Bool() + case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind, protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: + return entries[i].key.Int() < entries[j].key.Int() + case protoreflect.Uint32Kind, protoreflect.Fixed32Kind, protoreflect.Uint64Kind, protoreflect.Fixed64Kind: + return entries[i].key.Uint() < entries[j].key.Uint() + case protoreflect.StringKind: + return entries[i].key.String() < entries[j].key.String() + default: + panic("invalid kind") + } + }) + + w.write(`{`) + comma := "" + for _, entry := range entries { + w.write(comma) + if w.Indent != "" { + w.write("\n") + w.write(indent) + w.write(w.Indent) + w.write(w.Indent) + } + + s := fmt.Sprint(entry.key.Interface()) + b, err := json.Marshal(s) + if err != nil { + return err + } + w.write(string(b)) + + w.write(`:`) + if w.Indent != "" { + w.write(` `) + } + + if err := w.marshalSingularValue(vfd, entry.val, indent+w.Indent); err != nil { + return err + } + comma = "," + } + if w.Indent != "" { + w.write("\n") + w.write(indent) + w.write(w.Indent) + } + w.write(`}`) + return nil + default: + return w.marshalSingularValue(fd, v, indent) + } +} + +func (w *jsonWriter) marshalSingularValue(fd protoreflect.FieldDescriptor, v protoreflect.Value, indent string) error { + switch { + case !v.IsValid(): + w.write("null") + return nil + case fd.Message() != nil: + return w.marshalMessage(v.Message(), indent+w.Indent, "") + case fd.Enum() != nil: + if fd.Enum().FullName() == "google.protobuf.NullValue" { + w.write("null") + return nil + } + + vd := fd.Enum().Values().ByNumber(v.Enum()) + if vd == nil || w.EnumsAsInts { + w.write(strconv.Itoa(int(v.Enum()))) + } else { + w.write(`"` + string(vd.Name()) + `"`) + } + return nil + default: + switch v.Interface().(type) { + case float32, float64: + switch { + case math.IsInf(v.Float(), +1): + w.write(`"Infinity"`) + return nil + case math.IsInf(v.Float(), -1): + w.write(`"-Infinity"`) + return nil + case math.IsNaN(v.Float()): + w.write(`"NaN"`) + return nil + } + case int64, uint64: + w.write(fmt.Sprintf(`"%d"`, v.Interface())) + return nil + } + + b, err := json.Marshal(v.Interface()) + if err != nil { + return err + } + w.write(string(b)) + return nil + } +} diff --git a/vendor/github.com/golang/protobuf/jsonpb/json.go b/vendor/github.com/golang/protobuf/jsonpb/json.go new file mode 100644 index 00000000000..480e2448de6 --- /dev/null +++ b/vendor/github.com/golang/protobuf/jsonpb/json.go @@ -0,0 +1,69 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package jsonpb provides functionality to marshal and unmarshal between a +// protocol buffer message and JSON. It follows the specification at +// https://developers.google.com/protocol-buffers/docs/proto3#json. +// +// Do not rely on the default behavior of the standard encoding/json package +// when called on generated message types as it does not operate correctly. +// +// Deprecated: Use the "google.golang.org/protobuf/encoding/protojson" +// package instead. +package jsonpb + +import ( + "github.com/golang/protobuf/proto" + "google.golang.org/protobuf/reflect/protoreflect" + "google.golang.org/protobuf/reflect/protoregistry" + "google.golang.org/protobuf/runtime/protoimpl" +) + +// AnyResolver takes a type URL, present in an Any message, +// and resolves it into an instance of the associated message. +type AnyResolver interface { + Resolve(typeURL string) (proto.Message, error) +} + +type anyResolver struct{ AnyResolver } + +func (r anyResolver) FindMessageByName(message protoreflect.FullName) (protoreflect.MessageType, error) { + return r.FindMessageByURL(string(message)) +} + +func (r anyResolver) FindMessageByURL(url string) (protoreflect.MessageType, error) { + m, err := r.Resolve(url) + if err != nil { + return nil, err + } + return protoimpl.X.MessageTypeOf(m), nil +} + +func (r anyResolver) FindExtensionByName(field protoreflect.FullName) (protoreflect.ExtensionType, error) { + return protoregistry.GlobalTypes.FindExtensionByName(field) +} + +func (r anyResolver) FindExtensionByNumber(message protoreflect.FullName, field protoreflect.FieldNumber) (protoreflect.ExtensionType, error) { + return protoregistry.GlobalTypes.FindExtensionByNumber(message, field) +} + +func wellKnownType(s protoreflect.FullName) string { + if s.Parent() == "google.protobuf" { + switch s.Name() { + case "Empty", "Any", + "BoolValue", "BytesValue", "StringValue", + "Int32Value", "UInt32Value", "FloatValue", + "Int64Value", "UInt64Value", "DoubleValue", + "Duration", "Timestamp", + "NullValue", "Struct", "Value", "ListValue": + return string(s.Name()) + } + } + return "" +} + +func isMessageSet(md protoreflect.MessageDescriptor) bool { + ms, ok := md.(interface{ IsMessageSet() bool }) + return ok && ms.IsMessageSet() +} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.pb.go b/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.pb.go deleted file mode 100644 index a5a138613ac..00000000000 --- a/vendor/github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.pb.go +++ /dev/null @@ -1,324 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: github.com/golang/protobuf/protoc-gen-go/descriptor/descriptor.proto - -package descriptor - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - descriptorpb "google.golang.org/protobuf/types/descriptorpb" - reflect "reflect" -) - -// Symbols defined in public import of google/protobuf/descriptor.proto. - -type Edition = descriptorpb.Edition - -const Edition_EDITION_UNKNOWN = descriptorpb.Edition_EDITION_UNKNOWN -const Edition_EDITION_PROTO2 = descriptorpb.Edition_EDITION_PROTO2 -const Edition_EDITION_PROTO3 = descriptorpb.Edition_EDITION_PROTO3 -const Edition_EDITION_2023 = descriptorpb.Edition_EDITION_2023 -const Edition_EDITION_2024 = descriptorpb.Edition_EDITION_2024 -const Edition_EDITION_1_TEST_ONLY = descriptorpb.Edition_EDITION_1_TEST_ONLY -const Edition_EDITION_2_TEST_ONLY = descriptorpb.Edition_EDITION_2_TEST_ONLY -const Edition_EDITION_99997_TEST_ONLY = descriptorpb.Edition_EDITION_99997_TEST_ONLY -const Edition_EDITION_99998_TEST_ONLY = descriptorpb.Edition_EDITION_99998_TEST_ONLY -const Edition_EDITION_99999_TEST_ONLY = descriptorpb.Edition_EDITION_99999_TEST_ONLY -const Edition_EDITION_MAX = descriptorpb.Edition_EDITION_MAX - -var Edition_name = descriptorpb.Edition_name -var Edition_value = descriptorpb.Edition_value - -type ExtensionRangeOptions_VerificationState = descriptorpb.ExtensionRangeOptions_VerificationState - -const ExtensionRangeOptions_DECLARATION = descriptorpb.ExtensionRangeOptions_DECLARATION -const ExtensionRangeOptions_UNVERIFIED = descriptorpb.ExtensionRangeOptions_UNVERIFIED - -var ExtensionRangeOptions_VerificationState_name = descriptorpb.ExtensionRangeOptions_VerificationState_name -var ExtensionRangeOptions_VerificationState_value = descriptorpb.ExtensionRangeOptions_VerificationState_value - -type FieldDescriptorProto_Type = descriptorpb.FieldDescriptorProto_Type - -const FieldDescriptorProto_TYPE_DOUBLE = descriptorpb.FieldDescriptorProto_TYPE_DOUBLE -const FieldDescriptorProto_TYPE_FLOAT = descriptorpb.FieldDescriptorProto_TYPE_FLOAT -const FieldDescriptorProto_TYPE_INT64 = descriptorpb.FieldDescriptorProto_TYPE_INT64 -const FieldDescriptorProto_TYPE_UINT64 = descriptorpb.FieldDescriptorProto_TYPE_UINT64 -const FieldDescriptorProto_TYPE_INT32 = descriptorpb.FieldDescriptorProto_TYPE_INT32 -const FieldDescriptorProto_TYPE_FIXED64 = descriptorpb.FieldDescriptorProto_TYPE_FIXED64 -const FieldDescriptorProto_TYPE_FIXED32 = descriptorpb.FieldDescriptorProto_TYPE_FIXED32 -const FieldDescriptorProto_TYPE_BOOL = descriptorpb.FieldDescriptorProto_TYPE_BOOL -const FieldDescriptorProto_TYPE_STRING = descriptorpb.FieldDescriptorProto_TYPE_STRING -const FieldDescriptorProto_TYPE_GROUP = descriptorpb.FieldDescriptorProto_TYPE_GROUP -const FieldDescriptorProto_TYPE_MESSAGE = descriptorpb.FieldDescriptorProto_TYPE_MESSAGE -const FieldDescriptorProto_TYPE_BYTES = descriptorpb.FieldDescriptorProto_TYPE_BYTES -const FieldDescriptorProto_TYPE_UINT32 = descriptorpb.FieldDescriptorProto_TYPE_UINT32 -const FieldDescriptorProto_TYPE_ENUM = descriptorpb.FieldDescriptorProto_TYPE_ENUM -const FieldDescriptorProto_TYPE_SFIXED32 = descriptorpb.FieldDescriptorProto_TYPE_SFIXED32 -const FieldDescriptorProto_TYPE_SFIXED64 = descriptorpb.FieldDescriptorProto_TYPE_SFIXED64 -const FieldDescriptorProto_TYPE_SINT32 = descriptorpb.FieldDescriptorProto_TYPE_SINT32 -const FieldDescriptorProto_TYPE_SINT64 = descriptorpb.FieldDescriptorProto_TYPE_SINT64 - -var FieldDescriptorProto_Type_name = descriptorpb.FieldDescriptorProto_Type_name -var FieldDescriptorProto_Type_value = descriptorpb.FieldDescriptorProto_Type_value - -type FieldDescriptorProto_Label = descriptorpb.FieldDescriptorProto_Label - -const FieldDescriptorProto_LABEL_OPTIONAL = descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL -const FieldDescriptorProto_LABEL_REPEATED = descriptorpb.FieldDescriptorProto_LABEL_REPEATED -const FieldDescriptorProto_LABEL_REQUIRED = descriptorpb.FieldDescriptorProto_LABEL_REQUIRED - -var FieldDescriptorProto_Label_name = descriptorpb.FieldDescriptorProto_Label_name -var FieldDescriptorProto_Label_value = descriptorpb.FieldDescriptorProto_Label_value - -type FileOptions_OptimizeMode = descriptorpb.FileOptions_OptimizeMode - -const FileOptions_SPEED = descriptorpb.FileOptions_SPEED -const FileOptions_CODE_SIZE = descriptorpb.FileOptions_CODE_SIZE -const FileOptions_LITE_RUNTIME = descriptorpb.FileOptions_LITE_RUNTIME - -var FileOptions_OptimizeMode_name = descriptorpb.FileOptions_OptimizeMode_name -var FileOptions_OptimizeMode_value = descriptorpb.FileOptions_OptimizeMode_value - -type FieldOptions_CType = descriptorpb.FieldOptions_CType - -const FieldOptions_STRING = descriptorpb.FieldOptions_STRING -const FieldOptions_CORD = descriptorpb.FieldOptions_CORD -const FieldOptions_STRING_PIECE = descriptorpb.FieldOptions_STRING_PIECE - -var FieldOptions_CType_name = descriptorpb.FieldOptions_CType_name -var FieldOptions_CType_value = descriptorpb.FieldOptions_CType_value - -type FieldOptions_JSType = descriptorpb.FieldOptions_JSType - -const FieldOptions_JS_NORMAL = descriptorpb.FieldOptions_JS_NORMAL -const FieldOptions_JS_STRING = descriptorpb.FieldOptions_JS_STRING -const FieldOptions_JS_NUMBER = descriptorpb.FieldOptions_JS_NUMBER - -var FieldOptions_JSType_name = descriptorpb.FieldOptions_JSType_name -var FieldOptions_JSType_value = descriptorpb.FieldOptions_JSType_value - -type FieldOptions_OptionRetention = descriptorpb.FieldOptions_OptionRetention - -const FieldOptions_RETENTION_UNKNOWN = descriptorpb.FieldOptions_RETENTION_UNKNOWN -const FieldOptions_RETENTION_RUNTIME = descriptorpb.FieldOptions_RETENTION_RUNTIME -const FieldOptions_RETENTION_SOURCE = descriptorpb.FieldOptions_RETENTION_SOURCE - -var FieldOptions_OptionRetention_name = descriptorpb.FieldOptions_OptionRetention_name -var FieldOptions_OptionRetention_value = descriptorpb.FieldOptions_OptionRetention_value - -type FieldOptions_OptionTargetType = descriptorpb.FieldOptions_OptionTargetType - -const FieldOptions_TARGET_TYPE_UNKNOWN = descriptorpb.FieldOptions_TARGET_TYPE_UNKNOWN -const FieldOptions_TARGET_TYPE_FILE = descriptorpb.FieldOptions_TARGET_TYPE_FILE -const FieldOptions_TARGET_TYPE_EXTENSION_RANGE = descriptorpb.FieldOptions_TARGET_TYPE_EXTENSION_RANGE -const FieldOptions_TARGET_TYPE_MESSAGE = descriptorpb.FieldOptions_TARGET_TYPE_MESSAGE -const FieldOptions_TARGET_TYPE_FIELD = descriptorpb.FieldOptions_TARGET_TYPE_FIELD -const FieldOptions_TARGET_TYPE_ONEOF = descriptorpb.FieldOptions_TARGET_TYPE_ONEOF -const FieldOptions_TARGET_TYPE_ENUM = descriptorpb.FieldOptions_TARGET_TYPE_ENUM -const FieldOptions_TARGET_TYPE_ENUM_ENTRY = descriptorpb.FieldOptions_TARGET_TYPE_ENUM_ENTRY -const FieldOptions_TARGET_TYPE_SERVICE = descriptorpb.FieldOptions_TARGET_TYPE_SERVICE -const FieldOptions_TARGET_TYPE_METHOD = descriptorpb.FieldOptions_TARGET_TYPE_METHOD - -var FieldOptions_OptionTargetType_name = descriptorpb.FieldOptions_OptionTargetType_name -var FieldOptions_OptionTargetType_value = descriptorpb.FieldOptions_OptionTargetType_value - -type MethodOptions_IdempotencyLevel = descriptorpb.MethodOptions_IdempotencyLevel - -const MethodOptions_IDEMPOTENCY_UNKNOWN = descriptorpb.MethodOptions_IDEMPOTENCY_UNKNOWN -const MethodOptions_NO_SIDE_EFFECTS = descriptorpb.MethodOptions_NO_SIDE_EFFECTS -const MethodOptions_IDEMPOTENT = descriptorpb.MethodOptions_IDEMPOTENT - -var MethodOptions_IdempotencyLevel_name = descriptorpb.MethodOptions_IdempotencyLevel_name -var MethodOptions_IdempotencyLevel_value = descriptorpb.MethodOptions_IdempotencyLevel_value - -type FeatureSet_FieldPresence = descriptorpb.FeatureSet_FieldPresence - -const FeatureSet_FIELD_PRESENCE_UNKNOWN = descriptorpb.FeatureSet_FIELD_PRESENCE_UNKNOWN -const FeatureSet_EXPLICIT = descriptorpb.FeatureSet_EXPLICIT -const FeatureSet_IMPLICIT = descriptorpb.FeatureSet_IMPLICIT -const FeatureSet_LEGACY_REQUIRED = descriptorpb.FeatureSet_LEGACY_REQUIRED - -var FeatureSet_FieldPresence_name = descriptorpb.FeatureSet_FieldPresence_name -var FeatureSet_FieldPresence_value = descriptorpb.FeatureSet_FieldPresence_value - -type FeatureSet_EnumType = descriptorpb.FeatureSet_EnumType - -const FeatureSet_ENUM_TYPE_UNKNOWN = descriptorpb.FeatureSet_ENUM_TYPE_UNKNOWN -const FeatureSet_OPEN = descriptorpb.FeatureSet_OPEN -const FeatureSet_CLOSED = descriptorpb.FeatureSet_CLOSED - -var FeatureSet_EnumType_name = descriptorpb.FeatureSet_EnumType_name -var FeatureSet_EnumType_value = descriptorpb.FeatureSet_EnumType_value - -type FeatureSet_RepeatedFieldEncoding = descriptorpb.FeatureSet_RepeatedFieldEncoding - -const FeatureSet_REPEATED_FIELD_ENCODING_UNKNOWN = descriptorpb.FeatureSet_REPEATED_FIELD_ENCODING_UNKNOWN -const FeatureSet_PACKED = descriptorpb.FeatureSet_PACKED -const FeatureSet_EXPANDED = descriptorpb.FeatureSet_EXPANDED - -var FeatureSet_RepeatedFieldEncoding_name = descriptorpb.FeatureSet_RepeatedFieldEncoding_name -var FeatureSet_RepeatedFieldEncoding_value = descriptorpb.FeatureSet_RepeatedFieldEncoding_value - -type FeatureSet_Utf8Validation = descriptorpb.FeatureSet_Utf8Validation - -const FeatureSet_UTF8_VALIDATION_UNKNOWN = descriptorpb.FeatureSet_UTF8_VALIDATION_UNKNOWN -const FeatureSet_VERIFY = descriptorpb.FeatureSet_VERIFY -const FeatureSet_NONE = descriptorpb.FeatureSet_NONE - -var FeatureSet_Utf8Validation_name = descriptorpb.FeatureSet_Utf8Validation_name -var FeatureSet_Utf8Validation_value = descriptorpb.FeatureSet_Utf8Validation_value - -type FeatureSet_MessageEncoding = descriptorpb.FeatureSet_MessageEncoding - -const FeatureSet_MESSAGE_ENCODING_UNKNOWN = descriptorpb.FeatureSet_MESSAGE_ENCODING_UNKNOWN -const FeatureSet_LENGTH_PREFIXED = descriptorpb.FeatureSet_LENGTH_PREFIXED -const FeatureSet_DELIMITED = descriptorpb.FeatureSet_DELIMITED - -var FeatureSet_MessageEncoding_name = descriptorpb.FeatureSet_MessageEncoding_name -var FeatureSet_MessageEncoding_value = descriptorpb.FeatureSet_MessageEncoding_value - -type FeatureSet_JsonFormat = descriptorpb.FeatureSet_JsonFormat - -const FeatureSet_JSON_FORMAT_UNKNOWN = descriptorpb.FeatureSet_JSON_FORMAT_UNKNOWN -const FeatureSet_ALLOW = descriptorpb.FeatureSet_ALLOW -const FeatureSet_LEGACY_BEST_EFFORT = descriptorpb.FeatureSet_LEGACY_BEST_EFFORT - -var FeatureSet_JsonFormat_name = descriptorpb.FeatureSet_JsonFormat_name -var FeatureSet_JsonFormat_value = descriptorpb.FeatureSet_JsonFormat_value - -type GeneratedCodeInfo_Annotation_Semantic = descriptorpb.GeneratedCodeInfo_Annotation_Semantic - -const GeneratedCodeInfo_Annotation_NONE = descriptorpb.GeneratedCodeInfo_Annotation_NONE -const GeneratedCodeInfo_Annotation_SET = descriptorpb.GeneratedCodeInfo_Annotation_SET -const GeneratedCodeInfo_Annotation_ALIAS = descriptorpb.GeneratedCodeInfo_Annotation_ALIAS - -var GeneratedCodeInfo_Annotation_Semantic_name = descriptorpb.GeneratedCodeInfo_Annotation_Semantic_name -var GeneratedCodeInfo_Annotation_Semantic_value = descriptorpb.GeneratedCodeInfo_Annotation_Semantic_value - -type FileDescriptorSet = descriptorpb.FileDescriptorSet -type FileDescriptorProto = descriptorpb.FileDescriptorProto -type DescriptorProto = descriptorpb.DescriptorProto -type ExtensionRangeOptions = descriptorpb.ExtensionRangeOptions - -const Default_ExtensionRangeOptions_Verification = descriptorpb.Default_ExtensionRangeOptions_Verification - -type FieldDescriptorProto = descriptorpb.FieldDescriptorProto -type OneofDescriptorProto = descriptorpb.OneofDescriptorProto -type EnumDescriptorProto = descriptorpb.EnumDescriptorProto -type EnumValueDescriptorProto = descriptorpb.EnumValueDescriptorProto -type ServiceDescriptorProto = descriptorpb.ServiceDescriptorProto -type MethodDescriptorProto = descriptorpb.MethodDescriptorProto - -const Default_MethodDescriptorProto_ClientStreaming = descriptorpb.Default_MethodDescriptorProto_ClientStreaming -const Default_MethodDescriptorProto_ServerStreaming = descriptorpb.Default_MethodDescriptorProto_ServerStreaming - -type FileOptions = descriptorpb.FileOptions - -const Default_FileOptions_JavaMultipleFiles = descriptorpb.Default_FileOptions_JavaMultipleFiles -const Default_FileOptions_JavaStringCheckUtf8 = descriptorpb.Default_FileOptions_JavaStringCheckUtf8 -const Default_FileOptions_OptimizeFor = descriptorpb.Default_FileOptions_OptimizeFor -const Default_FileOptions_CcGenericServices = descriptorpb.Default_FileOptions_CcGenericServices -const Default_FileOptions_JavaGenericServices = descriptorpb.Default_FileOptions_JavaGenericServices -const Default_FileOptions_PyGenericServices = descriptorpb.Default_FileOptions_PyGenericServices -const Default_FileOptions_Deprecated = descriptorpb.Default_FileOptions_Deprecated -const Default_FileOptions_CcEnableArenas = descriptorpb.Default_FileOptions_CcEnableArenas - -type MessageOptions = descriptorpb.MessageOptions - -const Default_MessageOptions_MessageSetWireFormat = descriptorpb.Default_MessageOptions_MessageSetWireFormat -const Default_MessageOptions_NoStandardDescriptorAccessor = descriptorpb.Default_MessageOptions_NoStandardDescriptorAccessor -const Default_MessageOptions_Deprecated = descriptorpb.Default_MessageOptions_Deprecated - -type FieldOptions = descriptorpb.FieldOptions - -const Default_FieldOptions_Ctype = descriptorpb.Default_FieldOptions_Ctype -const Default_FieldOptions_Jstype = descriptorpb.Default_FieldOptions_Jstype -const Default_FieldOptions_Lazy = descriptorpb.Default_FieldOptions_Lazy -const Default_FieldOptions_UnverifiedLazy = descriptorpb.Default_FieldOptions_UnverifiedLazy -const Default_FieldOptions_Deprecated = descriptorpb.Default_FieldOptions_Deprecated -const Default_FieldOptions_Weak = descriptorpb.Default_FieldOptions_Weak -const Default_FieldOptions_DebugRedact = descriptorpb.Default_FieldOptions_DebugRedact - -type OneofOptions = descriptorpb.OneofOptions -type EnumOptions = descriptorpb.EnumOptions - -const Default_EnumOptions_Deprecated = descriptorpb.Default_EnumOptions_Deprecated - -type EnumValueOptions = descriptorpb.EnumValueOptions - -const Default_EnumValueOptions_Deprecated = descriptorpb.Default_EnumValueOptions_Deprecated -const Default_EnumValueOptions_DebugRedact = descriptorpb.Default_EnumValueOptions_DebugRedact - -type ServiceOptions = descriptorpb.ServiceOptions - -const Default_ServiceOptions_Deprecated = descriptorpb.Default_ServiceOptions_Deprecated - -type MethodOptions = descriptorpb.MethodOptions - -const Default_MethodOptions_Deprecated = descriptorpb.Default_MethodOptions_Deprecated -const Default_MethodOptions_IdempotencyLevel = descriptorpb.Default_MethodOptions_IdempotencyLevel - -type UninterpretedOption = descriptorpb.UninterpretedOption -type FeatureSet = descriptorpb.FeatureSet -type FeatureSetDefaults = descriptorpb.FeatureSetDefaults -type SourceCodeInfo = descriptorpb.SourceCodeInfo -type GeneratedCodeInfo = descriptorpb.GeneratedCodeInfo -type DescriptorProto_ExtensionRange = descriptorpb.DescriptorProto_ExtensionRange -type DescriptorProto_ReservedRange = descriptorpb.DescriptorProto_ReservedRange -type ExtensionRangeOptions_Declaration = descriptorpb.ExtensionRangeOptions_Declaration -type EnumDescriptorProto_EnumReservedRange = descriptorpb.EnumDescriptorProto_EnumReservedRange -type FieldOptions_EditionDefault = descriptorpb.FieldOptions_EditionDefault -type UninterpretedOption_NamePart = descriptorpb.UninterpretedOption_NamePart -type FeatureSetDefaults_FeatureSetEditionDefault = descriptorpb.FeatureSetDefaults_FeatureSetEditionDefault -type SourceCodeInfo_Location = descriptorpb.SourceCodeInfo_Location -type GeneratedCodeInfo_Annotation = descriptorpb.GeneratedCodeInfo_Annotation - -var File_github_com_golang_protobuf_protoc_gen_go_descriptor_descriptor_proto protoreflect.FileDescriptor - -var file_github_com_golang_protobuf_protoc_gen_go_descriptor_descriptor_proto_rawDesc = []byte{ - 0x0a, 0x44, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, - 0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x67, 0x6f, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x42, 0x40, 0x5a, 0x3e, 0x67, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, - 0x6e, 0x2d, 0x67, 0x6f, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x3b, - 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x50, 0x00, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x32, -} - -var file_github_com_golang_protobuf_protoc_gen_go_descriptor_descriptor_proto_goTypes = []interface{}{} -var file_github_com_golang_protobuf_protoc_gen_go_descriptor_descriptor_proto_depIdxs = []int32{ - 0, // [0:0] is the sub-list for method output_type - 0, // [0:0] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name -} - -func init() { file_github_com_golang_protobuf_protoc_gen_go_descriptor_descriptor_proto_init() } -func file_github_com_golang_protobuf_protoc_gen_go_descriptor_descriptor_proto_init() { - if File_github_com_golang_protobuf_protoc_gen_go_descriptor_descriptor_proto != nil { - return - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_github_com_golang_protobuf_protoc_gen_go_descriptor_descriptor_proto_rawDesc, - NumEnums: 0, - NumMessages: 0, - NumExtensions: 0, - NumServices: 0, - }, - GoTypes: file_github_com_golang_protobuf_protoc_gen_go_descriptor_descriptor_proto_goTypes, - DependencyIndexes: file_github_com_golang_protobuf_protoc_gen_go_descriptor_descriptor_proto_depIdxs, - }.Build() - File_github_com_golang_protobuf_protoc_gen_go_descriptor_descriptor_proto = out.File - file_github_com_golang_protobuf_protoc_gen_go_descriptor_descriptor_proto_rawDesc = nil - file_github_com_golang_protobuf_protoc_gen_go_descriptor_descriptor_proto_goTypes = nil - file_github_com_golang_protobuf_protoc_gen_go_descriptor_descriptor_proto_depIdxs = nil -} diff --git a/vendor/github.com/golang/protobuf/protoc-gen-go/main.go b/vendor/github.com/golang/protobuf/protoc-gen-go/main.go deleted file mode 100644 index 11b67d9f783..00000000000 --- a/vendor/github.com/golang/protobuf/protoc-gen-go/main.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// protoc-gen-go is a plugin for the Google protocol buffer compiler to generate -// Go code. Install it by building this program and making it accessible within -// your PATH with the name: -// -// protoc-gen-go -// -// The 'go' suffix becomes part of the argument for the protocol compiler, -// such that it can be invoked as: -// -// protoc --go_out=paths=source_relative:. path/to/file.proto -// -// This generates Go bindings for the protocol buffer defined by file.proto. -// With that input, the output will be written to: -// -// path/to/file.pb.go -// -// See the README and documentation for protocol buffers to learn more: -// -// https://developers.google.com/protocol-buffers/ -package main - -import ( - "flag" - "fmt" - "strings" - - "github.com/golang/protobuf/internal/gengogrpc" - gengo "google.golang.org/protobuf/cmd/protoc-gen-go/internal_gengo" - "google.golang.org/protobuf/compiler/protogen" -) - -func main() { - var ( - flags flag.FlagSet - plugins = flags.String("plugins", "", "list of plugins to enable (supported values: grpc)") - importPrefix = flags.String("import_prefix", "", "prefix to prepend to import paths") - ) - importRewriteFunc := func(importPath protogen.GoImportPath) protogen.GoImportPath { - switch importPath { - case "context", "fmt", "math": - return importPath - } - if *importPrefix != "" { - return protogen.GoImportPath(*importPrefix) + importPath - } - return importPath - } - protogen.Options{ - ParamFunc: flags.Set, - ImportRewriteFunc: importRewriteFunc, - }.Run(func(gen *protogen.Plugin) error { - grpc := false - for _, plugin := range strings.Split(*plugins, ",") { - switch plugin { - case "grpc": - grpc = true - case "": - default: - return fmt.Errorf("protoc-gen-go: unknown plugin %q", plugin) - } - } - for _, f := range gen.Files { - if !f.Generate { - continue - } - g := gengo.GenerateFile(gen, f) - if grpc { - gengogrpc.GenerateFileContent(gen, f, g) - } - } - gen.SupportedFeatures = gengo.SupportedFeatures - return nil - }) -} diff --git a/vendor/golang.org/x/lint/LICENSE b/vendor/github.com/google/go-cmp/LICENSE similarity index 96% rename from vendor/golang.org/x/lint/LICENSE rename to vendor/github.com/google/go-cmp/LICENSE index 65d761bc9f2..32017f8fa1d 100644 --- a/vendor/golang.org/x/lint/LICENSE +++ b/vendor/github.com/google/go-cmp/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2013 The Go Authors. All rights reserved. +Copyright (c) 2017 The Go Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are diff --git a/vendor/github.com/google/go-cmp/cmp/compare.go b/vendor/github.com/google/go-cmp/cmp/compare.go new file mode 100644 index 00000000000..087320da7f0 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/compare.go @@ -0,0 +1,669 @@ +// Copyright 2017, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package cmp determines equality of values. +// +// This package is intended to be a more powerful and safer alternative to +// reflect.DeepEqual for comparing whether two values are semantically equal. +// It is intended to only be used in tests, as performance is not a goal and +// it may panic if it cannot compare the values. Its propensity towards +// panicking means that its unsuitable for production environments where a +// spurious panic may be fatal. +// +// The primary features of cmp are: +// +// - When the default behavior of equality does not suit the test's needs, +// custom equality functions can override the equality operation. +// For example, an equality function may report floats as equal so long as +// they are within some tolerance of each other. +// +// - Types with an Equal method may use that method to determine equality. +// This allows package authors to determine the equality operation +// for the types that they define. +// +// - If no custom equality functions are used and no Equal method is defined, +// equality is determined by recursively comparing the primitive kinds on +// both values, much like reflect.DeepEqual. Unlike reflect.DeepEqual, +// unexported fields are not compared by default; they result in panics +// unless suppressed by using an Ignore option (see cmpopts.IgnoreUnexported) +// or explicitly compared using the Exporter option. +package cmp + +import ( + "fmt" + "reflect" + "strings" + + "github.com/google/go-cmp/cmp/internal/diff" + "github.com/google/go-cmp/cmp/internal/function" + "github.com/google/go-cmp/cmp/internal/value" +) + +// TODO(≥go1.18): Use any instead of interface{}. + +// Equal reports whether x and y are equal by recursively applying the +// following rules in the given order to x and y and all of their sub-values: +// +// - Let S be the set of all Ignore, Transformer, and Comparer options that +// remain after applying all path filters, value filters, and type filters. +// If at least one Ignore exists in S, then the comparison is ignored. +// If the number of Transformer and Comparer options in S is non-zero, +// then Equal panics because it is ambiguous which option to use. +// If S contains a single Transformer, then use that to transform +// the current values and recursively call Equal on the output values. +// If S contains a single Comparer, then use that to compare the current values. +// Otherwise, evaluation proceeds to the next rule. +// +// - If the values have an Equal method of the form "(T) Equal(T) bool" or +// "(T) Equal(I) bool" where T is assignable to I, then use the result of +// x.Equal(y) even if x or y is nil. Otherwise, no such method exists and +// evaluation proceeds to the next rule. +// +// - Lastly, try to compare x and y based on their basic kinds. +// Simple kinds like booleans, integers, floats, complex numbers, strings, +// and channels are compared using the equivalent of the == operator in Go. +// Functions are only equal if they are both nil, otherwise they are unequal. +// +// Structs are equal if recursively calling Equal on all fields report equal. +// If a struct contains unexported fields, Equal panics unless an Ignore option +// (e.g., cmpopts.IgnoreUnexported) ignores that field or the Exporter option +// explicitly permits comparing the unexported field. +// +// Slices are equal if they are both nil or both non-nil, where recursively +// calling Equal on all non-ignored slice or array elements report equal. +// Empty non-nil slices and nil slices are not equal; to equate empty slices, +// consider using cmpopts.EquateEmpty. +// +// Maps are equal if they are both nil or both non-nil, where recursively +// calling Equal on all non-ignored map entries report equal. +// Map keys are equal according to the == operator. +// To use custom comparisons for map keys, consider using cmpopts.SortMaps. +// Empty non-nil maps and nil maps are not equal; to equate empty maps, +// consider using cmpopts.EquateEmpty. +// +// Pointers and interfaces are equal if they are both nil or both non-nil, +// where they have the same underlying concrete type and recursively +// calling Equal on the underlying values reports equal. +// +// Before recursing into a pointer, slice element, or map, the current path +// is checked to detect whether the address has already been visited. +// If there is a cycle, then the pointed at values are considered equal +// only if both addresses were previously visited in the same path step. +func Equal(x, y interface{}, opts ...Option) bool { + s := newState(opts) + s.compareAny(rootStep(x, y)) + return s.result.Equal() +} + +// Diff returns a human-readable report of the differences between two values: +// y - x. It returns an empty string if and only if Equal returns true for the +// same input values and options. +// +// The output is displayed as a literal in pseudo-Go syntax. +// At the start of each line, a "-" prefix indicates an element removed from x, +// a "+" prefix to indicates an element added from y, and the lack of a prefix +// indicates an element common to both x and y. If possible, the output +// uses fmt.Stringer.String or error.Error methods to produce more humanly +// readable outputs. In such cases, the string is prefixed with either an +// 's' or 'e' character, respectively, to indicate that the method was called. +// +// Do not depend on this output being stable. If you need the ability to +// programmatically interpret the difference, consider using a custom Reporter. +func Diff(x, y interface{}, opts ...Option) string { + s := newState(opts) + + // Optimization: If there are no other reporters, we can optimize for the + // common case where the result is equal (and thus no reported difference). + // This avoids the expensive construction of a difference tree. + if len(s.reporters) == 0 { + s.compareAny(rootStep(x, y)) + if s.result.Equal() { + return "" + } + s.result = diff.Result{} // Reset results + } + + r := new(defaultReporter) + s.reporters = append(s.reporters, reporter{r}) + s.compareAny(rootStep(x, y)) + d := r.String() + if (d == "") != s.result.Equal() { + panic("inconsistent difference and equality results") + } + return d +} + +// rootStep constructs the first path step. If x and y have differing types, +// then they are stored within an empty interface type. +func rootStep(x, y interface{}) PathStep { + vx := reflect.ValueOf(x) + vy := reflect.ValueOf(y) + + // If the inputs are different types, auto-wrap them in an empty interface + // so that they have the same parent type. + var t reflect.Type + if !vx.IsValid() || !vy.IsValid() || vx.Type() != vy.Type() { + t = anyType + if vx.IsValid() { + vvx := reflect.New(t).Elem() + vvx.Set(vx) + vx = vvx + } + if vy.IsValid() { + vvy := reflect.New(t).Elem() + vvy.Set(vy) + vy = vvy + } + } else { + t = vx.Type() + } + + return &pathStep{t, vx, vy} +} + +type state struct { + // These fields represent the "comparison state". + // Calling statelessCompare must not result in observable changes to these. + result diff.Result // The current result of comparison + curPath Path // The current path in the value tree + curPtrs pointerPath // The current set of visited pointers + reporters []reporter // Optional reporters + + // recChecker checks for infinite cycles applying the same set of + // transformers upon the output of itself. + recChecker recChecker + + // dynChecker triggers pseudo-random checks for option correctness. + // It is safe for statelessCompare to mutate this value. + dynChecker dynChecker + + // These fields, once set by processOption, will not change. + exporters []exporter // List of exporters for structs with unexported fields + opts Options // List of all fundamental and filter options +} + +func newState(opts []Option) *state { + // Always ensure a validator option exists to validate the inputs. + s := &state{opts: Options{validator{}}} + s.curPtrs.Init() + s.processOption(Options(opts)) + return s +} + +func (s *state) processOption(opt Option) { + switch opt := opt.(type) { + case nil: + case Options: + for _, o := range opt { + s.processOption(o) + } + case coreOption: + type filtered interface { + isFiltered() bool + } + if fopt, ok := opt.(filtered); ok && !fopt.isFiltered() { + panic(fmt.Sprintf("cannot use an unfiltered option: %v", opt)) + } + s.opts = append(s.opts, opt) + case exporter: + s.exporters = append(s.exporters, opt) + case reporter: + s.reporters = append(s.reporters, opt) + default: + panic(fmt.Sprintf("unknown option %T", opt)) + } +} + +// statelessCompare compares two values and returns the result. +// This function is stateless in that it does not alter the current result, +// or output to any registered reporters. +func (s *state) statelessCompare(step PathStep) diff.Result { + // We do not save and restore curPath and curPtrs because all of the + // compareX methods should properly push and pop from them. + // It is an implementation bug if the contents of the paths differ from + // when calling this function to when returning from it. + + oldResult, oldReporters := s.result, s.reporters + s.result = diff.Result{} // Reset result + s.reporters = nil // Remove reporters to avoid spurious printouts + s.compareAny(step) + res := s.result + s.result, s.reporters = oldResult, oldReporters + return res +} + +func (s *state) compareAny(step PathStep) { + // Update the path stack. + s.curPath.push(step) + defer s.curPath.pop() + for _, r := range s.reporters { + r.PushStep(step) + defer r.PopStep() + } + s.recChecker.Check(s.curPath) + + // Cycle-detection for slice elements (see NOTE in compareSlice). + t := step.Type() + vx, vy := step.Values() + if si, ok := step.(SliceIndex); ok && si.isSlice && vx.IsValid() && vy.IsValid() { + px, py := vx.Addr(), vy.Addr() + if eq, visited := s.curPtrs.Push(px, py); visited { + s.report(eq, reportByCycle) + return + } + defer s.curPtrs.Pop(px, py) + } + + // Rule 1: Check whether an option applies on this node in the value tree. + if s.tryOptions(t, vx, vy) { + return + } + + // Rule 2: Check whether the type has a valid Equal method. + if s.tryMethod(t, vx, vy) { + return + } + + // Rule 3: Compare based on the underlying kind. + switch t.Kind() { + case reflect.Bool: + s.report(vx.Bool() == vy.Bool(), 0) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + s.report(vx.Int() == vy.Int(), 0) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + s.report(vx.Uint() == vy.Uint(), 0) + case reflect.Float32, reflect.Float64: + s.report(vx.Float() == vy.Float(), 0) + case reflect.Complex64, reflect.Complex128: + s.report(vx.Complex() == vy.Complex(), 0) + case reflect.String: + s.report(vx.String() == vy.String(), 0) + case reflect.Chan, reflect.UnsafePointer: + s.report(vx.Pointer() == vy.Pointer(), 0) + case reflect.Func: + s.report(vx.IsNil() && vy.IsNil(), 0) + case reflect.Struct: + s.compareStruct(t, vx, vy) + case reflect.Slice, reflect.Array: + s.compareSlice(t, vx, vy) + case reflect.Map: + s.compareMap(t, vx, vy) + case reflect.Ptr: + s.comparePtr(t, vx, vy) + case reflect.Interface: + s.compareInterface(t, vx, vy) + default: + panic(fmt.Sprintf("%v kind not handled", t.Kind())) + } +} + +func (s *state) tryOptions(t reflect.Type, vx, vy reflect.Value) bool { + // Evaluate all filters and apply the remaining options. + if opt := s.opts.filter(s, t, vx, vy); opt != nil { + opt.apply(s, vx, vy) + return true + } + return false +} + +func (s *state) tryMethod(t reflect.Type, vx, vy reflect.Value) bool { + // Check if this type even has an Equal method. + m, ok := t.MethodByName("Equal") + if !ok || !function.IsType(m.Type, function.EqualAssignable) { + return false + } + + eq := s.callTTBFunc(m.Func, vx, vy) + s.report(eq, reportByMethod) + return true +} + +func (s *state) callTRFunc(f, v reflect.Value, step Transform) reflect.Value { + if !s.dynChecker.Next() { + return f.Call([]reflect.Value{v})[0] + } + + // Run the function twice and ensure that we get the same results back. + // We run in goroutines so that the race detector (if enabled) can detect + // unsafe mutations to the input. + c := make(chan reflect.Value) + go detectRaces(c, f, v) + got := <-c + want := f.Call([]reflect.Value{v})[0] + if step.vx, step.vy = got, want; !s.statelessCompare(step).Equal() { + // To avoid false-positives with non-reflexive equality operations, + // we sanity check whether a value is equal to itself. + if step.vx, step.vy = want, want; !s.statelessCompare(step).Equal() { + return want + } + panic(fmt.Sprintf("non-deterministic function detected: %s", function.NameOf(f))) + } + return want +} + +func (s *state) callTTBFunc(f, x, y reflect.Value) bool { + if !s.dynChecker.Next() { + return f.Call([]reflect.Value{x, y})[0].Bool() + } + + // Swapping the input arguments is sufficient to check that + // f is symmetric and deterministic. + // We run in goroutines so that the race detector (if enabled) can detect + // unsafe mutations to the input. + c := make(chan reflect.Value) + go detectRaces(c, f, y, x) + got := <-c + want := f.Call([]reflect.Value{x, y})[0].Bool() + if !got.IsValid() || got.Bool() != want { + panic(fmt.Sprintf("non-deterministic or non-symmetric function detected: %s", function.NameOf(f))) + } + return want +} + +func detectRaces(c chan<- reflect.Value, f reflect.Value, vs ...reflect.Value) { + var ret reflect.Value + defer func() { + recover() // Ignore panics, let the other call to f panic instead + c <- ret + }() + ret = f.Call(vs)[0] +} + +func (s *state) compareStruct(t reflect.Type, vx, vy reflect.Value) { + var addr bool + var vax, vay reflect.Value // Addressable versions of vx and vy + + var mayForce, mayForceInit bool + step := StructField{&structField{}} + for i := 0; i < t.NumField(); i++ { + step.typ = t.Field(i).Type + step.vx = vx.Field(i) + step.vy = vy.Field(i) + step.name = t.Field(i).Name + step.idx = i + step.unexported = !isExported(step.name) + if step.unexported { + if step.name == "_" { + continue + } + // Defer checking of unexported fields until later to give an + // Ignore a chance to ignore the field. + if !vax.IsValid() || !vay.IsValid() { + // For retrieveUnexportedField to work, the parent struct must + // be addressable. Create a new copy of the values if + // necessary to make them addressable. + addr = vx.CanAddr() || vy.CanAddr() + vax = makeAddressable(vx) + vay = makeAddressable(vy) + } + if !mayForceInit { + for _, xf := range s.exporters { + mayForce = mayForce || xf(t) + } + mayForceInit = true + } + step.mayForce = mayForce + step.paddr = addr + step.pvx = vax + step.pvy = vay + step.field = t.Field(i) + } + s.compareAny(step) + } +} + +func (s *state) compareSlice(t reflect.Type, vx, vy reflect.Value) { + isSlice := t.Kind() == reflect.Slice + if isSlice && (vx.IsNil() || vy.IsNil()) { + s.report(vx.IsNil() && vy.IsNil(), 0) + return + } + + // NOTE: It is incorrect to call curPtrs.Push on the slice header pointer + // since slices represents a list of pointers, rather than a single pointer. + // The pointer checking logic must be handled on a per-element basis + // in compareAny. + // + // A slice header (see reflect.SliceHeader) in Go is a tuple of a starting + // pointer P, a length N, and a capacity C. Supposing each slice element has + // a memory size of M, then the slice is equivalent to the list of pointers: + // [P+i*M for i in range(N)] + // + // For example, v[:0] and v[:1] are slices with the same starting pointer, + // but they are clearly different values. Using the slice pointer alone + // violates the assumption that equal pointers implies equal values. + + step := SliceIndex{&sliceIndex{pathStep: pathStep{typ: t.Elem()}, isSlice: isSlice}} + withIndexes := func(ix, iy int) SliceIndex { + if ix >= 0 { + step.vx, step.xkey = vx.Index(ix), ix + } else { + step.vx, step.xkey = reflect.Value{}, -1 + } + if iy >= 0 { + step.vy, step.ykey = vy.Index(iy), iy + } else { + step.vy, step.ykey = reflect.Value{}, -1 + } + return step + } + + // Ignore options are able to ignore missing elements in a slice. + // However, detecting these reliably requires an optimal differencing + // algorithm, for which diff.Difference is not. + // + // Instead, we first iterate through both slices to detect which elements + // would be ignored if standing alone. The index of non-discarded elements + // are stored in a separate slice, which diffing is then performed on. + var indexesX, indexesY []int + var ignoredX, ignoredY []bool + for ix := 0; ix < vx.Len(); ix++ { + ignored := s.statelessCompare(withIndexes(ix, -1)).NumDiff == 0 + if !ignored { + indexesX = append(indexesX, ix) + } + ignoredX = append(ignoredX, ignored) + } + for iy := 0; iy < vy.Len(); iy++ { + ignored := s.statelessCompare(withIndexes(-1, iy)).NumDiff == 0 + if !ignored { + indexesY = append(indexesY, iy) + } + ignoredY = append(ignoredY, ignored) + } + + // Compute an edit-script for slices vx and vy (excluding ignored elements). + edits := diff.Difference(len(indexesX), len(indexesY), func(ix, iy int) diff.Result { + return s.statelessCompare(withIndexes(indexesX[ix], indexesY[iy])) + }) + + // Replay the ignore-scripts and the edit-script. + var ix, iy int + for ix < vx.Len() || iy < vy.Len() { + var e diff.EditType + switch { + case ix < len(ignoredX) && ignoredX[ix]: + e = diff.UniqueX + case iy < len(ignoredY) && ignoredY[iy]: + e = diff.UniqueY + default: + e, edits = edits[0], edits[1:] + } + switch e { + case diff.UniqueX: + s.compareAny(withIndexes(ix, -1)) + ix++ + case diff.UniqueY: + s.compareAny(withIndexes(-1, iy)) + iy++ + default: + s.compareAny(withIndexes(ix, iy)) + ix++ + iy++ + } + } +} + +func (s *state) compareMap(t reflect.Type, vx, vy reflect.Value) { + if vx.IsNil() || vy.IsNil() { + s.report(vx.IsNil() && vy.IsNil(), 0) + return + } + + // Cycle-detection for maps. + if eq, visited := s.curPtrs.Push(vx, vy); visited { + s.report(eq, reportByCycle) + return + } + defer s.curPtrs.Pop(vx, vy) + + // We combine and sort the two map keys so that we can perform the + // comparisons in a deterministic order. + step := MapIndex{&mapIndex{pathStep: pathStep{typ: t.Elem()}}} + for _, k := range value.SortKeys(append(vx.MapKeys(), vy.MapKeys()...)) { + step.vx = vx.MapIndex(k) + step.vy = vy.MapIndex(k) + step.key = k + if !step.vx.IsValid() && !step.vy.IsValid() { + // It is possible for both vx and vy to be invalid if the + // key contained a NaN value in it. + // + // Even with the ability to retrieve NaN keys in Go 1.12, + // there still isn't a sensible way to compare the values since + // a NaN key may map to multiple unordered values. + // The most reasonable way to compare NaNs would be to compare the + // set of values. However, this is impossible to do efficiently + // since set equality is provably an O(n^2) operation given only + // an Equal function. If we had a Less function or Hash function, + // this could be done in O(n*log(n)) or O(n), respectively. + // + // Rather than adding complex logic to deal with NaNs, make it + // the user's responsibility to compare such obscure maps. + const help = "consider providing a Comparer to compare the map" + panic(fmt.Sprintf("%#v has map key with NaNs\n%s", s.curPath, help)) + } + s.compareAny(step) + } +} + +func (s *state) comparePtr(t reflect.Type, vx, vy reflect.Value) { + if vx.IsNil() || vy.IsNil() { + s.report(vx.IsNil() && vy.IsNil(), 0) + return + } + + // Cycle-detection for pointers. + if eq, visited := s.curPtrs.Push(vx, vy); visited { + s.report(eq, reportByCycle) + return + } + defer s.curPtrs.Pop(vx, vy) + + vx, vy = vx.Elem(), vy.Elem() + s.compareAny(Indirect{&indirect{pathStep{t.Elem(), vx, vy}}}) +} + +func (s *state) compareInterface(t reflect.Type, vx, vy reflect.Value) { + if vx.IsNil() || vy.IsNil() { + s.report(vx.IsNil() && vy.IsNil(), 0) + return + } + vx, vy = vx.Elem(), vy.Elem() + if vx.Type() != vy.Type() { + s.report(false, 0) + return + } + s.compareAny(TypeAssertion{&typeAssertion{pathStep{vx.Type(), vx, vy}}}) +} + +func (s *state) report(eq bool, rf resultFlags) { + if rf&reportByIgnore == 0 { + if eq { + s.result.NumSame++ + rf |= reportEqual + } else { + s.result.NumDiff++ + rf |= reportUnequal + } + } + for _, r := range s.reporters { + r.Report(Result{flags: rf}) + } +} + +// recChecker tracks the state needed to periodically perform checks that +// user provided transformers are not stuck in an infinitely recursive cycle. +type recChecker struct{ next int } + +// Check scans the Path for any recursive transformers and panics when any +// recursive transformers are detected. Note that the presence of a +// recursive Transformer does not necessarily imply an infinite cycle. +// As such, this check only activates after some minimal number of path steps. +func (rc *recChecker) Check(p Path) { + const minLen = 1 << 16 + if rc.next == 0 { + rc.next = minLen + } + if len(p) < rc.next { + return + } + rc.next <<= 1 + + // Check whether the same transformer has appeared at least twice. + var ss []string + m := map[Option]int{} + for _, ps := range p { + if t, ok := ps.(Transform); ok { + t := t.Option() + if m[t] == 1 { // Transformer was used exactly once before + tf := t.(*transformer).fnc.Type() + ss = append(ss, fmt.Sprintf("%v: %v => %v", t, tf.In(0), tf.Out(0))) + } + m[t]++ + } + } + if len(ss) > 0 { + const warning = "recursive set of Transformers detected" + const help = "consider using cmpopts.AcyclicTransformer" + set := strings.Join(ss, "\n\t") + panic(fmt.Sprintf("%s:\n\t%s\n%s", warning, set, help)) + } +} + +// dynChecker tracks the state needed to periodically perform checks that +// user provided functions are symmetric and deterministic. +// The zero value is safe for immediate use. +type dynChecker struct{ curr, next int } + +// Next increments the state and reports whether a check should be performed. +// +// Checks occur every Nth function call, where N is a triangular number: +// +// 0 1 3 6 10 15 21 28 36 45 55 66 78 91 105 120 136 153 171 190 ... +// +// See https://en.wikipedia.org/wiki/Triangular_number +// +// This sequence ensures that the cost of checks drops significantly as +// the number of functions calls grows larger. +func (dc *dynChecker) Next() bool { + ok := dc.curr == dc.next + if ok { + dc.curr = 0 + dc.next++ + } + dc.curr++ + return ok +} + +// makeAddressable returns a value that is always addressable. +// It returns the input verbatim if it is already addressable, +// otherwise it creates a new value and returns an addressable copy. +func makeAddressable(v reflect.Value) reflect.Value { + if v.CanAddr() { + return v + } + vc := reflect.New(v.Type()).Elem() + vc.Set(v) + return vc +} diff --git a/vendor/github.com/google/go-cmp/cmp/export_panic.go b/vendor/github.com/google/go-cmp/cmp/export_panic.go new file mode 100644 index 00000000000..ae851fe53f2 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/export_panic.go @@ -0,0 +1,16 @@ +// Copyright 2017, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build purego +// +build purego + +package cmp + +import "reflect" + +const supportExporters = false + +func retrieveUnexportedField(reflect.Value, reflect.StructField, bool) reflect.Value { + panic("no support for forcibly accessing unexported fields") +} diff --git a/vendor/github.com/google/go-cmp/cmp/export_unsafe.go b/vendor/github.com/google/go-cmp/cmp/export_unsafe.go new file mode 100644 index 00000000000..e2c0f74e839 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/export_unsafe.go @@ -0,0 +1,36 @@ +// Copyright 2017, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !purego +// +build !purego + +package cmp + +import ( + "reflect" + "unsafe" +) + +const supportExporters = true + +// retrieveUnexportedField uses unsafe to forcibly retrieve any field from +// a struct such that the value has read-write permissions. +// +// The parent struct, v, must be addressable, while f must be a StructField +// describing the field to retrieve. If addr is false, +// then the returned value will be shallowed copied to be non-addressable. +func retrieveUnexportedField(v reflect.Value, f reflect.StructField, addr bool) reflect.Value { + ve := reflect.NewAt(f.Type, unsafe.Pointer(uintptr(unsafe.Pointer(v.UnsafeAddr()))+f.Offset)).Elem() + if !addr { + // A field is addressable if and only if the struct is addressable. + // If the original parent value was not addressable, shallow copy the + // value to make it non-addressable to avoid leaking an implementation + // detail of how forcibly exporting a field works. + if ve.Kind() == reflect.Interface && ve.IsNil() { + return reflect.Zero(f.Type) + } + return reflect.ValueOf(ve.Interface()).Convert(f.Type) + } + return ve +} diff --git a/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_disable.go b/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_disable.go new file mode 100644 index 00000000000..36062a604ca --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_disable.go @@ -0,0 +1,18 @@ +// Copyright 2017, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !cmp_debug +// +build !cmp_debug + +package diff + +var debug debugger + +type debugger struct{} + +func (debugger) Begin(_, _ int, f EqualFunc, _, _ *EditScript) EqualFunc { + return f +} +func (debugger) Update() {} +func (debugger) Finish() {} diff --git a/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_enable.go b/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_enable.go new file mode 100644 index 00000000000..a3b97a1ad57 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/internal/diff/debug_enable.go @@ -0,0 +1,123 @@ +// Copyright 2017, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build cmp_debug +// +build cmp_debug + +package diff + +import ( + "fmt" + "strings" + "sync" + "time" +) + +// The algorithm can be seen running in real-time by enabling debugging: +// go test -tags=cmp_debug -v +// +// Example output: +// === RUN TestDifference/#34 +// ┌───────────────────────────────┐ +// │ \ · · · · · · · · · · · · · · │ +// │ · # · · · · · · · · · · · · · │ +// │ · \ · · · · · · · · · · · · · │ +// │ · · \ · · · · · · · · · · · · │ +// │ · · · X # · · · · · · · · · · │ +// │ · · · # \ · · · · · · · · · · │ +// │ · · · · · # # · · · · · · · · │ +// │ · · · · · # \ · · · · · · · · │ +// │ · · · · · · · \ · · · · · · · │ +// │ · · · · · · · · \ · · · · · · │ +// │ · · · · · · · · · \ · · · · · │ +// │ · · · · · · · · · · \ · · # · │ +// │ · · · · · · · · · · · \ # # · │ +// │ · · · · · · · · · · · # # # · │ +// │ · · · · · · · · · · # # # # · │ +// │ · · · · · · · · · # # # # # · │ +// │ · · · · · · · · · · · · · · \ │ +// └───────────────────────────────┘ +// [.Y..M.XY......YXYXY.|] +// +// The grid represents the edit-graph where the horizontal axis represents +// list X and the vertical axis represents list Y. The start of the two lists +// is the top-left, while the ends are the bottom-right. The '·' represents +// an unexplored node in the graph. The '\' indicates that the two symbols +// from list X and Y are equal. The 'X' indicates that two symbols are similar +// (but not exactly equal) to each other. The '#' indicates that the two symbols +// are different (and not similar). The algorithm traverses this graph trying to +// make the paths starting in the top-left and the bottom-right connect. +// +// The series of '.', 'X', 'Y', and 'M' characters at the bottom represents +// the currently established path from the forward and reverse searches, +// separated by a '|' character. + +const ( + updateDelay = 100 * time.Millisecond + finishDelay = 500 * time.Millisecond + ansiTerminal = true // ANSI escape codes used to move terminal cursor +) + +var debug debugger + +type debugger struct { + sync.Mutex + p1, p2 EditScript + fwdPath, revPath *EditScript + grid []byte + lines int +} + +func (dbg *debugger) Begin(nx, ny int, f EqualFunc, p1, p2 *EditScript) EqualFunc { + dbg.Lock() + dbg.fwdPath, dbg.revPath = p1, p2 + top := "┌─" + strings.Repeat("──", nx) + "┐\n" + row := "│ " + strings.Repeat("· ", nx) + "│\n" + btm := "└─" + strings.Repeat("──", nx) + "┘\n" + dbg.grid = []byte(top + strings.Repeat(row, ny) + btm) + dbg.lines = strings.Count(dbg.String(), "\n") + fmt.Print(dbg) + + // Wrap the EqualFunc so that we can intercept each result. + return func(ix, iy int) (r Result) { + cell := dbg.grid[len(top)+iy*len(row):][len("│ ")+len("· ")*ix:][:len("·")] + for i := range cell { + cell[i] = 0 // Zero out the multiple bytes of UTF-8 middle-dot + } + switch r = f(ix, iy); { + case r.Equal(): + cell[0] = '\\' + case r.Similar(): + cell[0] = 'X' + default: + cell[0] = '#' + } + return + } +} + +func (dbg *debugger) Update() { + dbg.print(updateDelay) +} + +func (dbg *debugger) Finish() { + dbg.print(finishDelay) + dbg.Unlock() +} + +func (dbg *debugger) String() string { + dbg.p1, dbg.p2 = *dbg.fwdPath, dbg.p2[:0] + for i := len(*dbg.revPath) - 1; i >= 0; i-- { + dbg.p2 = append(dbg.p2, (*dbg.revPath)[i]) + } + return fmt.Sprintf("%s[%v|%v]\n\n", dbg.grid, dbg.p1, dbg.p2) +} + +func (dbg *debugger) print(d time.Duration) { + if ansiTerminal { + fmt.Printf("\x1b[%dA", dbg.lines) // Reset terminal cursor + } + fmt.Print(dbg) + time.Sleep(d) +} diff --git a/vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go b/vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go new file mode 100644 index 00000000000..a248e5436d9 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/internal/diff/diff.go @@ -0,0 +1,402 @@ +// Copyright 2017, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package diff implements an algorithm for producing edit-scripts. +// The edit-script is a sequence of operations needed to transform one list +// of symbols into another (or vice-versa). The edits allowed are insertions, +// deletions, and modifications. The summation of all edits is called the +// Levenshtein distance as this problem is well-known in computer science. +// +// This package prioritizes performance over accuracy. That is, the run time +// is more important than obtaining a minimal Levenshtein distance. +package diff + +import ( + "math/rand" + "time" + + "github.com/google/go-cmp/cmp/internal/flags" +) + +// EditType represents a single operation within an edit-script. +type EditType uint8 + +const ( + // Identity indicates that a symbol pair is identical in both list X and Y. + Identity EditType = iota + // UniqueX indicates that a symbol only exists in X and not Y. + UniqueX + // UniqueY indicates that a symbol only exists in Y and not X. + UniqueY + // Modified indicates that a symbol pair is a modification of each other. + Modified +) + +// EditScript represents the series of differences between two lists. +type EditScript []EditType + +// String returns a human-readable string representing the edit-script where +// Identity, UniqueX, UniqueY, and Modified are represented by the +// '.', 'X', 'Y', and 'M' characters, respectively. +func (es EditScript) String() string { + b := make([]byte, len(es)) + for i, e := range es { + switch e { + case Identity: + b[i] = '.' + case UniqueX: + b[i] = 'X' + case UniqueY: + b[i] = 'Y' + case Modified: + b[i] = 'M' + default: + panic("invalid edit-type") + } + } + return string(b) +} + +// stats returns a histogram of the number of each type of edit operation. +func (es EditScript) stats() (s struct{ NI, NX, NY, NM int }) { + for _, e := range es { + switch e { + case Identity: + s.NI++ + case UniqueX: + s.NX++ + case UniqueY: + s.NY++ + case Modified: + s.NM++ + default: + panic("invalid edit-type") + } + } + return +} + +// Dist is the Levenshtein distance and is guaranteed to be 0 if and only if +// lists X and Y are equal. +func (es EditScript) Dist() int { return len(es) - es.stats().NI } + +// LenX is the length of the X list. +func (es EditScript) LenX() int { return len(es) - es.stats().NY } + +// LenY is the length of the Y list. +func (es EditScript) LenY() int { return len(es) - es.stats().NX } + +// EqualFunc reports whether the symbols at indexes ix and iy are equal. +// When called by Difference, the index is guaranteed to be within nx and ny. +type EqualFunc func(ix int, iy int) Result + +// Result is the result of comparison. +// NumSame is the number of sub-elements that are equal. +// NumDiff is the number of sub-elements that are not equal. +type Result struct{ NumSame, NumDiff int } + +// BoolResult returns a Result that is either Equal or not Equal. +func BoolResult(b bool) Result { + if b { + return Result{NumSame: 1} // Equal, Similar + } else { + return Result{NumDiff: 2} // Not Equal, not Similar + } +} + +// Equal indicates whether the symbols are equal. Two symbols are equal +// if and only if NumDiff == 0. If Equal, then they are also Similar. +func (r Result) Equal() bool { return r.NumDiff == 0 } + +// Similar indicates whether two symbols are similar and may be represented +// by using the Modified type. As a special case, we consider binary comparisons +// (i.e., those that return Result{1, 0} or Result{0, 1}) to be similar. +// +// The exact ratio of NumSame to NumDiff to determine similarity may change. +func (r Result) Similar() bool { + // Use NumSame+1 to offset NumSame so that binary comparisons are similar. + return r.NumSame+1 >= r.NumDiff +} + +var randBool = rand.New(rand.NewSource(time.Now().Unix())).Intn(2) == 0 + +// Difference reports whether two lists of lengths nx and ny are equal +// given the definition of equality provided as f. +// +// This function returns an edit-script, which is a sequence of operations +// needed to convert one list into the other. The following invariants for +// the edit-script are maintained: +// - eq == (es.Dist()==0) +// - nx == es.LenX() +// - ny == es.LenY() +// +// This algorithm is not guaranteed to be an optimal solution (i.e., one that +// produces an edit-script with a minimal Levenshtein distance). This algorithm +// favors performance over optimality. The exact output is not guaranteed to +// be stable and may change over time. +func Difference(nx, ny int, f EqualFunc) (es EditScript) { + // This algorithm is based on traversing what is known as an "edit-graph". + // See Figure 1 from "An O(ND) Difference Algorithm and Its Variations" + // by Eugene W. Myers. Since D can be as large as N itself, this is + // effectively O(N^2). Unlike the algorithm from that paper, we are not + // interested in the optimal path, but at least some "decent" path. + // + // For example, let X and Y be lists of symbols: + // X = [A B C A B B A] + // Y = [C B A B A C] + // + // The edit-graph can be drawn as the following: + // A B C A B B A + // ┌─────────────┐ + // C │_|_|\|_|_|_|_│ 0 + // B │_|\|_|_|\|\|_│ 1 + // A │\|_|_|\|_|_|\│ 2 + // B │_|\|_|_|\|\|_│ 3 + // A │\|_|_|\|_|_|\│ 4 + // C │ | |\| | | | │ 5 + // └─────────────┘ 6 + // 0 1 2 3 4 5 6 7 + // + // List X is written along the horizontal axis, while list Y is written + // along the vertical axis. At any point on this grid, if the symbol in + // list X matches the corresponding symbol in list Y, then a '\' is drawn. + // The goal of any minimal edit-script algorithm is to find a path from the + // top-left corner to the bottom-right corner, while traveling through the + // fewest horizontal or vertical edges. + // A horizontal edge is equivalent to inserting a symbol from list X. + // A vertical edge is equivalent to inserting a symbol from list Y. + // A diagonal edge is equivalent to a matching symbol between both X and Y. + + // Invariants: + // - 0 ≤ fwdPath.X ≤ (fwdFrontier.X, revFrontier.X) ≤ revPath.X ≤ nx + // - 0 ≤ fwdPath.Y ≤ (fwdFrontier.Y, revFrontier.Y) ≤ revPath.Y ≤ ny + // + // In general: + // - fwdFrontier.X < revFrontier.X + // - fwdFrontier.Y < revFrontier.Y + // + // Unless, it is time for the algorithm to terminate. + fwdPath := path{+1, point{0, 0}, make(EditScript, 0, (nx+ny)/2)} + revPath := path{-1, point{nx, ny}, make(EditScript, 0)} + fwdFrontier := fwdPath.point // Forward search frontier + revFrontier := revPath.point // Reverse search frontier + + // Search budget bounds the cost of searching for better paths. + // The longest sequence of non-matching symbols that can be tolerated is + // approximately the square-root of the search budget. + searchBudget := 4 * (nx + ny) // O(n) + + // Running the tests with the "cmp_debug" build tag prints a visualization + // of the algorithm running in real-time. This is educational for + // understanding how the algorithm works. See debug_enable.go. + f = debug.Begin(nx, ny, f, &fwdPath.es, &revPath.es) + + // The algorithm below is a greedy, meet-in-the-middle algorithm for + // computing sub-optimal edit-scripts between two lists. + // + // The algorithm is approximately as follows: + // - Searching for differences switches back-and-forth between + // a search that starts at the beginning (the top-left corner), and + // a search that starts at the end (the bottom-right corner). + // The goal of the search is connect with the search + // from the opposite corner. + // - As we search, we build a path in a greedy manner, + // where the first match seen is added to the path (this is sub-optimal, + // but provides a decent result in practice). When matches are found, + // we try the next pair of symbols in the lists and follow all matches + // as far as possible. + // - When searching for matches, we search along a diagonal going through + // through the "frontier" point. If no matches are found, + // we advance the frontier towards the opposite corner. + // - This algorithm terminates when either the X coordinates or the + // Y coordinates of the forward and reverse frontier points ever intersect. + + // This algorithm is correct even if searching only in the forward direction + // or in the reverse direction. We do both because it is commonly observed + // that two lists commonly differ because elements were added to the front + // or end of the other list. + // + // Non-deterministically start with either the forward or reverse direction + // to introduce some deliberate instability so that we have the flexibility + // to change this algorithm in the future. + if flags.Deterministic || randBool { + goto forwardSearch + } else { + goto reverseSearch + } + +forwardSearch: + { + // Forward search from the beginning. + if fwdFrontier.X >= revFrontier.X || fwdFrontier.Y >= revFrontier.Y || searchBudget == 0 { + goto finishSearch + } + for stop1, stop2, i := false, false, 0; !(stop1 && stop2) && searchBudget > 0; i++ { + // Search in a diagonal pattern for a match. + z := zigzag(i) + p := point{fwdFrontier.X + z, fwdFrontier.Y - z} + switch { + case p.X >= revPath.X || p.Y < fwdPath.Y: + stop1 = true // Hit top-right corner + case p.Y >= revPath.Y || p.X < fwdPath.X: + stop2 = true // Hit bottom-left corner + case f(p.X, p.Y).Equal(): + // Match found, so connect the path to this point. + fwdPath.connect(p, f) + fwdPath.append(Identity) + // Follow sequence of matches as far as possible. + for fwdPath.X < revPath.X && fwdPath.Y < revPath.Y { + if !f(fwdPath.X, fwdPath.Y).Equal() { + break + } + fwdPath.append(Identity) + } + fwdFrontier = fwdPath.point + stop1, stop2 = true, true + default: + searchBudget-- // Match not found + } + debug.Update() + } + // Advance the frontier towards reverse point. + if revPath.X-fwdFrontier.X >= revPath.Y-fwdFrontier.Y { + fwdFrontier.X++ + } else { + fwdFrontier.Y++ + } + goto reverseSearch + } + +reverseSearch: + { + // Reverse search from the end. + if fwdFrontier.X >= revFrontier.X || fwdFrontier.Y >= revFrontier.Y || searchBudget == 0 { + goto finishSearch + } + for stop1, stop2, i := false, false, 0; !(stop1 && stop2) && searchBudget > 0; i++ { + // Search in a diagonal pattern for a match. + z := zigzag(i) + p := point{revFrontier.X - z, revFrontier.Y + z} + switch { + case fwdPath.X >= p.X || revPath.Y < p.Y: + stop1 = true // Hit bottom-left corner + case fwdPath.Y >= p.Y || revPath.X < p.X: + stop2 = true // Hit top-right corner + case f(p.X-1, p.Y-1).Equal(): + // Match found, so connect the path to this point. + revPath.connect(p, f) + revPath.append(Identity) + // Follow sequence of matches as far as possible. + for fwdPath.X < revPath.X && fwdPath.Y < revPath.Y { + if !f(revPath.X-1, revPath.Y-1).Equal() { + break + } + revPath.append(Identity) + } + revFrontier = revPath.point + stop1, stop2 = true, true + default: + searchBudget-- // Match not found + } + debug.Update() + } + // Advance the frontier towards forward point. + if revFrontier.X-fwdPath.X >= revFrontier.Y-fwdPath.Y { + revFrontier.X-- + } else { + revFrontier.Y-- + } + goto forwardSearch + } + +finishSearch: + // Join the forward and reverse paths and then append the reverse path. + fwdPath.connect(revPath.point, f) + for i := len(revPath.es) - 1; i >= 0; i-- { + t := revPath.es[i] + revPath.es = revPath.es[:i] + fwdPath.append(t) + } + debug.Finish() + return fwdPath.es +} + +type path struct { + dir int // +1 if forward, -1 if reverse + point // Leading point of the EditScript path + es EditScript +} + +// connect appends any necessary Identity, Modified, UniqueX, or UniqueY types +// to the edit-script to connect p.point to dst. +func (p *path) connect(dst point, f EqualFunc) { + if p.dir > 0 { + // Connect in forward direction. + for dst.X > p.X && dst.Y > p.Y { + switch r := f(p.X, p.Y); { + case r.Equal(): + p.append(Identity) + case r.Similar(): + p.append(Modified) + case dst.X-p.X >= dst.Y-p.Y: + p.append(UniqueX) + default: + p.append(UniqueY) + } + } + for dst.X > p.X { + p.append(UniqueX) + } + for dst.Y > p.Y { + p.append(UniqueY) + } + } else { + // Connect in reverse direction. + for p.X > dst.X && p.Y > dst.Y { + switch r := f(p.X-1, p.Y-1); { + case r.Equal(): + p.append(Identity) + case r.Similar(): + p.append(Modified) + case p.Y-dst.Y >= p.X-dst.X: + p.append(UniqueY) + default: + p.append(UniqueX) + } + } + for p.X > dst.X { + p.append(UniqueX) + } + for p.Y > dst.Y { + p.append(UniqueY) + } + } +} + +func (p *path) append(t EditType) { + p.es = append(p.es, t) + switch t { + case Identity, Modified: + p.add(p.dir, p.dir) + case UniqueX: + p.add(p.dir, 0) + case UniqueY: + p.add(0, p.dir) + } + debug.Update() +} + +type point struct{ X, Y int } + +func (p *point) add(dx, dy int) { p.X += dx; p.Y += dy } + +// zigzag maps a consecutive sequence of integers to a zig-zag sequence. +// +// [0 1 2 3 4 5 ...] => [0 -1 +1 -2 +2 ...] +func zigzag(x int) int { + if x&1 != 0 { + x = ^x + } + return x >> 1 +} diff --git a/vendor/github.com/google/go-cmp/cmp/internal/flags/flags.go b/vendor/github.com/google/go-cmp/cmp/internal/flags/flags.go new file mode 100644 index 00000000000..d8e459c9b93 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/internal/flags/flags.go @@ -0,0 +1,9 @@ +// Copyright 2019, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package flags + +// Deterministic controls whether the output of Diff should be deterministic. +// This is only used for testing. +var Deterministic bool diff --git a/vendor/github.com/google/go-cmp/cmp/internal/function/func.go b/vendor/github.com/google/go-cmp/cmp/internal/function/func.go new file mode 100644 index 00000000000..d127d436230 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/internal/function/func.go @@ -0,0 +1,99 @@ +// Copyright 2017, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package function provides functionality for identifying function types. +package function + +import ( + "reflect" + "regexp" + "runtime" + "strings" +) + +type funcType int + +const ( + _ funcType = iota + + tbFunc // func(T) bool + ttbFunc // func(T, T) bool + trbFunc // func(T, R) bool + tibFunc // func(T, I) bool + trFunc // func(T) R + + Equal = ttbFunc // func(T, T) bool + EqualAssignable = tibFunc // func(T, I) bool; encapsulates func(T, T) bool + Transformer = trFunc // func(T) R + ValueFilter = ttbFunc // func(T, T) bool + Less = ttbFunc // func(T, T) bool + ValuePredicate = tbFunc // func(T) bool + KeyValuePredicate = trbFunc // func(T, R) bool +) + +var boolType = reflect.TypeOf(true) + +// IsType reports whether the reflect.Type is of the specified function type. +func IsType(t reflect.Type, ft funcType) bool { + if t == nil || t.Kind() != reflect.Func || t.IsVariadic() { + return false + } + ni, no := t.NumIn(), t.NumOut() + switch ft { + case tbFunc: // func(T) bool + if ni == 1 && no == 1 && t.Out(0) == boolType { + return true + } + case ttbFunc: // func(T, T) bool + if ni == 2 && no == 1 && t.In(0) == t.In(1) && t.Out(0) == boolType { + return true + } + case trbFunc: // func(T, R) bool + if ni == 2 && no == 1 && t.Out(0) == boolType { + return true + } + case tibFunc: // func(T, I) bool + if ni == 2 && no == 1 && t.In(0).AssignableTo(t.In(1)) && t.Out(0) == boolType { + return true + } + case trFunc: // func(T) R + if ni == 1 && no == 1 { + return true + } + } + return false +} + +var lastIdentRx = regexp.MustCompile(`[_\p{L}][_\p{L}\p{N}]*$`) + +// NameOf returns the name of the function value. +func NameOf(v reflect.Value) string { + fnc := runtime.FuncForPC(v.Pointer()) + if fnc == nil { + return "" + } + fullName := fnc.Name() // e.g., "long/path/name/mypkg.(*MyType).(long/path/name/mypkg.myMethod)-fm" + + // Method closures have a "-fm" suffix. + fullName = strings.TrimSuffix(fullName, "-fm") + + var name string + for len(fullName) > 0 { + inParen := strings.HasSuffix(fullName, ")") + fullName = strings.TrimSuffix(fullName, ")") + + s := lastIdentRx.FindString(fullName) + if s == "" { + break + } + name = s + "." + name + fullName = strings.TrimSuffix(fullName, s) + + if i := strings.LastIndexByte(fullName, '('); inParen && i >= 0 { + fullName = fullName[:i] + } + fullName = strings.TrimSuffix(fullName, ".") + } + return strings.TrimSuffix(name, ".") +} diff --git a/vendor/github.com/google/go-cmp/cmp/internal/value/name.go b/vendor/github.com/google/go-cmp/cmp/internal/value/name.go new file mode 100644 index 00000000000..7b498bb2cb9 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/internal/value/name.go @@ -0,0 +1,164 @@ +// Copyright 2020, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package value + +import ( + "reflect" + "strconv" +) + +var anyType = reflect.TypeOf((*interface{})(nil)).Elem() + +// TypeString is nearly identical to reflect.Type.String, +// but has an additional option to specify that full type names be used. +func TypeString(t reflect.Type, qualified bool) string { + return string(appendTypeName(nil, t, qualified, false)) +} + +func appendTypeName(b []byte, t reflect.Type, qualified, elideFunc bool) []byte { + // BUG: Go reflection provides no way to disambiguate two named types + // of the same name and within the same package, + // but declared within the namespace of different functions. + + // Use the "any" alias instead of "interface{}" for better readability. + if t == anyType { + return append(b, "any"...) + } + + // Named type. + if t.Name() != "" { + if qualified && t.PkgPath() != "" { + b = append(b, '"') + b = append(b, t.PkgPath()...) + b = append(b, '"') + b = append(b, '.') + b = append(b, t.Name()...) + } else { + b = append(b, t.String()...) + } + return b + } + + // Unnamed type. + switch k := t.Kind(); k { + case reflect.Bool, reflect.String, reflect.UnsafePointer, + reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, + reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128: + b = append(b, k.String()...) + case reflect.Chan: + if t.ChanDir() == reflect.RecvDir { + b = append(b, "<-"...) + } + b = append(b, "chan"...) + if t.ChanDir() == reflect.SendDir { + b = append(b, "<-"...) + } + b = append(b, ' ') + b = appendTypeName(b, t.Elem(), qualified, false) + case reflect.Func: + if !elideFunc { + b = append(b, "func"...) + } + b = append(b, '(') + for i := 0; i < t.NumIn(); i++ { + if i > 0 { + b = append(b, ", "...) + } + if i == t.NumIn()-1 && t.IsVariadic() { + b = append(b, "..."...) + b = appendTypeName(b, t.In(i).Elem(), qualified, false) + } else { + b = appendTypeName(b, t.In(i), qualified, false) + } + } + b = append(b, ')') + switch t.NumOut() { + case 0: + // Do nothing + case 1: + b = append(b, ' ') + b = appendTypeName(b, t.Out(0), qualified, false) + default: + b = append(b, " ("...) + for i := 0; i < t.NumOut(); i++ { + if i > 0 { + b = append(b, ", "...) + } + b = appendTypeName(b, t.Out(i), qualified, false) + } + b = append(b, ')') + } + case reflect.Struct: + b = append(b, "struct{ "...) + for i := 0; i < t.NumField(); i++ { + if i > 0 { + b = append(b, "; "...) + } + sf := t.Field(i) + if !sf.Anonymous { + if qualified && sf.PkgPath != "" { + b = append(b, '"') + b = append(b, sf.PkgPath...) + b = append(b, '"') + b = append(b, '.') + } + b = append(b, sf.Name...) + b = append(b, ' ') + } + b = appendTypeName(b, sf.Type, qualified, false) + if sf.Tag != "" { + b = append(b, ' ') + b = strconv.AppendQuote(b, string(sf.Tag)) + } + } + if b[len(b)-1] == ' ' { + b = b[:len(b)-1] + } else { + b = append(b, ' ') + } + b = append(b, '}') + case reflect.Slice, reflect.Array: + b = append(b, '[') + if k == reflect.Array { + b = strconv.AppendUint(b, uint64(t.Len()), 10) + } + b = append(b, ']') + b = appendTypeName(b, t.Elem(), qualified, false) + case reflect.Map: + b = append(b, "map["...) + b = appendTypeName(b, t.Key(), qualified, false) + b = append(b, ']') + b = appendTypeName(b, t.Elem(), qualified, false) + case reflect.Ptr: + b = append(b, '*') + b = appendTypeName(b, t.Elem(), qualified, false) + case reflect.Interface: + b = append(b, "interface{ "...) + for i := 0; i < t.NumMethod(); i++ { + if i > 0 { + b = append(b, "; "...) + } + m := t.Method(i) + if qualified && m.PkgPath != "" { + b = append(b, '"') + b = append(b, m.PkgPath...) + b = append(b, '"') + b = append(b, '.') + } + b = append(b, m.Name...) + b = appendTypeName(b, m.Type, qualified, true) + } + if b[len(b)-1] == ' ' { + b = b[:len(b)-1] + } else { + b = append(b, ' ') + } + b = append(b, '}') + default: + panic("invalid kind: " + k.String()) + } + return b +} diff --git a/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_purego.go b/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_purego.go new file mode 100644 index 00000000000..1a71bfcbd39 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_purego.go @@ -0,0 +1,34 @@ +// Copyright 2018, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build purego +// +build purego + +package value + +import "reflect" + +// Pointer is an opaque typed pointer and is guaranteed to be comparable. +type Pointer struct { + p uintptr + t reflect.Type +} + +// PointerOf returns a Pointer from v, which must be a +// reflect.Ptr, reflect.Slice, or reflect.Map. +func PointerOf(v reflect.Value) Pointer { + // NOTE: Storing a pointer as an uintptr is technically incorrect as it + // assumes that the GC implementation does not use a moving collector. + return Pointer{v.Pointer(), v.Type()} +} + +// IsNil reports whether the pointer is nil. +func (p Pointer) IsNil() bool { + return p.p == 0 +} + +// Uintptr returns the pointer as a uintptr. +func (p Pointer) Uintptr() uintptr { + return p.p +} diff --git a/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_unsafe.go b/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_unsafe.go new file mode 100644 index 00000000000..16e6860af6e --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/internal/value/pointer_unsafe.go @@ -0,0 +1,37 @@ +// Copyright 2018, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !purego +// +build !purego + +package value + +import ( + "reflect" + "unsafe" +) + +// Pointer is an opaque typed pointer and is guaranteed to be comparable. +type Pointer struct { + p unsafe.Pointer + t reflect.Type +} + +// PointerOf returns a Pointer from v, which must be a +// reflect.Ptr, reflect.Slice, or reflect.Map. +func PointerOf(v reflect.Value) Pointer { + // The proper representation of a pointer is unsafe.Pointer, + // which is necessary if the GC ever uses a moving collector. + return Pointer{unsafe.Pointer(v.Pointer()), v.Type()} +} + +// IsNil reports whether the pointer is nil. +func (p Pointer) IsNil() bool { + return p.p == nil +} + +// Uintptr returns the pointer as a uintptr. +func (p Pointer) Uintptr() uintptr { + return uintptr(p.p) +} diff --git a/vendor/github.com/google/go-cmp/cmp/internal/value/sort.go b/vendor/github.com/google/go-cmp/cmp/internal/value/sort.go new file mode 100644 index 00000000000..98533b036cc --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/internal/value/sort.go @@ -0,0 +1,106 @@ +// Copyright 2017, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package value + +import ( + "fmt" + "math" + "reflect" + "sort" +) + +// SortKeys sorts a list of map keys, deduplicating keys if necessary. +// The type of each value must be comparable. +func SortKeys(vs []reflect.Value) []reflect.Value { + if len(vs) == 0 { + return vs + } + + // Sort the map keys. + sort.SliceStable(vs, func(i, j int) bool { return isLess(vs[i], vs[j]) }) + + // Deduplicate keys (fails for NaNs). + vs2 := vs[:1] + for _, v := range vs[1:] { + if isLess(vs2[len(vs2)-1], v) { + vs2 = append(vs2, v) + } + } + return vs2 +} + +// isLess is a generic function for sorting arbitrary map keys. +// The inputs must be of the same type and must be comparable. +func isLess(x, y reflect.Value) bool { + switch x.Type().Kind() { + case reflect.Bool: + return !x.Bool() && y.Bool() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return x.Int() < y.Int() + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return x.Uint() < y.Uint() + case reflect.Float32, reflect.Float64: + // NOTE: This does not sort -0 as less than +0 + // since Go maps treat -0 and +0 as equal keys. + fx, fy := x.Float(), y.Float() + return fx < fy || math.IsNaN(fx) && !math.IsNaN(fy) + case reflect.Complex64, reflect.Complex128: + cx, cy := x.Complex(), y.Complex() + rx, ix, ry, iy := real(cx), imag(cx), real(cy), imag(cy) + if rx == ry || (math.IsNaN(rx) && math.IsNaN(ry)) { + return ix < iy || math.IsNaN(ix) && !math.IsNaN(iy) + } + return rx < ry || math.IsNaN(rx) && !math.IsNaN(ry) + case reflect.Ptr, reflect.UnsafePointer, reflect.Chan: + return x.Pointer() < y.Pointer() + case reflect.String: + return x.String() < y.String() + case reflect.Array: + for i := 0; i < x.Len(); i++ { + if isLess(x.Index(i), y.Index(i)) { + return true + } + if isLess(y.Index(i), x.Index(i)) { + return false + } + } + return false + case reflect.Struct: + for i := 0; i < x.NumField(); i++ { + if isLess(x.Field(i), y.Field(i)) { + return true + } + if isLess(y.Field(i), x.Field(i)) { + return false + } + } + return false + case reflect.Interface: + vx, vy := x.Elem(), y.Elem() + if !vx.IsValid() || !vy.IsValid() { + return !vx.IsValid() && vy.IsValid() + } + tx, ty := vx.Type(), vy.Type() + if tx == ty { + return isLess(x.Elem(), y.Elem()) + } + if tx.Kind() != ty.Kind() { + return vx.Kind() < vy.Kind() + } + if tx.String() != ty.String() { + return tx.String() < ty.String() + } + if tx.PkgPath() != ty.PkgPath() { + return tx.PkgPath() < ty.PkgPath() + } + // This can happen in rare situations, so we fallback to just comparing + // the unique pointer for a reflect.Type. This guarantees deterministic + // ordering within a program, but it is obviously not stable. + return reflect.ValueOf(vx.Type()).Pointer() < reflect.ValueOf(vy.Type()).Pointer() + default: + // Must be Func, Map, or Slice; which are not comparable. + panic(fmt.Sprintf("%T is not comparable", x.Type())) + } +} diff --git a/vendor/github.com/google/go-cmp/cmp/options.go b/vendor/github.com/google/go-cmp/cmp/options.go new file mode 100644 index 00000000000..1f9ca9c4892 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/options.go @@ -0,0 +1,554 @@ +// Copyright 2017, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cmp + +import ( + "fmt" + "reflect" + "regexp" + "strings" + + "github.com/google/go-cmp/cmp/internal/function" +) + +// Option configures for specific behavior of Equal and Diff. In particular, +// the fundamental Option functions (Ignore, Transformer, and Comparer), +// configure how equality is determined. +// +// The fundamental options may be composed with filters (FilterPath and +// FilterValues) to control the scope over which they are applied. +// +// The cmp/cmpopts package provides helper functions for creating options that +// may be used with Equal and Diff. +type Option interface { + // filter applies all filters and returns the option that remains. + // Each option may only read s.curPath and call s.callTTBFunc. + // + // An Options is returned only if multiple comparers or transformers + // can apply simultaneously and will only contain values of those types + // or sub-Options containing values of those types. + filter(s *state, t reflect.Type, vx, vy reflect.Value) applicableOption +} + +// applicableOption represents the following types: +// +// Fundamental: ignore | validator | *comparer | *transformer +// Grouping: Options +type applicableOption interface { + Option + + // apply executes the option, which may mutate s or panic. + apply(s *state, vx, vy reflect.Value) +} + +// coreOption represents the following types: +// +// Fundamental: ignore | validator | *comparer | *transformer +// Filters: *pathFilter | *valuesFilter +type coreOption interface { + Option + isCore() +} + +type core struct{} + +func (core) isCore() {} + +// Options is a list of Option values that also satisfies the Option interface. +// Helper comparison packages may return an Options value when packing multiple +// Option values into a single Option. When this package processes an Options, +// it will be implicitly expanded into a flat list. +// +// Applying a filter on an Options is equivalent to applying that same filter +// on all individual options held within. +type Options []Option + +func (opts Options) filter(s *state, t reflect.Type, vx, vy reflect.Value) (out applicableOption) { + for _, opt := range opts { + switch opt := opt.filter(s, t, vx, vy); opt.(type) { + case ignore: + return ignore{} // Only ignore can short-circuit evaluation + case validator: + out = validator{} // Takes precedence over comparer or transformer + case *comparer, *transformer, Options: + switch out.(type) { + case nil: + out = opt + case validator: + // Keep validator + case *comparer, *transformer, Options: + out = Options{out, opt} // Conflicting comparers or transformers + } + } + } + return out +} + +func (opts Options) apply(s *state, _, _ reflect.Value) { + const warning = "ambiguous set of applicable options" + const help = "consider using filters to ensure at most one Comparer or Transformer may apply" + var ss []string + for _, opt := range flattenOptions(nil, opts) { + ss = append(ss, fmt.Sprint(opt)) + } + set := strings.Join(ss, "\n\t") + panic(fmt.Sprintf("%s at %#v:\n\t%s\n%s", warning, s.curPath, set, help)) +} + +func (opts Options) String() string { + var ss []string + for _, opt := range opts { + ss = append(ss, fmt.Sprint(opt)) + } + return fmt.Sprintf("Options{%s}", strings.Join(ss, ", ")) +} + +// FilterPath returns a new Option where opt is only evaluated if filter f +// returns true for the current Path in the value tree. +// +// This filter is called even if a slice element or map entry is missing and +// provides an opportunity to ignore such cases. The filter function must be +// symmetric such that the filter result is identical regardless of whether the +// missing value is from x or y. +// +// The option passed in may be an Ignore, Transformer, Comparer, Options, or +// a previously filtered Option. +func FilterPath(f func(Path) bool, opt Option) Option { + if f == nil { + panic("invalid path filter function") + } + if opt := normalizeOption(opt); opt != nil { + return &pathFilter{fnc: f, opt: opt} + } + return nil +} + +type pathFilter struct { + core + fnc func(Path) bool + opt Option +} + +func (f pathFilter) filter(s *state, t reflect.Type, vx, vy reflect.Value) applicableOption { + if f.fnc(s.curPath) { + return f.opt.filter(s, t, vx, vy) + } + return nil +} + +func (f pathFilter) String() string { + return fmt.Sprintf("FilterPath(%s, %v)", function.NameOf(reflect.ValueOf(f.fnc)), f.opt) +} + +// FilterValues returns a new Option where opt is only evaluated if filter f, +// which is a function of the form "func(T, T) bool", returns true for the +// current pair of values being compared. If either value is invalid or +// the type of the values is not assignable to T, then this filter implicitly +// returns false. +// +// The filter function must be +// symmetric (i.e., agnostic to the order of the inputs) and +// deterministic (i.e., produces the same result when given the same inputs). +// If T is an interface, it is possible that f is called with two values with +// different concrete types that both implement T. +// +// The option passed in may be an Ignore, Transformer, Comparer, Options, or +// a previously filtered Option. +func FilterValues(f interface{}, opt Option) Option { + v := reflect.ValueOf(f) + if !function.IsType(v.Type(), function.ValueFilter) || v.IsNil() { + panic(fmt.Sprintf("invalid values filter function: %T", f)) + } + if opt := normalizeOption(opt); opt != nil { + vf := &valuesFilter{fnc: v, opt: opt} + if ti := v.Type().In(0); ti.Kind() != reflect.Interface || ti.NumMethod() > 0 { + vf.typ = ti + } + return vf + } + return nil +} + +type valuesFilter struct { + core + typ reflect.Type // T + fnc reflect.Value // func(T, T) bool + opt Option +} + +func (f valuesFilter) filter(s *state, t reflect.Type, vx, vy reflect.Value) applicableOption { + if !vx.IsValid() || !vx.CanInterface() || !vy.IsValid() || !vy.CanInterface() { + return nil + } + if (f.typ == nil || t.AssignableTo(f.typ)) && s.callTTBFunc(f.fnc, vx, vy) { + return f.opt.filter(s, t, vx, vy) + } + return nil +} + +func (f valuesFilter) String() string { + return fmt.Sprintf("FilterValues(%s, %v)", function.NameOf(f.fnc), f.opt) +} + +// Ignore is an Option that causes all comparisons to be ignored. +// This value is intended to be combined with FilterPath or FilterValues. +// It is an error to pass an unfiltered Ignore option to Equal. +func Ignore() Option { return ignore{} } + +type ignore struct{ core } + +func (ignore) isFiltered() bool { return false } +func (ignore) filter(_ *state, _ reflect.Type, _, _ reflect.Value) applicableOption { return ignore{} } +func (ignore) apply(s *state, _, _ reflect.Value) { s.report(true, reportByIgnore) } +func (ignore) String() string { return "Ignore()" } + +// validator is a sentinel Option type to indicate that some options could not +// be evaluated due to unexported fields, missing slice elements, or +// missing map entries. Both values are validator only for unexported fields. +type validator struct{ core } + +func (validator) filter(_ *state, _ reflect.Type, vx, vy reflect.Value) applicableOption { + if !vx.IsValid() || !vy.IsValid() { + return validator{} + } + if !vx.CanInterface() || !vy.CanInterface() { + return validator{} + } + return nil +} +func (validator) apply(s *state, vx, vy reflect.Value) { + // Implies missing slice element or map entry. + if !vx.IsValid() || !vy.IsValid() { + s.report(vx.IsValid() == vy.IsValid(), 0) + return + } + + // Unable to Interface implies unexported field without visibility access. + if !vx.CanInterface() || !vy.CanInterface() { + help := "consider using a custom Comparer; if you control the implementation of type, you can also consider using an Exporter, AllowUnexported, or cmpopts.IgnoreUnexported" + var name string + if t := s.curPath.Index(-2).Type(); t.Name() != "" { + // Named type with unexported fields. + name = fmt.Sprintf("%q.%v", t.PkgPath(), t.Name()) // e.g., "path/to/package".MyType + if _, ok := reflect.New(t).Interface().(error); ok { + help = "consider using cmpopts.EquateErrors to compare error values" + } + } else { + // Unnamed type with unexported fields. Derive PkgPath from field. + var pkgPath string + for i := 0; i < t.NumField() && pkgPath == ""; i++ { + pkgPath = t.Field(i).PkgPath + } + name = fmt.Sprintf("%q.(%v)", pkgPath, t.String()) // e.g., "path/to/package".(struct { a int }) + } + panic(fmt.Sprintf("cannot handle unexported field at %#v:\n\t%v\n%s", s.curPath, name, help)) + } + + panic("not reachable") +} + +// identRx represents a valid identifier according to the Go specification. +const identRx = `[_\p{L}][_\p{L}\p{N}]*` + +var identsRx = regexp.MustCompile(`^` + identRx + `(\.` + identRx + `)*$`) + +// Transformer returns an Option that applies a transformation function that +// converts values of a certain type into that of another. +// +// The transformer f must be a function "func(T) R" that converts values of +// type T to those of type R and is implicitly filtered to input values +// assignable to T. The transformer must not mutate T in any way. +// +// To help prevent some cases of infinite recursive cycles applying the +// same transform to the output of itself (e.g., in the case where the +// input and output types are the same), an implicit filter is added such that +// a transformer is applicable only if that exact transformer is not already +// in the tail of the Path since the last non-Transform step. +// For situations where the implicit filter is still insufficient, +// consider using cmpopts.AcyclicTransformer, which adds a filter +// to prevent the transformer from being recursively applied upon itself. +// +// The name is a user provided label that is used as the Transform.Name in the +// transformation PathStep (and eventually shown in the Diff output). +// The name must be a valid identifier or qualified identifier in Go syntax. +// If empty, an arbitrary name is used. +func Transformer(name string, f interface{}) Option { + v := reflect.ValueOf(f) + if !function.IsType(v.Type(), function.Transformer) || v.IsNil() { + panic(fmt.Sprintf("invalid transformer function: %T", f)) + } + if name == "" { + name = function.NameOf(v) + if !identsRx.MatchString(name) { + name = "λ" // Lambda-symbol as placeholder name + } + } else if !identsRx.MatchString(name) { + panic(fmt.Sprintf("invalid name: %q", name)) + } + tr := &transformer{name: name, fnc: reflect.ValueOf(f)} + if ti := v.Type().In(0); ti.Kind() != reflect.Interface || ti.NumMethod() > 0 { + tr.typ = ti + } + return tr +} + +type transformer struct { + core + name string + typ reflect.Type // T + fnc reflect.Value // func(T) R +} + +func (tr *transformer) isFiltered() bool { return tr.typ != nil } + +func (tr *transformer) filter(s *state, t reflect.Type, _, _ reflect.Value) applicableOption { + for i := len(s.curPath) - 1; i >= 0; i-- { + if t, ok := s.curPath[i].(Transform); !ok { + break // Hit most recent non-Transform step + } else if tr == t.trans { + return nil // Cannot directly use same Transform + } + } + if tr.typ == nil || t.AssignableTo(tr.typ) { + return tr + } + return nil +} + +func (tr *transformer) apply(s *state, vx, vy reflect.Value) { + step := Transform{&transform{pathStep{typ: tr.fnc.Type().Out(0)}, tr}} + vvx := s.callTRFunc(tr.fnc, vx, step) + vvy := s.callTRFunc(tr.fnc, vy, step) + step.vx, step.vy = vvx, vvy + s.compareAny(step) +} + +func (tr transformer) String() string { + return fmt.Sprintf("Transformer(%s, %s)", tr.name, function.NameOf(tr.fnc)) +} + +// Comparer returns an Option that determines whether two values are equal +// to each other. +// +// The comparer f must be a function "func(T, T) bool" and is implicitly +// filtered to input values assignable to T. If T is an interface, it is +// possible that f is called with two values of different concrete types that +// both implement T. +// +// The equality function must be: +// - Symmetric: equal(x, y) == equal(y, x) +// - Deterministic: equal(x, y) == equal(x, y) +// - Pure: equal(x, y) does not modify x or y +func Comparer(f interface{}) Option { + v := reflect.ValueOf(f) + if !function.IsType(v.Type(), function.Equal) || v.IsNil() { + panic(fmt.Sprintf("invalid comparer function: %T", f)) + } + cm := &comparer{fnc: v} + if ti := v.Type().In(0); ti.Kind() != reflect.Interface || ti.NumMethod() > 0 { + cm.typ = ti + } + return cm +} + +type comparer struct { + core + typ reflect.Type // T + fnc reflect.Value // func(T, T) bool +} + +func (cm *comparer) isFiltered() bool { return cm.typ != nil } + +func (cm *comparer) filter(_ *state, t reflect.Type, _, _ reflect.Value) applicableOption { + if cm.typ == nil || t.AssignableTo(cm.typ) { + return cm + } + return nil +} + +func (cm *comparer) apply(s *state, vx, vy reflect.Value) { + eq := s.callTTBFunc(cm.fnc, vx, vy) + s.report(eq, reportByFunc) +} + +func (cm comparer) String() string { + return fmt.Sprintf("Comparer(%s)", function.NameOf(cm.fnc)) +} + +// Exporter returns an Option that specifies whether Equal is allowed to +// introspect into the unexported fields of certain struct types. +// +// Users of this option must understand that comparing on unexported fields +// from external packages is not safe since changes in the internal +// implementation of some external package may cause the result of Equal +// to unexpectedly change. However, it may be valid to use this option on types +// defined in an internal package where the semantic meaning of an unexported +// field is in the control of the user. +// +// In many cases, a custom Comparer should be used instead that defines +// equality as a function of the public API of a type rather than the underlying +// unexported implementation. +// +// For example, the reflect.Type documentation defines equality to be determined +// by the == operator on the interface (essentially performing a shallow pointer +// comparison) and most attempts to compare *regexp.Regexp types are interested +// in only checking that the regular expression strings are equal. +// Both of these are accomplished using Comparers: +// +// Comparer(func(x, y reflect.Type) bool { return x == y }) +// Comparer(func(x, y *regexp.Regexp) bool { return x.String() == y.String() }) +// +// In other cases, the cmpopts.IgnoreUnexported option can be used to ignore +// all unexported fields on specified struct types. +func Exporter(f func(reflect.Type) bool) Option { + if !supportExporters { + panic("Exporter is not supported on purego builds") + } + return exporter(f) +} + +type exporter func(reflect.Type) bool + +func (exporter) filter(_ *state, _ reflect.Type, _, _ reflect.Value) applicableOption { + panic("not implemented") +} + +// AllowUnexported returns an Options that allows Equal to forcibly introspect +// unexported fields of the specified struct types. +// +// See Exporter for the proper use of this option. +func AllowUnexported(types ...interface{}) Option { + m := make(map[reflect.Type]bool) + for _, typ := range types { + t := reflect.TypeOf(typ) + if t.Kind() != reflect.Struct { + panic(fmt.Sprintf("invalid struct type: %T", typ)) + } + m[t] = true + } + return exporter(func(t reflect.Type) bool { return m[t] }) +} + +// Result represents the comparison result for a single node and +// is provided by cmp when calling Report (see Reporter). +type Result struct { + _ [0]func() // Make Result incomparable + flags resultFlags +} + +// Equal reports whether the node was determined to be equal or not. +// As a special case, ignored nodes are considered equal. +func (r Result) Equal() bool { + return r.flags&(reportEqual|reportByIgnore) != 0 +} + +// ByIgnore reports whether the node is equal because it was ignored. +// This never reports true if Equal reports false. +func (r Result) ByIgnore() bool { + return r.flags&reportByIgnore != 0 +} + +// ByMethod reports whether the Equal method determined equality. +func (r Result) ByMethod() bool { + return r.flags&reportByMethod != 0 +} + +// ByFunc reports whether a Comparer function determined equality. +func (r Result) ByFunc() bool { + return r.flags&reportByFunc != 0 +} + +// ByCycle reports whether a reference cycle was detected. +func (r Result) ByCycle() bool { + return r.flags&reportByCycle != 0 +} + +type resultFlags uint + +const ( + _ resultFlags = (1 << iota) / 2 + + reportEqual + reportUnequal + reportByIgnore + reportByMethod + reportByFunc + reportByCycle +) + +// Reporter is an Option that can be passed to Equal. When Equal traverses +// the value trees, it calls PushStep as it descends into each node in the +// tree and PopStep as it ascend out of the node. The leaves of the tree are +// either compared (determined to be equal or not equal) or ignored and reported +// as such by calling the Report method. +func Reporter(r interface { + // PushStep is called when a tree-traversal operation is performed. + // The PathStep itself is only valid until the step is popped. + // The PathStep.Values are valid for the duration of the entire traversal + // and must not be mutated. + // + // Equal always calls PushStep at the start to provide an operation-less + // PathStep used to report the root values. + // + // Within a slice, the exact set of inserted, removed, or modified elements + // is unspecified and may change in future implementations. + // The entries of a map are iterated through in an unspecified order. + PushStep(PathStep) + + // Report is called exactly once on leaf nodes to report whether the + // comparison identified the node as equal, unequal, or ignored. + // A leaf node is one that is immediately preceded by and followed by + // a pair of PushStep and PopStep calls. + Report(Result) + + // PopStep ascends back up the value tree. + // There is always a matching pop call for every push call. + PopStep() +}) Option { + return reporter{r} +} + +type reporter struct{ reporterIface } +type reporterIface interface { + PushStep(PathStep) + Report(Result) + PopStep() +} + +func (reporter) filter(_ *state, _ reflect.Type, _, _ reflect.Value) applicableOption { + panic("not implemented") +} + +// normalizeOption normalizes the input options such that all Options groups +// are flattened and groups with a single element are reduced to that element. +// Only coreOptions and Options containing coreOptions are allowed. +func normalizeOption(src Option) Option { + switch opts := flattenOptions(nil, Options{src}); len(opts) { + case 0: + return nil + case 1: + return opts[0] + default: + return opts + } +} + +// flattenOptions copies all options in src to dst as a flat list. +// Only coreOptions and Options containing coreOptions are allowed. +func flattenOptions(dst, src Options) Options { + for _, opt := range src { + switch opt := opt.(type) { + case nil: + continue + case Options: + dst = flattenOptions(dst, opt) + case coreOption: + dst = append(dst, opt) + default: + panic(fmt.Sprintf("invalid option type: %T", opt)) + } + } + return dst +} diff --git a/vendor/github.com/google/go-cmp/cmp/path.go b/vendor/github.com/google/go-cmp/cmp/path.go new file mode 100644 index 00000000000..a0a588502ed --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/path.go @@ -0,0 +1,380 @@ +// Copyright 2017, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cmp + +import ( + "fmt" + "reflect" + "strings" + "unicode" + "unicode/utf8" + + "github.com/google/go-cmp/cmp/internal/value" +) + +// Path is a list of PathSteps describing the sequence of operations to get +// from some root type to the current position in the value tree. +// The first Path element is always an operation-less PathStep that exists +// simply to identify the initial type. +// +// When traversing structs with embedded structs, the embedded struct will +// always be accessed as a field before traversing the fields of the +// embedded struct themselves. That is, an exported field from the +// embedded struct will never be accessed directly from the parent struct. +type Path []PathStep + +// PathStep is a union-type for specific operations to traverse +// a value's tree structure. Users of this package never need to implement +// these types as values of this type will be returned by this package. +// +// Implementations of this interface are +// StructField, SliceIndex, MapIndex, Indirect, TypeAssertion, and Transform. +type PathStep interface { + String() string + + // Type is the resulting type after performing the path step. + Type() reflect.Type + + // Values is the resulting values after performing the path step. + // The type of each valid value is guaranteed to be identical to Type. + // + // In some cases, one or both may be invalid or have restrictions: + // - For StructField, both are not interface-able if the current field + // is unexported and the struct type is not explicitly permitted by + // an Exporter to traverse unexported fields. + // - For SliceIndex, one may be invalid if an element is missing from + // either the x or y slice. + // - For MapIndex, one may be invalid if an entry is missing from + // either the x or y map. + // + // The provided values must not be mutated. + Values() (vx, vy reflect.Value) +} + +var ( + _ PathStep = StructField{} + _ PathStep = SliceIndex{} + _ PathStep = MapIndex{} + _ PathStep = Indirect{} + _ PathStep = TypeAssertion{} + _ PathStep = Transform{} +) + +func (pa *Path) push(s PathStep) { + *pa = append(*pa, s) +} + +func (pa *Path) pop() { + *pa = (*pa)[:len(*pa)-1] +} + +// Last returns the last PathStep in the Path. +// If the path is empty, this returns a non-nil PathStep that reports a nil Type. +func (pa Path) Last() PathStep { + return pa.Index(-1) +} + +// Index returns the ith step in the Path and supports negative indexing. +// A negative index starts counting from the tail of the Path such that -1 +// refers to the last step, -2 refers to the second-to-last step, and so on. +// If index is invalid, this returns a non-nil PathStep that reports a nil Type. +func (pa Path) Index(i int) PathStep { + if i < 0 { + i = len(pa) + i + } + if i < 0 || i >= len(pa) { + return pathStep{} + } + return pa[i] +} + +// String returns the simplified path to a node. +// The simplified path only contains struct field accesses. +// +// For example: +// +// MyMap.MySlices.MyField +func (pa Path) String() string { + var ss []string + for _, s := range pa { + if _, ok := s.(StructField); ok { + ss = append(ss, s.String()) + } + } + return strings.TrimPrefix(strings.Join(ss, ""), ".") +} + +// GoString returns the path to a specific node using Go syntax. +// +// For example: +// +// (*root.MyMap["key"].(*mypkg.MyStruct).MySlices)[2][3].MyField +func (pa Path) GoString() string { + var ssPre, ssPost []string + var numIndirect int + for i, s := range pa { + var nextStep PathStep + if i+1 < len(pa) { + nextStep = pa[i+1] + } + switch s := s.(type) { + case Indirect: + numIndirect++ + pPre, pPost := "(", ")" + switch nextStep.(type) { + case Indirect: + continue // Next step is indirection, so let them batch up + case StructField: + numIndirect-- // Automatic indirection on struct fields + case nil: + pPre, pPost = "", "" // Last step; no need for parenthesis + } + if numIndirect > 0 { + ssPre = append(ssPre, pPre+strings.Repeat("*", numIndirect)) + ssPost = append(ssPost, pPost) + } + numIndirect = 0 + continue + case Transform: + ssPre = append(ssPre, s.trans.name+"(") + ssPost = append(ssPost, ")") + continue + } + ssPost = append(ssPost, s.String()) + } + for i, j := 0, len(ssPre)-1; i < j; i, j = i+1, j-1 { + ssPre[i], ssPre[j] = ssPre[j], ssPre[i] + } + return strings.Join(ssPre, "") + strings.Join(ssPost, "") +} + +type pathStep struct { + typ reflect.Type + vx, vy reflect.Value +} + +func (ps pathStep) Type() reflect.Type { return ps.typ } +func (ps pathStep) Values() (vx, vy reflect.Value) { return ps.vx, ps.vy } +func (ps pathStep) String() string { + if ps.typ == nil { + return "" + } + s := value.TypeString(ps.typ, false) + if s == "" || strings.ContainsAny(s, "{}\n") { + return "root" // Type too simple or complex to print + } + return fmt.Sprintf("{%s}", s) +} + +// StructField represents a struct field access on a field called Name. +type StructField struct{ *structField } +type structField struct { + pathStep + name string + idx int + + // These fields are used for forcibly accessing an unexported field. + // pvx, pvy, and field are only valid if unexported is true. + unexported bool + mayForce bool // Forcibly allow visibility + paddr bool // Was parent addressable? + pvx, pvy reflect.Value // Parent values (always addressable) + field reflect.StructField // Field information +} + +func (sf StructField) Type() reflect.Type { return sf.typ } +func (sf StructField) Values() (vx, vy reflect.Value) { + if !sf.unexported { + return sf.vx, sf.vy // CanInterface reports true + } + + // Forcibly obtain read-write access to an unexported struct field. + if sf.mayForce { + vx = retrieveUnexportedField(sf.pvx, sf.field, sf.paddr) + vy = retrieveUnexportedField(sf.pvy, sf.field, sf.paddr) + return vx, vy // CanInterface reports true + } + return sf.vx, sf.vy // CanInterface reports false +} +func (sf StructField) String() string { return fmt.Sprintf(".%s", sf.name) } + +// Name is the field name. +func (sf StructField) Name() string { return sf.name } + +// Index is the index of the field in the parent struct type. +// See reflect.Type.Field. +func (sf StructField) Index() int { return sf.idx } + +// SliceIndex is an index operation on a slice or array at some index Key. +type SliceIndex struct{ *sliceIndex } +type sliceIndex struct { + pathStep + xkey, ykey int + isSlice bool // False for reflect.Array +} + +func (si SliceIndex) Type() reflect.Type { return si.typ } +func (si SliceIndex) Values() (vx, vy reflect.Value) { return si.vx, si.vy } +func (si SliceIndex) String() string { + switch { + case si.xkey == si.ykey: + return fmt.Sprintf("[%d]", si.xkey) + case si.ykey == -1: + // [5->?] means "I don't know where X[5] went" + return fmt.Sprintf("[%d->?]", si.xkey) + case si.xkey == -1: + // [?->3] means "I don't know where Y[3] came from" + return fmt.Sprintf("[?->%d]", si.ykey) + default: + // [5->3] means "X[5] moved to Y[3]" + return fmt.Sprintf("[%d->%d]", si.xkey, si.ykey) + } +} + +// Key is the index key; it may return -1 if in a split state +func (si SliceIndex) Key() int { + if si.xkey != si.ykey { + return -1 + } + return si.xkey +} + +// SplitKeys are the indexes for indexing into slices in the +// x and y values, respectively. These indexes may differ due to the +// insertion or removal of an element in one of the slices, causing +// all of the indexes to be shifted. If an index is -1, then that +// indicates that the element does not exist in the associated slice. +// +// Key is guaranteed to return -1 if and only if the indexes returned +// by SplitKeys are not the same. SplitKeys will never return -1 for +// both indexes. +func (si SliceIndex) SplitKeys() (ix, iy int) { return si.xkey, si.ykey } + +// MapIndex is an index operation on a map at some index Key. +type MapIndex struct{ *mapIndex } +type mapIndex struct { + pathStep + key reflect.Value +} + +func (mi MapIndex) Type() reflect.Type { return mi.typ } +func (mi MapIndex) Values() (vx, vy reflect.Value) { return mi.vx, mi.vy } +func (mi MapIndex) String() string { return fmt.Sprintf("[%#v]", mi.key) } + +// Key is the value of the map key. +func (mi MapIndex) Key() reflect.Value { return mi.key } + +// Indirect represents pointer indirection on the parent type. +type Indirect struct{ *indirect } +type indirect struct { + pathStep +} + +func (in Indirect) Type() reflect.Type { return in.typ } +func (in Indirect) Values() (vx, vy reflect.Value) { return in.vx, in.vy } +func (in Indirect) String() string { return "*" } + +// TypeAssertion represents a type assertion on an interface. +type TypeAssertion struct{ *typeAssertion } +type typeAssertion struct { + pathStep +} + +func (ta TypeAssertion) Type() reflect.Type { return ta.typ } +func (ta TypeAssertion) Values() (vx, vy reflect.Value) { return ta.vx, ta.vy } +func (ta TypeAssertion) String() string { return fmt.Sprintf(".(%v)", value.TypeString(ta.typ, false)) } + +// Transform is a transformation from the parent type to the current type. +type Transform struct{ *transform } +type transform struct { + pathStep + trans *transformer +} + +func (tf Transform) Type() reflect.Type { return tf.typ } +func (tf Transform) Values() (vx, vy reflect.Value) { return tf.vx, tf.vy } +func (tf Transform) String() string { return fmt.Sprintf("%s()", tf.trans.name) } + +// Name is the name of the Transformer. +func (tf Transform) Name() string { return tf.trans.name } + +// Func is the function pointer to the transformer function. +func (tf Transform) Func() reflect.Value { return tf.trans.fnc } + +// Option returns the originally constructed Transformer option. +// The == operator can be used to detect the exact option used. +func (tf Transform) Option() Option { return tf.trans } + +// pointerPath represents a dual-stack of pointers encountered when +// recursively traversing the x and y values. This data structure supports +// detection of cycles and determining whether the cycles are equal. +// In Go, cycles can occur via pointers, slices, and maps. +// +// The pointerPath uses a map to represent a stack; where descension into a +// pointer pushes the address onto the stack, and ascension from a pointer +// pops the address from the stack. Thus, when traversing into a pointer from +// reflect.Ptr, reflect.Slice element, or reflect.Map, we can detect cycles +// by checking whether the pointer has already been visited. The cycle detection +// uses a separate stack for the x and y values. +// +// If a cycle is detected we need to determine whether the two pointers +// should be considered equal. The definition of equality chosen by Equal +// requires two graphs to have the same structure. To determine this, both the +// x and y values must have a cycle where the previous pointers were also +// encountered together as a pair. +// +// Semantically, this is equivalent to augmenting Indirect, SliceIndex, and +// MapIndex with pointer information for the x and y values. +// Suppose px and py are two pointers to compare, we then search the +// Path for whether px was ever encountered in the Path history of x, and +// similarly so with py. If either side has a cycle, the comparison is only +// equal if both px and py have a cycle resulting from the same PathStep. +// +// Using a map as a stack is more performant as we can perform cycle detection +// in O(1) instead of O(N) where N is len(Path). +type pointerPath struct { + // mx is keyed by x pointers, where the value is the associated y pointer. + mx map[value.Pointer]value.Pointer + // my is keyed by y pointers, where the value is the associated x pointer. + my map[value.Pointer]value.Pointer +} + +func (p *pointerPath) Init() { + p.mx = make(map[value.Pointer]value.Pointer) + p.my = make(map[value.Pointer]value.Pointer) +} + +// Push indicates intent to descend into pointers vx and vy where +// visited reports whether either has been seen before. If visited before, +// equal reports whether both pointers were encountered together. +// Pop must be called if and only if the pointers were never visited. +// +// The pointers vx and vy must be a reflect.Ptr, reflect.Slice, or reflect.Map +// and be non-nil. +func (p pointerPath) Push(vx, vy reflect.Value) (equal, visited bool) { + px := value.PointerOf(vx) + py := value.PointerOf(vy) + _, ok1 := p.mx[px] + _, ok2 := p.my[py] + if ok1 || ok2 { + equal = p.mx[px] == py && p.my[py] == px // Pointers paired together + return equal, true + } + p.mx[px] = py + p.my[py] = px + return false, false +} + +// Pop ascends from pointers vx and vy. +func (p pointerPath) Pop(vx, vy reflect.Value) { + delete(p.mx, value.PointerOf(vx)) + delete(p.my, value.PointerOf(vy)) +} + +// isExported reports whether the identifier is exported. +func isExported(id string) bool { + r, _ := utf8.DecodeRuneInString(id) + return unicode.IsUpper(r) +} diff --git a/vendor/github.com/google/go-cmp/cmp/report.go b/vendor/github.com/google/go-cmp/cmp/report.go new file mode 100644 index 00000000000..f43cd12eb5f --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/report.go @@ -0,0 +1,54 @@ +// Copyright 2017, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cmp + +// defaultReporter implements the reporter interface. +// +// As Equal serially calls the PushStep, Report, and PopStep methods, the +// defaultReporter constructs a tree-based representation of the compared value +// and the result of each comparison (see valueNode). +// +// When the String method is called, the FormatDiff method transforms the +// valueNode tree into a textNode tree, which is a tree-based representation +// of the textual output (see textNode). +// +// Lastly, the textNode.String method produces the final report as a string. +type defaultReporter struct { + root *valueNode + curr *valueNode +} + +func (r *defaultReporter) PushStep(ps PathStep) { + r.curr = r.curr.PushStep(ps) + if r.root == nil { + r.root = r.curr + } +} +func (r *defaultReporter) Report(rs Result) { + r.curr.Report(rs) +} +func (r *defaultReporter) PopStep() { + r.curr = r.curr.PopStep() +} + +// String provides a full report of the differences detected as a structured +// literal in pseudo-Go syntax. String may only be called after the entire tree +// has been traversed. +func (r *defaultReporter) String() string { + assert(r.root != nil && r.curr == nil) + if r.root.NumDiff == 0 { + return "" + } + ptrs := new(pointerReferences) + text := formatOptions{}.FormatDiff(r.root, ptrs) + resolveReferences(text) + return text.String() +} + +func assert(ok bool) { + if !ok { + panic("assertion failure") + } +} diff --git a/vendor/github.com/google/go-cmp/cmp/report_compare.go b/vendor/github.com/google/go-cmp/cmp/report_compare.go new file mode 100644 index 00000000000..2050bf6b46b --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/report_compare.go @@ -0,0 +1,433 @@ +// Copyright 2019, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cmp + +import ( + "fmt" + "reflect" +) + +// numContextRecords is the number of surrounding equal records to print. +const numContextRecords = 2 + +type diffMode byte + +const ( + diffUnknown diffMode = 0 + diffIdentical diffMode = ' ' + diffRemoved diffMode = '-' + diffInserted diffMode = '+' +) + +type typeMode int + +const ( + // emitType always prints the type. + emitType typeMode = iota + // elideType never prints the type. + elideType + // autoType prints the type only for composite kinds + // (i.e., structs, slices, arrays, and maps). + autoType +) + +type formatOptions struct { + // DiffMode controls the output mode of FormatDiff. + // + // If diffUnknown, then produce a diff of the x and y values. + // If diffIdentical, then emit values as if they were equal. + // If diffRemoved, then only emit x values (ignoring y values). + // If diffInserted, then only emit y values (ignoring x values). + DiffMode diffMode + + // TypeMode controls whether to print the type for the current node. + // + // As a general rule of thumb, we always print the type of the next node + // after an interface, and always elide the type of the next node after + // a slice or map node. + TypeMode typeMode + + // formatValueOptions are options specific to printing reflect.Values. + formatValueOptions +} + +func (opts formatOptions) WithDiffMode(d diffMode) formatOptions { + opts.DiffMode = d + return opts +} +func (opts formatOptions) WithTypeMode(t typeMode) formatOptions { + opts.TypeMode = t + return opts +} +func (opts formatOptions) WithVerbosity(level int) formatOptions { + opts.VerbosityLevel = level + opts.LimitVerbosity = true + return opts +} +func (opts formatOptions) verbosity() uint { + switch { + case opts.VerbosityLevel < 0: + return 0 + case opts.VerbosityLevel > 16: + return 16 // some reasonable maximum to avoid shift overflow + default: + return uint(opts.VerbosityLevel) + } +} + +const maxVerbosityPreset = 6 + +// verbosityPreset modifies the verbosity settings given an index +// between 0 and maxVerbosityPreset, inclusive. +func verbosityPreset(opts formatOptions, i int) formatOptions { + opts.VerbosityLevel = int(opts.verbosity()) + 2*i + if i > 0 { + opts.AvoidStringer = true + } + if i >= maxVerbosityPreset { + opts.PrintAddresses = true + opts.QualifiedNames = true + } + return opts +} + +// FormatDiff converts a valueNode tree into a textNode tree, where the later +// is a textual representation of the differences detected in the former. +func (opts formatOptions) FormatDiff(v *valueNode, ptrs *pointerReferences) (out textNode) { + if opts.DiffMode == diffIdentical { + opts = opts.WithVerbosity(1) + } else if opts.verbosity() < 3 { + opts = opts.WithVerbosity(3) + } + + // Check whether we have specialized formatting for this node. + // This is not necessary, but helpful for producing more readable outputs. + if opts.CanFormatDiffSlice(v) { + return opts.FormatDiffSlice(v) + } + + var parentKind reflect.Kind + if v.parent != nil && v.parent.TransformerName == "" { + parentKind = v.parent.Type.Kind() + } + + // For leaf nodes, format the value based on the reflect.Values alone. + // As a special case, treat equal []byte as a leaf nodes. + isBytes := v.Type.Kind() == reflect.Slice && v.Type.Elem() == byteType + isEqualBytes := isBytes && v.NumDiff+v.NumIgnored+v.NumTransformed == 0 + if v.MaxDepth == 0 || isEqualBytes { + switch opts.DiffMode { + case diffUnknown, diffIdentical: + // Format Equal. + if v.NumDiff == 0 { + outx := opts.FormatValue(v.ValueX, parentKind, ptrs) + outy := opts.FormatValue(v.ValueY, parentKind, ptrs) + if v.NumIgnored > 0 && v.NumSame == 0 { + return textEllipsis + } else if outx.Len() < outy.Len() { + return outx + } else { + return outy + } + } + + // Format unequal. + assert(opts.DiffMode == diffUnknown) + var list textList + outx := opts.WithTypeMode(elideType).FormatValue(v.ValueX, parentKind, ptrs) + outy := opts.WithTypeMode(elideType).FormatValue(v.ValueY, parentKind, ptrs) + for i := 0; i <= maxVerbosityPreset && outx != nil && outy != nil && outx.Equal(outy); i++ { + opts2 := verbosityPreset(opts, i).WithTypeMode(elideType) + outx = opts2.FormatValue(v.ValueX, parentKind, ptrs) + outy = opts2.FormatValue(v.ValueY, parentKind, ptrs) + } + if outx != nil { + list = append(list, textRecord{Diff: '-', Value: outx}) + } + if outy != nil { + list = append(list, textRecord{Diff: '+', Value: outy}) + } + return opts.WithTypeMode(emitType).FormatType(v.Type, list) + case diffRemoved: + return opts.FormatValue(v.ValueX, parentKind, ptrs) + case diffInserted: + return opts.FormatValue(v.ValueY, parentKind, ptrs) + default: + panic("invalid diff mode") + } + } + + // Register slice element to support cycle detection. + if parentKind == reflect.Slice { + ptrRefs := ptrs.PushPair(v.ValueX, v.ValueY, opts.DiffMode, true) + defer ptrs.Pop() + defer func() { out = wrapTrunkReferences(ptrRefs, out) }() + } + + // Descend into the child value node. + if v.TransformerName != "" { + out := opts.WithTypeMode(emitType).FormatDiff(v.Value, ptrs) + out = &textWrap{Prefix: "Inverse(" + v.TransformerName + ", ", Value: out, Suffix: ")"} + return opts.FormatType(v.Type, out) + } else { + switch k := v.Type.Kind(); k { + case reflect.Struct, reflect.Array, reflect.Slice: + out = opts.formatDiffList(v.Records, k, ptrs) + out = opts.FormatType(v.Type, out) + case reflect.Map: + // Register map to support cycle detection. + ptrRefs := ptrs.PushPair(v.ValueX, v.ValueY, opts.DiffMode, false) + defer ptrs.Pop() + + out = opts.formatDiffList(v.Records, k, ptrs) + out = wrapTrunkReferences(ptrRefs, out) + out = opts.FormatType(v.Type, out) + case reflect.Ptr: + // Register pointer to support cycle detection. + ptrRefs := ptrs.PushPair(v.ValueX, v.ValueY, opts.DiffMode, false) + defer ptrs.Pop() + + out = opts.FormatDiff(v.Value, ptrs) + out = wrapTrunkReferences(ptrRefs, out) + out = &textWrap{Prefix: "&", Value: out} + case reflect.Interface: + out = opts.WithTypeMode(emitType).FormatDiff(v.Value, ptrs) + default: + panic(fmt.Sprintf("%v cannot have children", k)) + } + return out + } +} + +func (opts formatOptions) formatDiffList(recs []reportRecord, k reflect.Kind, ptrs *pointerReferences) textNode { + // Derive record name based on the data structure kind. + var name string + var formatKey func(reflect.Value) string + switch k { + case reflect.Struct: + name = "field" + opts = opts.WithTypeMode(autoType) + formatKey = func(v reflect.Value) string { return v.String() } + case reflect.Slice, reflect.Array: + name = "element" + opts = opts.WithTypeMode(elideType) + formatKey = func(reflect.Value) string { return "" } + case reflect.Map: + name = "entry" + opts = opts.WithTypeMode(elideType) + formatKey = func(v reflect.Value) string { return formatMapKey(v, false, ptrs) } + } + + maxLen := -1 + if opts.LimitVerbosity { + if opts.DiffMode == diffIdentical { + maxLen = ((1 << opts.verbosity()) >> 1) << 2 // 0, 4, 8, 16, 32, etc... + } else { + maxLen = (1 << opts.verbosity()) << 1 // 2, 4, 8, 16, 32, 64, etc... + } + opts.VerbosityLevel-- + } + + // Handle unification. + switch opts.DiffMode { + case diffIdentical, diffRemoved, diffInserted: + var list textList + var deferredEllipsis bool // Add final "..." to indicate records were dropped + for _, r := range recs { + if len(list) == maxLen { + deferredEllipsis = true + break + } + + // Elide struct fields that are zero value. + if k == reflect.Struct { + var isZero bool + switch opts.DiffMode { + case diffIdentical: + isZero = r.Value.ValueX.IsZero() || r.Value.ValueY.IsZero() + case diffRemoved: + isZero = r.Value.ValueX.IsZero() + case diffInserted: + isZero = r.Value.ValueY.IsZero() + } + if isZero { + continue + } + } + // Elide ignored nodes. + if r.Value.NumIgnored > 0 && r.Value.NumSame+r.Value.NumDiff == 0 { + deferredEllipsis = !(k == reflect.Slice || k == reflect.Array) + if !deferredEllipsis { + list.AppendEllipsis(diffStats{}) + } + continue + } + if out := opts.FormatDiff(r.Value, ptrs); out != nil { + list = append(list, textRecord{Key: formatKey(r.Key), Value: out}) + } + } + if deferredEllipsis { + list.AppendEllipsis(diffStats{}) + } + return &textWrap{Prefix: "{", Value: list, Suffix: "}"} + case diffUnknown: + default: + panic("invalid diff mode") + } + + // Handle differencing. + var numDiffs int + var list textList + var keys []reflect.Value // invariant: len(list) == len(keys) + groups := coalesceAdjacentRecords(name, recs) + maxGroup := diffStats{Name: name} + for i, ds := range groups { + if maxLen >= 0 && numDiffs >= maxLen { + maxGroup = maxGroup.Append(ds) + continue + } + + // Handle equal records. + if ds.NumDiff() == 0 { + // Compute the number of leading and trailing records to print. + var numLo, numHi int + numEqual := ds.NumIgnored + ds.NumIdentical + for numLo < numContextRecords && numLo+numHi < numEqual && i != 0 { + if r := recs[numLo].Value; r.NumIgnored > 0 && r.NumSame+r.NumDiff == 0 { + break + } + numLo++ + } + for numHi < numContextRecords && numLo+numHi < numEqual && i != len(groups)-1 { + if r := recs[numEqual-numHi-1].Value; r.NumIgnored > 0 && r.NumSame+r.NumDiff == 0 { + break + } + numHi++ + } + if numEqual-(numLo+numHi) == 1 && ds.NumIgnored == 0 { + numHi++ // Avoid pointless coalescing of a single equal record + } + + // Format the equal values. + for _, r := range recs[:numLo] { + out := opts.WithDiffMode(diffIdentical).FormatDiff(r.Value, ptrs) + list = append(list, textRecord{Key: formatKey(r.Key), Value: out}) + keys = append(keys, r.Key) + } + if numEqual > numLo+numHi { + ds.NumIdentical -= numLo + numHi + list.AppendEllipsis(ds) + for len(keys) < len(list) { + keys = append(keys, reflect.Value{}) + } + } + for _, r := range recs[numEqual-numHi : numEqual] { + out := opts.WithDiffMode(diffIdentical).FormatDiff(r.Value, ptrs) + list = append(list, textRecord{Key: formatKey(r.Key), Value: out}) + keys = append(keys, r.Key) + } + recs = recs[numEqual:] + continue + } + + // Handle unequal records. + for _, r := range recs[:ds.NumDiff()] { + switch { + case opts.CanFormatDiffSlice(r.Value): + out := opts.FormatDiffSlice(r.Value) + list = append(list, textRecord{Key: formatKey(r.Key), Value: out}) + keys = append(keys, r.Key) + case r.Value.NumChildren == r.Value.MaxDepth: + outx := opts.WithDiffMode(diffRemoved).FormatDiff(r.Value, ptrs) + outy := opts.WithDiffMode(diffInserted).FormatDiff(r.Value, ptrs) + for i := 0; i <= maxVerbosityPreset && outx != nil && outy != nil && outx.Equal(outy); i++ { + opts2 := verbosityPreset(opts, i) + outx = opts2.WithDiffMode(diffRemoved).FormatDiff(r.Value, ptrs) + outy = opts2.WithDiffMode(diffInserted).FormatDiff(r.Value, ptrs) + } + if outx != nil { + list = append(list, textRecord{Diff: diffRemoved, Key: formatKey(r.Key), Value: outx}) + keys = append(keys, r.Key) + } + if outy != nil { + list = append(list, textRecord{Diff: diffInserted, Key: formatKey(r.Key), Value: outy}) + keys = append(keys, r.Key) + } + default: + out := opts.FormatDiff(r.Value, ptrs) + list = append(list, textRecord{Key: formatKey(r.Key), Value: out}) + keys = append(keys, r.Key) + } + } + recs = recs[ds.NumDiff():] + numDiffs += ds.NumDiff() + } + if maxGroup.IsZero() { + assert(len(recs) == 0) + } else { + list.AppendEllipsis(maxGroup) + for len(keys) < len(list) { + keys = append(keys, reflect.Value{}) + } + } + assert(len(list) == len(keys)) + + // For maps, the default formatting logic uses fmt.Stringer which may + // produce ambiguous output. Avoid calling String to disambiguate. + if k == reflect.Map { + var ambiguous bool + seenKeys := map[string]reflect.Value{} + for i, currKey := range keys { + if currKey.IsValid() { + strKey := list[i].Key + prevKey, seen := seenKeys[strKey] + if seen && prevKey.CanInterface() && currKey.CanInterface() { + ambiguous = prevKey.Interface() != currKey.Interface() + if ambiguous { + break + } + } + seenKeys[strKey] = currKey + } + } + if ambiguous { + for i, k := range keys { + if k.IsValid() { + list[i].Key = formatMapKey(k, true, ptrs) + } + } + } + } + + return &textWrap{Prefix: "{", Value: list, Suffix: "}"} +} + +// coalesceAdjacentRecords coalesces the list of records into groups of +// adjacent equal, or unequal counts. +func coalesceAdjacentRecords(name string, recs []reportRecord) (groups []diffStats) { + var prevCase int // Arbitrary index into which case last occurred + lastStats := func(i int) *diffStats { + if prevCase != i { + groups = append(groups, diffStats{Name: name}) + prevCase = i + } + return &groups[len(groups)-1] + } + for _, r := range recs { + switch rv := r.Value; { + case rv.NumIgnored > 0 && rv.NumSame+rv.NumDiff == 0: + lastStats(1).NumIgnored++ + case rv.NumDiff == 0: + lastStats(1).NumIdentical++ + case rv.NumDiff > 0 && !rv.ValueY.IsValid(): + lastStats(2).NumRemoved++ + case rv.NumDiff > 0 && !rv.ValueX.IsValid(): + lastStats(2).NumInserted++ + default: + lastStats(2).NumModified++ + } + } + return groups +} diff --git a/vendor/github.com/google/go-cmp/cmp/report_references.go b/vendor/github.com/google/go-cmp/cmp/report_references.go new file mode 100644 index 00000000000..be31b33a9e1 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/report_references.go @@ -0,0 +1,264 @@ +// Copyright 2020, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cmp + +import ( + "fmt" + "reflect" + "strings" + + "github.com/google/go-cmp/cmp/internal/flags" + "github.com/google/go-cmp/cmp/internal/value" +) + +const ( + pointerDelimPrefix = "⟪" + pointerDelimSuffix = "⟫" +) + +// formatPointer prints the address of the pointer. +func formatPointer(p value.Pointer, withDelims bool) string { + v := p.Uintptr() + if flags.Deterministic { + v = 0xdeadf00f // Only used for stable testing purposes + } + if withDelims { + return pointerDelimPrefix + formatHex(uint64(v)) + pointerDelimSuffix + } + return formatHex(uint64(v)) +} + +// pointerReferences is a stack of pointers visited so far. +type pointerReferences [][2]value.Pointer + +func (ps *pointerReferences) PushPair(vx, vy reflect.Value, d diffMode, deref bool) (pp [2]value.Pointer) { + if deref && vx.IsValid() { + vx = vx.Addr() + } + if deref && vy.IsValid() { + vy = vy.Addr() + } + switch d { + case diffUnknown, diffIdentical: + pp = [2]value.Pointer{value.PointerOf(vx), value.PointerOf(vy)} + case diffRemoved: + pp = [2]value.Pointer{value.PointerOf(vx), value.Pointer{}} + case diffInserted: + pp = [2]value.Pointer{value.Pointer{}, value.PointerOf(vy)} + } + *ps = append(*ps, pp) + return pp +} + +func (ps *pointerReferences) Push(v reflect.Value) (p value.Pointer, seen bool) { + p = value.PointerOf(v) + for _, pp := range *ps { + if p == pp[0] || p == pp[1] { + return p, true + } + } + *ps = append(*ps, [2]value.Pointer{p, p}) + return p, false +} + +func (ps *pointerReferences) Pop() { + *ps = (*ps)[:len(*ps)-1] +} + +// trunkReferences is metadata for a textNode indicating that the sub-tree +// represents the value for either pointer in a pair of references. +type trunkReferences struct{ pp [2]value.Pointer } + +// trunkReference is metadata for a textNode indicating that the sub-tree +// represents the value for the given pointer reference. +type trunkReference struct{ p value.Pointer } + +// leafReference is metadata for a textNode indicating that the value is +// truncated as it refers to another part of the tree (i.e., a trunk). +type leafReference struct{ p value.Pointer } + +func wrapTrunkReferences(pp [2]value.Pointer, s textNode) textNode { + switch { + case pp[0].IsNil(): + return &textWrap{Value: s, Metadata: trunkReference{pp[1]}} + case pp[1].IsNil(): + return &textWrap{Value: s, Metadata: trunkReference{pp[0]}} + case pp[0] == pp[1]: + return &textWrap{Value: s, Metadata: trunkReference{pp[0]}} + default: + return &textWrap{Value: s, Metadata: trunkReferences{pp}} + } +} +func wrapTrunkReference(p value.Pointer, printAddress bool, s textNode) textNode { + var prefix string + if printAddress { + prefix = formatPointer(p, true) + } + return &textWrap{Prefix: prefix, Value: s, Metadata: trunkReference{p}} +} +func makeLeafReference(p value.Pointer, printAddress bool) textNode { + out := &textWrap{Prefix: "(", Value: textEllipsis, Suffix: ")"} + var prefix string + if printAddress { + prefix = formatPointer(p, true) + } + return &textWrap{Prefix: prefix, Value: out, Metadata: leafReference{p}} +} + +// resolveReferences walks the textNode tree searching for any leaf reference +// metadata and resolves each against the corresponding trunk references. +// Since pointer addresses in memory are not particularly readable to the user, +// it replaces each pointer value with an arbitrary and unique reference ID. +func resolveReferences(s textNode) { + var walkNodes func(textNode, func(textNode)) + walkNodes = func(s textNode, f func(textNode)) { + f(s) + switch s := s.(type) { + case *textWrap: + walkNodes(s.Value, f) + case textList: + for _, r := range s { + walkNodes(r.Value, f) + } + } + } + + // Collect all trunks and leaves with reference metadata. + var trunks, leaves []*textWrap + walkNodes(s, func(s textNode) { + if s, ok := s.(*textWrap); ok { + switch s.Metadata.(type) { + case leafReference: + leaves = append(leaves, s) + case trunkReference, trunkReferences: + trunks = append(trunks, s) + } + } + }) + + // No leaf references to resolve. + if len(leaves) == 0 { + return + } + + // Collect the set of all leaf references to resolve. + leafPtrs := make(map[value.Pointer]bool) + for _, leaf := range leaves { + leafPtrs[leaf.Metadata.(leafReference).p] = true + } + + // Collect the set of trunk pointers that are always paired together. + // This allows us to assign a single ID to both pointers for brevity. + // If a pointer in a pair ever occurs by itself or as a different pair, + // then the pair is broken. + pairedTrunkPtrs := make(map[value.Pointer]value.Pointer) + unpair := func(p value.Pointer) { + if !pairedTrunkPtrs[p].IsNil() { + pairedTrunkPtrs[pairedTrunkPtrs[p]] = value.Pointer{} // invalidate other half + } + pairedTrunkPtrs[p] = value.Pointer{} // invalidate this half + } + for _, trunk := range trunks { + switch p := trunk.Metadata.(type) { + case trunkReference: + unpair(p.p) // standalone pointer cannot be part of a pair + case trunkReferences: + p0, ok0 := pairedTrunkPtrs[p.pp[0]] + p1, ok1 := pairedTrunkPtrs[p.pp[1]] + switch { + case !ok0 && !ok1: + // Register the newly seen pair. + pairedTrunkPtrs[p.pp[0]] = p.pp[1] + pairedTrunkPtrs[p.pp[1]] = p.pp[0] + case ok0 && ok1 && p0 == p.pp[1] && p1 == p.pp[0]: + // Exact pair already seen; do nothing. + default: + // Pair conflicts with some other pair; break all pairs. + unpair(p.pp[0]) + unpair(p.pp[1]) + } + } + } + + // Correlate each pointer referenced by leaves to a unique identifier, + // and print the IDs for each trunk that matches those pointers. + var nextID uint + ptrIDs := make(map[value.Pointer]uint) + newID := func() uint { + id := nextID + nextID++ + return id + } + for _, trunk := range trunks { + switch p := trunk.Metadata.(type) { + case trunkReference: + if print := leafPtrs[p.p]; print { + id, ok := ptrIDs[p.p] + if !ok { + id = newID() + ptrIDs[p.p] = id + } + trunk.Prefix = updateReferencePrefix(trunk.Prefix, formatReference(id)) + } + case trunkReferences: + print0 := leafPtrs[p.pp[0]] + print1 := leafPtrs[p.pp[1]] + if print0 || print1 { + id0, ok0 := ptrIDs[p.pp[0]] + id1, ok1 := ptrIDs[p.pp[1]] + isPair := pairedTrunkPtrs[p.pp[0]] == p.pp[1] && pairedTrunkPtrs[p.pp[1]] == p.pp[0] + if isPair { + var id uint + assert(ok0 == ok1) // must be seen together or not at all + if ok0 { + assert(id0 == id1) // must have the same ID + id = id0 + } else { + id = newID() + ptrIDs[p.pp[0]] = id + ptrIDs[p.pp[1]] = id + } + trunk.Prefix = updateReferencePrefix(trunk.Prefix, formatReference(id)) + } else { + if print0 && !ok0 { + id0 = newID() + ptrIDs[p.pp[0]] = id0 + } + if print1 && !ok1 { + id1 = newID() + ptrIDs[p.pp[1]] = id1 + } + switch { + case print0 && print1: + trunk.Prefix = updateReferencePrefix(trunk.Prefix, formatReference(id0)+","+formatReference(id1)) + case print0: + trunk.Prefix = updateReferencePrefix(trunk.Prefix, formatReference(id0)) + case print1: + trunk.Prefix = updateReferencePrefix(trunk.Prefix, formatReference(id1)) + } + } + } + } + } + + // Update all leaf references with the unique identifier. + for _, leaf := range leaves { + if id, ok := ptrIDs[leaf.Metadata.(leafReference).p]; ok { + leaf.Prefix = updateReferencePrefix(leaf.Prefix, formatReference(id)) + } + } +} + +func formatReference(id uint) string { + return fmt.Sprintf("ref#%d", id) +} + +func updateReferencePrefix(prefix, ref string) string { + if prefix == "" { + return pointerDelimPrefix + ref + pointerDelimSuffix + } + suffix := strings.TrimPrefix(prefix, pointerDelimPrefix) + return pointerDelimPrefix + ref + ": " + suffix +} diff --git a/vendor/github.com/google/go-cmp/cmp/report_reflect.go b/vendor/github.com/google/go-cmp/cmp/report_reflect.go new file mode 100644 index 00000000000..2ab41fad3fb --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/report_reflect.go @@ -0,0 +1,414 @@ +// Copyright 2019, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cmp + +import ( + "bytes" + "fmt" + "reflect" + "strconv" + "strings" + "unicode" + "unicode/utf8" + + "github.com/google/go-cmp/cmp/internal/value" +) + +var ( + anyType = reflect.TypeOf((*interface{})(nil)).Elem() + stringType = reflect.TypeOf((*string)(nil)).Elem() + bytesType = reflect.TypeOf((*[]byte)(nil)).Elem() + byteType = reflect.TypeOf((*byte)(nil)).Elem() +) + +type formatValueOptions struct { + // AvoidStringer controls whether to avoid calling custom stringer + // methods like error.Error or fmt.Stringer.String. + AvoidStringer bool + + // PrintAddresses controls whether to print the address of all pointers, + // slice elements, and maps. + PrintAddresses bool + + // QualifiedNames controls whether FormatType uses the fully qualified name + // (including the full package path as opposed to just the package name). + QualifiedNames bool + + // VerbosityLevel controls the amount of output to produce. + // A higher value produces more output. A value of zero or lower produces + // no output (represented using an ellipsis). + // If LimitVerbosity is false, then the level is treated as infinite. + VerbosityLevel int + + // LimitVerbosity specifies that formatting should respect VerbosityLevel. + LimitVerbosity bool +} + +// FormatType prints the type as if it were wrapping s. +// This may return s as-is depending on the current type and TypeMode mode. +func (opts formatOptions) FormatType(t reflect.Type, s textNode) textNode { + // Check whether to emit the type or not. + switch opts.TypeMode { + case autoType: + switch t.Kind() { + case reflect.Struct, reflect.Slice, reflect.Array, reflect.Map: + if s.Equal(textNil) { + return s + } + default: + return s + } + if opts.DiffMode == diffIdentical { + return s // elide type for identical nodes + } + case elideType: + return s + } + + // Determine the type label, applying special handling for unnamed types. + typeName := value.TypeString(t, opts.QualifiedNames) + if t.Name() == "" { + // According to Go grammar, certain type literals contain symbols that + // do not strongly bind to the next lexicographical token (e.g., *T). + switch t.Kind() { + case reflect.Chan, reflect.Func, reflect.Ptr: + typeName = "(" + typeName + ")" + } + } + return &textWrap{Prefix: typeName, Value: wrapParens(s)} +} + +// wrapParens wraps s with a set of parenthesis, but avoids it if the +// wrapped node itself is already surrounded by a pair of parenthesis or braces. +// It handles unwrapping one level of pointer-reference nodes. +func wrapParens(s textNode) textNode { + var refNode *textWrap + if s2, ok := s.(*textWrap); ok { + // Unwrap a single pointer reference node. + switch s2.Metadata.(type) { + case leafReference, trunkReference, trunkReferences: + refNode = s2 + if s3, ok := refNode.Value.(*textWrap); ok { + s2 = s3 + } + } + + // Already has delimiters that make parenthesis unnecessary. + hasParens := strings.HasPrefix(s2.Prefix, "(") && strings.HasSuffix(s2.Suffix, ")") + hasBraces := strings.HasPrefix(s2.Prefix, "{") && strings.HasSuffix(s2.Suffix, "}") + if hasParens || hasBraces { + return s + } + } + if refNode != nil { + refNode.Value = &textWrap{Prefix: "(", Value: refNode.Value, Suffix: ")"} + return s + } + return &textWrap{Prefix: "(", Value: s, Suffix: ")"} +} + +// FormatValue prints the reflect.Value, taking extra care to avoid descending +// into pointers already in ptrs. As pointers are visited, ptrs is also updated. +func (opts formatOptions) FormatValue(v reflect.Value, parentKind reflect.Kind, ptrs *pointerReferences) (out textNode) { + if !v.IsValid() { + return nil + } + t := v.Type() + + // Check slice element for cycles. + if parentKind == reflect.Slice { + ptrRef, visited := ptrs.Push(v.Addr()) + if visited { + return makeLeafReference(ptrRef, false) + } + defer ptrs.Pop() + defer func() { out = wrapTrunkReference(ptrRef, false, out) }() + } + + // Check whether there is an Error or String method to call. + if !opts.AvoidStringer && v.CanInterface() { + // Avoid calling Error or String methods on nil receivers since many + // implementations crash when doing so. + if (t.Kind() != reflect.Ptr && t.Kind() != reflect.Interface) || !v.IsNil() { + var prefix, strVal string + func() { + // Swallow and ignore any panics from String or Error. + defer func() { recover() }() + switch v := v.Interface().(type) { + case error: + strVal = v.Error() + prefix = "e" + case fmt.Stringer: + strVal = v.String() + prefix = "s" + } + }() + if prefix != "" { + return opts.formatString(prefix, strVal) + } + } + } + + // Check whether to explicitly wrap the result with the type. + var skipType bool + defer func() { + if !skipType { + out = opts.FormatType(t, out) + } + }() + + switch t.Kind() { + case reflect.Bool: + return textLine(fmt.Sprint(v.Bool())) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return textLine(fmt.Sprint(v.Int())) + case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return textLine(fmt.Sprint(v.Uint())) + case reflect.Uint8: + if parentKind == reflect.Slice || parentKind == reflect.Array { + return textLine(formatHex(v.Uint())) + } + return textLine(fmt.Sprint(v.Uint())) + case reflect.Uintptr: + return textLine(formatHex(v.Uint())) + case reflect.Float32, reflect.Float64: + return textLine(fmt.Sprint(v.Float())) + case reflect.Complex64, reflect.Complex128: + return textLine(fmt.Sprint(v.Complex())) + case reflect.String: + return opts.formatString("", v.String()) + case reflect.UnsafePointer, reflect.Chan, reflect.Func: + return textLine(formatPointer(value.PointerOf(v), true)) + case reflect.Struct: + var list textList + v := makeAddressable(v) // needed for retrieveUnexportedField + maxLen := v.NumField() + if opts.LimitVerbosity { + maxLen = ((1 << opts.verbosity()) >> 1) << 2 // 0, 4, 8, 16, 32, etc... + opts.VerbosityLevel-- + } + for i := 0; i < v.NumField(); i++ { + vv := v.Field(i) + if vv.IsZero() { + continue // Elide fields with zero values + } + if len(list) == maxLen { + list.AppendEllipsis(diffStats{}) + break + } + sf := t.Field(i) + if supportExporters && !isExported(sf.Name) { + vv = retrieveUnexportedField(v, sf, true) + } + s := opts.WithTypeMode(autoType).FormatValue(vv, t.Kind(), ptrs) + list = append(list, textRecord{Key: sf.Name, Value: s}) + } + return &textWrap{Prefix: "{", Value: list, Suffix: "}"} + case reflect.Slice: + if v.IsNil() { + return textNil + } + + // Check whether this is a []byte of text data. + if t.Elem() == byteType { + b := v.Bytes() + isPrintSpace := func(r rune) bool { return unicode.IsPrint(r) || unicode.IsSpace(r) } + if len(b) > 0 && utf8.Valid(b) && len(bytes.TrimFunc(b, isPrintSpace)) == 0 { + out = opts.formatString("", string(b)) + skipType = true + return opts.FormatType(t, out) + } + } + + fallthrough + case reflect.Array: + maxLen := v.Len() + if opts.LimitVerbosity { + maxLen = ((1 << opts.verbosity()) >> 1) << 2 // 0, 4, 8, 16, 32, etc... + opts.VerbosityLevel-- + } + var list textList + for i := 0; i < v.Len(); i++ { + if len(list) == maxLen { + list.AppendEllipsis(diffStats{}) + break + } + s := opts.WithTypeMode(elideType).FormatValue(v.Index(i), t.Kind(), ptrs) + list = append(list, textRecord{Value: s}) + } + + out = &textWrap{Prefix: "{", Value: list, Suffix: "}"} + if t.Kind() == reflect.Slice && opts.PrintAddresses { + header := fmt.Sprintf("ptr:%v, len:%d, cap:%d", formatPointer(value.PointerOf(v), false), v.Len(), v.Cap()) + out = &textWrap{Prefix: pointerDelimPrefix + header + pointerDelimSuffix, Value: out} + } + return out + case reflect.Map: + if v.IsNil() { + return textNil + } + + // Check pointer for cycles. + ptrRef, visited := ptrs.Push(v) + if visited { + return makeLeafReference(ptrRef, opts.PrintAddresses) + } + defer ptrs.Pop() + + maxLen := v.Len() + if opts.LimitVerbosity { + maxLen = ((1 << opts.verbosity()) >> 1) << 2 // 0, 4, 8, 16, 32, etc... + opts.VerbosityLevel-- + } + var list textList + for _, k := range value.SortKeys(v.MapKeys()) { + if len(list) == maxLen { + list.AppendEllipsis(diffStats{}) + break + } + sk := formatMapKey(k, false, ptrs) + sv := opts.WithTypeMode(elideType).FormatValue(v.MapIndex(k), t.Kind(), ptrs) + list = append(list, textRecord{Key: sk, Value: sv}) + } + + out = &textWrap{Prefix: "{", Value: list, Suffix: "}"} + out = wrapTrunkReference(ptrRef, opts.PrintAddresses, out) + return out + case reflect.Ptr: + if v.IsNil() { + return textNil + } + + // Check pointer for cycles. + ptrRef, visited := ptrs.Push(v) + if visited { + out = makeLeafReference(ptrRef, opts.PrintAddresses) + return &textWrap{Prefix: "&", Value: out} + } + defer ptrs.Pop() + + // Skip the name only if this is an unnamed pointer type. + // Otherwise taking the address of a value does not reproduce + // the named pointer type. + if v.Type().Name() == "" { + skipType = true // Let the underlying value print the type instead + } + out = opts.FormatValue(v.Elem(), t.Kind(), ptrs) + out = wrapTrunkReference(ptrRef, opts.PrintAddresses, out) + out = &textWrap{Prefix: "&", Value: out} + return out + case reflect.Interface: + if v.IsNil() { + return textNil + } + // Interfaces accept different concrete types, + // so configure the underlying value to explicitly print the type. + return opts.WithTypeMode(emitType).FormatValue(v.Elem(), t.Kind(), ptrs) + default: + panic(fmt.Sprintf("%v kind not handled", v.Kind())) + } +} + +func (opts formatOptions) formatString(prefix, s string) textNode { + maxLen := len(s) + maxLines := strings.Count(s, "\n") + 1 + if opts.LimitVerbosity { + maxLen = (1 << opts.verbosity()) << 5 // 32, 64, 128, 256, etc... + maxLines = (1 << opts.verbosity()) << 2 // 4, 8, 16, 32, 64, etc... + } + + // For multiline strings, use the triple-quote syntax, + // but only use it when printing removed or inserted nodes since + // we only want the extra verbosity for those cases. + lines := strings.Split(strings.TrimSuffix(s, "\n"), "\n") + isTripleQuoted := len(lines) >= 4 && (opts.DiffMode == '-' || opts.DiffMode == '+') + for i := 0; i < len(lines) && isTripleQuoted; i++ { + lines[i] = strings.TrimPrefix(strings.TrimSuffix(lines[i], "\r"), "\r") // trim leading/trailing carriage returns for legacy Windows endline support + isPrintable := func(r rune) bool { + return unicode.IsPrint(r) || r == '\t' // specially treat tab as printable + } + line := lines[i] + isTripleQuoted = !strings.HasPrefix(strings.TrimPrefix(line, prefix), `"""`) && !strings.HasPrefix(line, "...") && strings.TrimFunc(line, isPrintable) == "" && len(line) <= maxLen + } + if isTripleQuoted { + var list textList + list = append(list, textRecord{Diff: opts.DiffMode, Value: textLine(prefix + `"""`), ElideComma: true}) + for i, line := range lines { + if numElided := len(lines) - i; i == maxLines-1 && numElided > 1 { + comment := commentString(fmt.Sprintf("%d elided lines", numElided)) + list = append(list, textRecord{Diff: opts.DiffMode, Value: textEllipsis, ElideComma: true, Comment: comment}) + break + } + list = append(list, textRecord{Diff: opts.DiffMode, Value: textLine(line), ElideComma: true}) + } + list = append(list, textRecord{Diff: opts.DiffMode, Value: textLine(prefix + `"""`), ElideComma: true}) + return &textWrap{Prefix: "(", Value: list, Suffix: ")"} + } + + // Format the string as a single-line quoted string. + if len(s) > maxLen+len(textEllipsis) { + return textLine(prefix + formatString(s[:maxLen]) + string(textEllipsis)) + } + return textLine(prefix + formatString(s)) +} + +// formatMapKey formats v as if it were a map key. +// The result is guaranteed to be a single line. +func formatMapKey(v reflect.Value, disambiguate bool, ptrs *pointerReferences) string { + var opts formatOptions + opts.DiffMode = diffIdentical + opts.TypeMode = elideType + opts.PrintAddresses = disambiguate + opts.AvoidStringer = disambiguate + opts.QualifiedNames = disambiguate + opts.VerbosityLevel = maxVerbosityPreset + opts.LimitVerbosity = true + s := opts.FormatValue(v, reflect.Map, ptrs).String() + return strings.TrimSpace(s) +} + +// formatString prints s as a double-quoted or backtick-quoted string. +func formatString(s string) string { + // Use quoted string if it the same length as a raw string literal. + // Otherwise, attempt to use the raw string form. + qs := strconv.Quote(s) + if len(qs) == 1+len(s)+1 { + return qs + } + + // Disallow newlines to ensure output is a single line. + // Only allow printable runes for readability purposes. + rawInvalid := func(r rune) bool { + return r == '`' || r == '\n' || !(unicode.IsPrint(r) || r == '\t') + } + if utf8.ValidString(s) && strings.IndexFunc(s, rawInvalid) < 0 { + return "`" + s + "`" + } + return qs +} + +// formatHex prints u as a hexadecimal integer in Go notation. +func formatHex(u uint64) string { + var f string + switch { + case u <= 0xff: + f = "0x%02x" + case u <= 0xffff: + f = "0x%04x" + case u <= 0xffffff: + f = "0x%06x" + case u <= 0xffffffff: + f = "0x%08x" + case u <= 0xffffffffff: + f = "0x%010x" + case u <= 0xffffffffffff: + f = "0x%012x" + case u <= 0xffffffffffffff: + f = "0x%014x" + case u <= 0xffffffffffffffff: + f = "0x%016x" + } + return fmt.Sprintf(f, u) +} diff --git a/vendor/github.com/google/go-cmp/cmp/report_slices.go b/vendor/github.com/google/go-cmp/cmp/report_slices.go new file mode 100644 index 00000000000..23e444f62f3 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/report_slices.go @@ -0,0 +1,614 @@ +// Copyright 2019, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cmp + +import ( + "bytes" + "fmt" + "math" + "reflect" + "strconv" + "strings" + "unicode" + "unicode/utf8" + + "github.com/google/go-cmp/cmp/internal/diff" +) + +// CanFormatDiffSlice reports whether we support custom formatting for nodes +// that are slices of primitive kinds or strings. +func (opts formatOptions) CanFormatDiffSlice(v *valueNode) bool { + switch { + case opts.DiffMode != diffUnknown: + return false // Must be formatting in diff mode + case v.NumDiff == 0: + return false // No differences detected + case !v.ValueX.IsValid() || !v.ValueY.IsValid(): + return false // Both values must be valid + case v.NumIgnored > 0: + return false // Some ignore option was used + case v.NumTransformed > 0: + return false // Some transform option was used + case v.NumCompared > 1: + return false // More than one comparison was used + case v.NumCompared == 1 && v.Type.Name() != "": + // The need for cmp to check applicability of options on every element + // in a slice is a significant performance detriment for large []byte. + // The workaround is to specify Comparer(bytes.Equal), + // which enables cmp to compare []byte more efficiently. + // If they differ, we still want to provide batched diffing. + // The logic disallows named types since they tend to have their own + // String method, with nicer formatting than what this provides. + return false + } + + // Check whether this is an interface with the same concrete types. + t := v.Type + vx, vy := v.ValueX, v.ValueY + if t.Kind() == reflect.Interface && !vx.IsNil() && !vy.IsNil() && vx.Elem().Type() == vy.Elem().Type() { + vx, vy = vx.Elem(), vy.Elem() + t = vx.Type() + } + + // Check whether we provide specialized diffing for this type. + switch t.Kind() { + case reflect.String: + case reflect.Array, reflect.Slice: + // Only slices of primitive types have specialized handling. + switch t.Elem().Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, + reflect.Bool, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128: + default: + return false + } + + // Both slice values have to be non-empty. + if t.Kind() == reflect.Slice && (vx.Len() == 0 || vy.Len() == 0) { + return false + } + + // If a sufficient number of elements already differ, + // use specialized formatting even if length requirement is not met. + if v.NumDiff > v.NumSame { + return true + } + default: + return false + } + + // Use specialized string diffing for longer slices or strings. + const minLength = 32 + return vx.Len() >= minLength && vy.Len() >= minLength +} + +// FormatDiffSlice prints a diff for the slices (or strings) represented by v. +// This provides custom-tailored logic to make printing of differences in +// textual strings and slices of primitive kinds more readable. +func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode { + assert(opts.DiffMode == diffUnknown) + t, vx, vy := v.Type, v.ValueX, v.ValueY + if t.Kind() == reflect.Interface { + vx, vy = vx.Elem(), vy.Elem() + t = vx.Type() + opts = opts.WithTypeMode(emitType) + } + + // Auto-detect the type of the data. + var sx, sy string + var ssx, ssy []string + var isString, isMostlyText, isPureLinedText, isBinary bool + switch { + case t.Kind() == reflect.String: + sx, sy = vx.String(), vy.String() + isString = true + case t.Kind() == reflect.Slice && t.Elem() == byteType: + sx, sy = string(vx.Bytes()), string(vy.Bytes()) + isString = true + case t.Kind() == reflect.Array: + // Arrays need to be addressable for slice operations to work. + vx2, vy2 := reflect.New(t).Elem(), reflect.New(t).Elem() + vx2.Set(vx) + vy2.Set(vy) + vx, vy = vx2, vy2 + } + if isString { + var numTotalRunes, numValidRunes, numLines, lastLineIdx, maxLineLen int + for i, r := range sx + sy { + numTotalRunes++ + if (unicode.IsPrint(r) || unicode.IsSpace(r)) && r != utf8.RuneError { + numValidRunes++ + } + if r == '\n' { + if maxLineLen < i-lastLineIdx { + maxLineLen = i - lastLineIdx + } + lastLineIdx = i + 1 + numLines++ + } + } + isPureText := numValidRunes == numTotalRunes + isMostlyText = float64(numValidRunes) > math.Floor(0.90*float64(numTotalRunes)) + isPureLinedText = isPureText && numLines >= 4 && maxLineLen <= 1024 + isBinary = !isMostlyText + + // Avoid diffing by lines if it produces a significantly more complex + // edit script than diffing by bytes. + if isPureLinedText { + ssx = strings.Split(sx, "\n") + ssy = strings.Split(sy, "\n") + esLines := diff.Difference(len(ssx), len(ssy), func(ix, iy int) diff.Result { + return diff.BoolResult(ssx[ix] == ssy[iy]) + }) + esBytes := diff.Difference(len(sx), len(sy), func(ix, iy int) diff.Result { + return diff.BoolResult(sx[ix] == sy[iy]) + }) + efficiencyLines := float64(esLines.Dist()) / float64(len(esLines)) + efficiencyBytes := float64(esBytes.Dist()) / float64(len(esBytes)) + quotedLength := len(strconv.Quote(sx + sy)) + unquotedLength := len(sx) + len(sy) + escapeExpansionRatio := float64(quotedLength) / float64(unquotedLength) + isPureLinedText = efficiencyLines < 4*efficiencyBytes || escapeExpansionRatio > 1.1 + } + } + + // Format the string into printable records. + var list textList + var delim string + switch { + // If the text appears to be multi-lined text, + // then perform differencing across individual lines. + case isPureLinedText: + list = opts.formatDiffSlice( + reflect.ValueOf(ssx), reflect.ValueOf(ssy), 1, "line", + func(v reflect.Value, d diffMode) textRecord { + s := formatString(v.Index(0).String()) + return textRecord{Diff: d, Value: textLine(s)} + }, + ) + delim = "\n" + + // If possible, use a custom triple-quote (""") syntax for printing + // differences in a string literal. This format is more readable, + // but has edge-cases where differences are visually indistinguishable. + // This format is avoided under the following conditions: + // - A line starts with `"""` + // - A line starts with "..." + // - A line contains non-printable characters + // - Adjacent different lines differ only by whitespace + // + // For example: + // + // """ + // ... // 3 identical lines + // foo + // bar + // - baz + // + BAZ + // """ + isTripleQuoted := true + prevRemoveLines := map[string]bool{} + prevInsertLines := map[string]bool{} + var list2 textList + list2 = append(list2, textRecord{Value: textLine(`"""`), ElideComma: true}) + for _, r := range list { + if !r.Value.Equal(textEllipsis) { + line, _ := strconv.Unquote(string(r.Value.(textLine))) + line = strings.TrimPrefix(strings.TrimSuffix(line, "\r"), "\r") // trim leading/trailing carriage returns for legacy Windows endline support + normLine := strings.Map(func(r rune) rune { + if unicode.IsSpace(r) { + return -1 // drop whitespace to avoid visually indistinguishable output + } + return r + }, line) + isPrintable := func(r rune) bool { + return unicode.IsPrint(r) || r == '\t' // specially treat tab as printable + } + isTripleQuoted = !strings.HasPrefix(line, `"""`) && !strings.HasPrefix(line, "...") && strings.TrimFunc(line, isPrintable) == "" + switch r.Diff { + case diffRemoved: + isTripleQuoted = isTripleQuoted && !prevInsertLines[normLine] + prevRemoveLines[normLine] = true + case diffInserted: + isTripleQuoted = isTripleQuoted && !prevRemoveLines[normLine] + prevInsertLines[normLine] = true + } + if !isTripleQuoted { + break + } + r.Value = textLine(line) + r.ElideComma = true + } + if !(r.Diff == diffRemoved || r.Diff == diffInserted) { // start a new non-adjacent difference group + prevRemoveLines = map[string]bool{} + prevInsertLines = map[string]bool{} + } + list2 = append(list2, r) + } + if r := list2[len(list2)-1]; r.Diff == diffIdentical && len(r.Value.(textLine)) == 0 { + list2 = list2[:len(list2)-1] // elide single empty line at the end + } + list2 = append(list2, textRecord{Value: textLine(`"""`), ElideComma: true}) + if isTripleQuoted { + var out textNode = &textWrap{Prefix: "(", Value: list2, Suffix: ")"} + switch t.Kind() { + case reflect.String: + if t != stringType { + out = opts.FormatType(t, out) + } + case reflect.Slice: + // Always emit type for slices since the triple-quote syntax + // looks like a string (not a slice). + opts = opts.WithTypeMode(emitType) + out = opts.FormatType(t, out) + } + return out + } + + // If the text appears to be single-lined text, + // then perform differencing in approximately fixed-sized chunks. + // The output is printed as quoted strings. + case isMostlyText: + list = opts.formatDiffSlice( + reflect.ValueOf(sx), reflect.ValueOf(sy), 64, "byte", + func(v reflect.Value, d diffMode) textRecord { + s := formatString(v.String()) + return textRecord{Diff: d, Value: textLine(s)} + }, + ) + + // If the text appears to be binary data, + // then perform differencing in approximately fixed-sized chunks. + // The output is inspired by hexdump. + case isBinary: + list = opts.formatDiffSlice( + reflect.ValueOf(sx), reflect.ValueOf(sy), 16, "byte", + func(v reflect.Value, d diffMode) textRecord { + var ss []string + for i := 0; i < v.Len(); i++ { + ss = append(ss, formatHex(v.Index(i).Uint())) + } + s := strings.Join(ss, ", ") + comment := commentString(fmt.Sprintf("%c|%v|", d, formatASCII(v.String()))) + return textRecord{Diff: d, Value: textLine(s), Comment: comment} + }, + ) + + // For all other slices of primitive types, + // then perform differencing in approximately fixed-sized chunks. + // The size of each chunk depends on the width of the element kind. + default: + var chunkSize int + if t.Elem().Kind() == reflect.Bool { + chunkSize = 16 + } else { + switch t.Elem().Bits() { + case 8: + chunkSize = 16 + case 16: + chunkSize = 12 + case 32: + chunkSize = 8 + default: + chunkSize = 8 + } + } + list = opts.formatDiffSlice( + vx, vy, chunkSize, t.Elem().Kind().String(), + func(v reflect.Value, d diffMode) textRecord { + var ss []string + for i := 0; i < v.Len(); i++ { + switch t.Elem().Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + ss = append(ss, fmt.Sprint(v.Index(i).Int())) + case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64: + ss = append(ss, fmt.Sprint(v.Index(i).Uint())) + case reflect.Uint8, reflect.Uintptr: + ss = append(ss, formatHex(v.Index(i).Uint())) + case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128: + ss = append(ss, fmt.Sprint(v.Index(i).Interface())) + } + } + s := strings.Join(ss, ", ") + return textRecord{Diff: d, Value: textLine(s)} + }, + ) + } + + // Wrap the output with appropriate type information. + var out textNode = &textWrap{Prefix: "{", Value: list, Suffix: "}"} + if !isMostlyText { + // The "{...}" byte-sequence literal is not valid Go syntax for strings. + // Emit the type for extra clarity (e.g. "string{...}"). + if t.Kind() == reflect.String { + opts = opts.WithTypeMode(emitType) + } + return opts.FormatType(t, out) + } + switch t.Kind() { + case reflect.String: + out = &textWrap{Prefix: "strings.Join(", Value: out, Suffix: fmt.Sprintf(", %q)", delim)} + if t != stringType { + out = opts.FormatType(t, out) + } + case reflect.Slice: + out = &textWrap{Prefix: "bytes.Join(", Value: out, Suffix: fmt.Sprintf(", %q)", delim)} + if t != bytesType { + out = opts.FormatType(t, out) + } + } + return out +} + +// formatASCII formats s as an ASCII string. +// This is useful for printing binary strings in a semi-legible way. +func formatASCII(s string) string { + b := bytes.Repeat([]byte{'.'}, len(s)) + for i := 0; i < len(s); i++ { + if ' ' <= s[i] && s[i] <= '~' { + b[i] = s[i] + } + } + return string(b) +} + +func (opts formatOptions) formatDiffSlice( + vx, vy reflect.Value, chunkSize int, name string, + makeRec func(reflect.Value, diffMode) textRecord, +) (list textList) { + eq := func(ix, iy int) bool { + return vx.Index(ix).Interface() == vy.Index(iy).Interface() + } + es := diff.Difference(vx.Len(), vy.Len(), func(ix, iy int) diff.Result { + return diff.BoolResult(eq(ix, iy)) + }) + + appendChunks := func(v reflect.Value, d diffMode) int { + n0 := v.Len() + for v.Len() > 0 { + n := chunkSize + if n > v.Len() { + n = v.Len() + } + list = append(list, makeRec(v.Slice(0, n), d)) + v = v.Slice(n, v.Len()) + } + return n0 - v.Len() + } + + var numDiffs int + maxLen := -1 + if opts.LimitVerbosity { + maxLen = (1 << opts.verbosity()) << 2 // 4, 8, 16, 32, 64, etc... + opts.VerbosityLevel-- + } + + groups := coalesceAdjacentEdits(name, es) + groups = coalesceInterveningIdentical(groups, chunkSize/4) + groups = cleanupSurroundingIdentical(groups, eq) + maxGroup := diffStats{Name: name} + for i, ds := range groups { + if maxLen >= 0 && numDiffs >= maxLen { + maxGroup = maxGroup.Append(ds) + continue + } + + // Print equal. + if ds.NumDiff() == 0 { + // Compute the number of leading and trailing equal bytes to print. + var numLo, numHi int + numEqual := ds.NumIgnored + ds.NumIdentical + for numLo < chunkSize*numContextRecords && numLo+numHi < numEqual && i != 0 { + numLo++ + } + for numHi < chunkSize*numContextRecords && numLo+numHi < numEqual && i != len(groups)-1 { + numHi++ + } + if numEqual-(numLo+numHi) <= chunkSize && ds.NumIgnored == 0 { + numHi = numEqual - numLo // Avoid pointless coalescing of single equal row + } + + // Print the equal bytes. + appendChunks(vx.Slice(0, numLo), diffIdentical) + if numEqual > numLo+numHi { + ds.NumIdentical -= numLo + numHi + list.AppendEllipsis(ds) + } + appendChunks(vx.Slice(numEqual-numHi, numEqual), diffIdentical) + vx = vx.Slice(numEqual, vx.Len()) + vy = vy.Slice(numEqual, vy.Len()) + continue + } + + // Print unequal. + len0 := len(list) + nx := appendChunks(vx.Slice(0, ds.NumIdentical+ds.NumRemoved+ds.NumModified), diffRemoved) + vx = vx.Slice(nx, vx.Len()) + ny := appendChunks(vy.Slice(0, ds.NumIdentical+ds.NumInserted+ds.NumModified), diffInserted) + vy = vy.Slice(ny, vy.Len()) + numDiffs += len(list) - len0 + } + if maxGroup.IsZero() { + assert(vx.Len() == 0 && vy.Len() == 0) + } else { + list.AppendEllipsis(maxGroup) + } + return list +} + +// coalesceAdjacentEdits coalesces the list of edits into groups of adjacent +// equal or unequal counts. +// +// Example: +// +// Input: "..XXY...Y" +// Output: [ +// {NumIdentical: 2}, +// {NumRemoved: 2, NumInserted 1}, +// {NumIdentical: 3}, +// {NumInserted: 1}, +// ] +func coalesceAdjacentEdits(name string, es diff.EditScript) (groups []diffStats) { + var prevMode byte + lastStats := func(mode byte) *diffStats { + if prevMode != mode { + groups = append(groups, diffStats{Name: name}) + prevMode = mode + } + return &groups[len(groups)-1] + } + for _, e := range es { + switch e { + case diff.Identity: + lastStats('=').NumIdentical++ + case diff.UniqueX: + lastStats('!').NumRemoved++ + case diff.UniqueY: + lastStats('!').NumInserted++ + case diff.Modified: + lastStats('!').NumModified++ + } + } + return groups +} + +// coalesceInterveningIdentical coalesces sufficiently short (<= windowSize) +// equal groups into adjacent unequal groups that currently result in a +// dual inserted/removed printout. This acts as a high-pass filter to smooth +// out high-frequency changes within the windowSize. +// +// Example: +// +// WindowSize: 16, +// Input: [ +// {NumIdentical: 61}, // group 0 +// {NumRemoved: 3, NumInserted: 1}, // group 1 +// {NumIdentical: 6}, // ├── coalesce +// {NumInserted: 2}, // ├── coalesce +// {NumIdentical: 1}, // ├── coalesce +// {NumRemoved: 9}, // └── coalesce +// {NumIdentical: 64}, // group 2 +// {NumRemoved: 3, NumInserted: 1}, // group 3 +// {NumIdentical: 6}, // ├── coalesce +// {NumInserted: 2}, // ├── coalesce +// {NumIdentical: 1}, // ├── coalesce +// {NumRemoved: 7}, // ├── coalesce +// {NumIdentical: 1}, // ├── coalesce +// {NumRemoved: 2}, // └── coalesce +// {NumIdentical: 63}, // group 4 +// ] +// Output: [ +// {NumIdentical: 61}, +// {NumIdentical: 7, NumRemoved: 12, NumInserted: 3}, +// {NumIdentical: 64}, +// {NumIdentical: 8, NumRemoved: 12, NumInserted: 3}, +// {NumIdentical: 63}, +// ] +func coalesceInterveningIdentical(groups []diffStats, windowSize int) []diffStats { + groups, groupsOrig := groups[:0], groups + for i, ds := range groupsOrig { + if len(groups) >= 2 && ds.NumDiff() > 0 { + prev := &groups[len(groups)-2] // Unequal group + curr := &groups[len(groups)-1] // Equal group + next := &groupsOrig[i] // Unequal group + hadX, hadY := prev.NumRemoved > 0, prev.NumInserted > 0 + hasX, hasY := next.NumRemoved > 0, next.NumInserted > 0 + if ((hadX || hasX) && (hadY || hasY)) && curr.NumIdentical <= windowSize { + *prev = prev.Append(*curr).Append(*next) + groups = groups[:len(groups)-1] // Truncate off equal group + continue + } + } + groups = append(groups, ds) + } + return groups +} + +// cleanupSurroundingIdentical scans through all unequal groups, and +// moves any leading sequence of equal elements to the preceding equal group and +// moves and trailing sequence of equal elements to the succeeding equal group. +// +// This is necessary since coalesceInterveningIdentical may coalesce edit groups +// together such that leading/trailing spans of equal elements becomes possible. +// Note that this can occur even with an optimal diffing algorithm. +// +// Example: +// +// Input: [ +// {NumIdentical: 61}, +// {NumIdentical: 1 , NumRemoved: 11, NumInserted: 2}, // assume 3 leading identical elements +// {NumIdentical: 67}, +// {NumIdentical: 7, NumRemoved: 12, NumInserted: 3}, // assume 10 trailing identical elements +// {NumIdentical: 54}, +// ] +// Output: [ +// {NumIdentical: 64}, // incremented by 3 +// {NumRemoved: 9}, +// {NumIdentical: 67}, +// {NumRemoved: 9}, +// {NumIdentical: 64}, // incremented by 10 +// ] +func cleanupSurroundingIdentical(groups []diffStats, eq func(i, j int) bool) []diffStats { + var ix, iy int // indexes into sequence x and y + for i, ds := range groups { + // Handle equal group. + if ds.NumDiff() == 0 { + ix += ds.NumIdentical + iy += ds.NumIdentical + continue + } + + // Handle unequal group. + nx := ds.NumIdentical + ds.NumRemoved + ds.NumModified + ny := ds.NumIdentical + ds.NumInserted + ds.NumModified + var numLeadingIdentical, numTrailingIdentical int + for j := 0; j < nx && j < ny && eq(ix+j, iy+j); j++ { + numLeadingIdentical++ + } + for j := 0; j < nx && j < ny && eq(ix+nx-1-j, iy+ny-1-j); j++ { + numTrailingIdentical++ + } + if numIdentical := numLeadingIdentical + numTrailingIdentical; numIdentical > 0 { + if numLeadingIdentical > 0 { + // Remove leading identical span from this group and + // insert it into the preceding group. + if i-1 >= 0 { + groups[i-1].NumIdentical += numLeadingIdentical + } else { + // No preceding group exists, so prepend a new group, + // but do so after we finish iterating over all groups. + defer func() { + groups = append([]diffStats{{Name: groups[0].Name, NumIdentical: numLeadingIdentical}}, groups...) + }() + } + // Increment indexes since the preceding group would have handled this. + ix += numLeadingIdentical + iy += numLeadingIdentical + } + if numTrailingIdentical > 0 { + // Remove trailing identical span from this group and + // insert it into the succeeding group. + if i+1 < len(groups) { + groups[i+1].NumIdentical += numTrailingIdentical + } else { + // No succeeding group exists, so append a new group, + // but do so after we finish iterating over all groups. + defer func() { + groups = append(groups, diffStats{Name: groups[len(groups)-1].Name, NumIdentical: numTrailingIdentical}) + }() + } + // Do not increment indexes since the succeeding group will handle this. + } + + // Update this group since some identical elements were removed. + nx -= numIdentical + ny -= numIdentical + groups[i] = diffStats{Name: ds.Name, NumRemoved: nx, NumInserted: ny} + } + ix += nx + iy += ny + } + return groups +} diff --git a/vendor/github.com/google/go-cmp/cmp/report_text.go b/vendor/github.com/google/go-cmp/cmp/report_text.go new file mode 100644 index 00000000000..388fcf57120 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/report_text.go @@ -0,0 +1,432 @@ +// Copyright 2019, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cmp + +import ( + "bytes" + "fmt" + "math/rand" + "strings" + "time" + "unicode/utf8" + + "github.com/google/go-cmp/cmp/internal/flags" +) + +var randBool = rand.New(rand.NewSource(time.Now().Unix())).Intn(2) == 0 + +const maxColumnLength = 80 + +type indentMode int + +func (n indentMode) appendIndent(b []byte, d diffMode) []byte { + // The output of Diff is documented as being unstable to provide future + // flexibility in changing the output for more humanly readable reports. + // This logic intentionally introduces instability to the exact output + // so that users can detect accidental reliance on stability early on, + // rather than much later when an actual change to the format occurs. + if flags.Deterministic || randBool { + // Use regular spaces (U+0020). + switch d { + case diffUnknown, diffIdentical: + b = append(b, " "...) + case diffRemoved: + b = append(b, "- "...) + case diffInserted: + b = append(b, "+ "...) + } + } else { + // Use non-breaking spaces (U+00a0). + switch d { + case diffUnknown, diffIdentical: + b = append(b, "  "...) + case diffRemoved: + b = append(b, "- "...) + case diffInserted: + b = append(b, "+ "...) + } + } + return repeatCount(n).appendChar(b, '\t') +} + +type repeatCount int + +func (n repeatCount) appendChar(b []byte, c byte) []byte { + for ; n > 0; n-- { + b = append(b, c) + } + return b +} + +// textNode is a simplified tree-based representation of structured text. +// Possible node types are textWrap, textList, or textLine. +type textNode interface { + // Len reports the length in bytes of a single-line version of the tree. + // Nested textRecord.Diff and textRecord.Comment fields are ignored. + Len() int + // Equal reports whether the two trees are structurally identical. + // Nested textRecord.Diff and textRecord.Comment fields are compared. + Equal(textNode) bool + // String returns the string representation of the text tree. + // It is not guaranteed that len(x.String()) == x.Len(), + // nor that x.String() == y.String() implies that x.Equal(y). + String() string + + // formatCompactTo formats the contents of the tree as a single-line string + // to the provided buffer. Any nested textRecord.Diff and textRecord.Comment + // fields are ignored. + // + // However, not all nodes in the tree should be collapsed as a single-line. + // If a node can be collapsed as a single-line, it is replaced by a textLine + // node. Since the top-level node cannot replace itself, this also returns + // the current node itself. + // + // This does not mutate the receiver. + formatCompactTo([]byte, diffMode) ([]byte, textNode) + // formatExpandedTo formats the contents of the tree as a multi-line string + // to the provided buffer. In order for column alignment to operate well, + // formatCompactTo must be called before calling formatExpandedTo. + formatExpandedTo([]byte, diffMode, indentMode) []byte +} + +// textWrap is a wrapper that concatenates a prefix and/or a suffix +// to the underlying node. +type textWrap struct { + Prefix string // e.g., "bytes.Buffer{" + Value textNode // textWrap | textList | textLine + Suffix string // e.g., "}" + Metadata interface{} // arbitrary metadata; has no effect on formatting +} + +func (s *textWrap) Len() int { + return len(s.Prefix) + s.Value.Len() + len(s.Suffix) +} +func (s1 *textWrap) Equal(s2 textNode) bool { + if s2, ok := s2.(*textWrap); ok { + return s1.Prefix == s2.Prefix && s1.Value.Equal(s2.Value) && s1.Suffix == s2.Suffix + } + return false +} +func (s *textWrap) String() string { + var d diffMode + var n indentMode + _, s2 := s.formatCompactTo(nil, d) + b := n.appendIndent(nil, d) // Leading indent + b = s2.formatExpandedTo(b, d, n) // Main body + b = append(b, '\n') // Trailing newline + return string(b) +} +func (s *textWrap) formatCompactTo(b []byte, d diffMode) ([]byte, textNode) { + n0 := len(b) // Original buffer length + b = append(b, s.Prefix...) + b, s.Value = s.Value.formatCompactTo(b, d) + b = append(b, s.Suffix...) + if _, ok := s.Value.(textLine); ok { + return b, textLine(b[n0:]) + } + return b, s +} +func (s *textWrap) formatExpandedTo(b []byte, d diffMode, n indentMode) []byte { + b = append(b, s.Prefix...) + b = s.Value.formatExpandedTo(b, d, n) + b = append(b, s.Suffix...) + return b +} + +// textList is a comma-separated list of textWrap or textLine nodes. +// The list may be formatted as multi-lines or single-line at the discretion +// of the textList.formatCompactTo method. +type textList []textRecord +type textRecord struct { + Diff diffMode // e.g., 0 or '-' or '+' + Key string // e.g., "MyField" + Value textNode // textWrap | textLine + ElideComma bool // avoid trailing comma + Comment fmt.Stringer // e.g., "6 identical fields" +} + +// AppendEllipsis appends a new ellipsis node to the list if none already +// exists at the end. If cs is non-zero it coalesces the statistics with the +// previous diffStats. +func (s *textList) AppendEllipsis(ds diffStats) { + hasStats := !ds.IsZero() + if len(*s) == 0 || !(*s)[len(*s)-1].Value.Equal(textEllipsis) { + if hasStats { + *s = append(*s, textRecord{Value: textEllipsis, ElideComma: true, Comment: ds}) + } else { + *s = append(*s, textRecord{Value: textEllipsis, ElideComma: true}) + } + return + } + if hasStats { + (*s)[len(*s)-1].Comment = (*s)[len(*s)-1].Comment.(diffStats).Append(ds) + } +} + +func (s textList) Len() (n int) { + for i, r := range s { + n += len(r.Key) + if r.Key != "" { + n += len(": ") + } + n += r.Value.Len() + if i < len(s)-1 { + n += len(", ") + } + } + return n +} + +func (s1 textList) Equal(s2 textNode) bool { + if s2, ok := s2.(textList); ok { + if len(s1) != len(s2) { + return false + } + for i := range s1 { + r1, r2 := s1[i], s2[i] + if !(r1.Diff == r2.Diff && r1.Key == r2.Key && r1.Value.Equal(r2.Value) && r1.Comment == r2.Comment) { + return false + } + } + return true + } + return false +} + +func (s textList) String() string { + return (&textWrap{Prefix: "{", Value: s, Suffix: "}"}).String() +} + +func (s textList) formatCompactTo(b []byte, d diffMode) ([]byte, textNode) { + s = append(textList(nil), s...) // Avoid mutating original + + // Determine whether we can collapse this list as a single line. + n0 := len(b) // Original buffer length + var multiLine bool + for i, r := range s { + if r.Diff == diffInserted || r.Diff == diffRemoved { + multiLine = true + } + b = append(b, r.Key...) + if r.Key != "" { + b = append(b, ": "...) + } + b, s[i].Value = r.Value.formatCompactTo(b, d|r.Diff) + if _, ok := s[i].Value.(textLine); !ok { + multiLine = true + } + if r.Comment != nil { + multiLine = true + } + if i < len(s)-1 { + b = append(b, ", "...) + } + } + // Force multi-lined output when printing a removed/inserted node that + // is sufficiently long. + if (d == diffInserted || d == diffRemoved) && len(b[n0:]) > maxColumnLength { + multiLine = true + } + if !multiLine { + return b, textLine(b[n0:]) + } + return b, s +} + +func (s textList) formatExpandedTo(b []byte, d diffMode, n indentMode) []byte { + alignKeyLens := s.alignLens( + func(r textRecord) bool { + _, isLine := r.Value.(textLine) + return r.Key == "" || !isLine + }, + func(r textRecord) int { return utf8.RuneCountInString(r.Key) }, + ) + alignValueLens := s.alignLens( + func(r textRecord) bool { + _, isLine := r.Value.(textLine) + return !isLine || r.Value.Equal(textEllipsis) || r.Comment == nil + }, + func(r textRecord) int { return utf8.RuneCount(r.Value.(textLine)) }, + ) + + // Format lists of simple lists in a batched form. + // If the list is sequence of only textLine values, + // then batch multiple values on a single line. + var isSimple bool + for _, r := range s { + _, isLine := r.Value.(textLine) + isSimple = r.Diff == 0 && r.Key == "" && isLine && r.Comment == nil + if !isSimple { + break + } + } + if isSimple { + n++ + var batch []byte + emitBatch := func() { + if len(batch) > 0 { + b = n.appendIndent(append(b, '\n'), d) + b = append(b, bytes.TrimRight(batch, " ")...) + batch = batch[:0] + } + } + for _, r := range s { + line := r.Value.(textLine) + if len(batch)+len(line)+len(", ") > maxColumnLength { + emitBatch() + } + batch = append(batch, line...) + batch = append(batch, ", "...) + } + emitBatch() + n-- + return n.appendIndent(append(b, '\n'), d) + } + + // Format the list as a multi-lined output. + n++ + for i, r := range s { + b = n.appendIndent(append(b, '\n'), d|r.Diff) + if r.Key != "" { + b = append(b, r.Key+": "...) + } + b = alignKeyLens[i].appendChar(b, ' ') + + b = r.Value.formatExpandedTo(b, d|r.Diff, n) + if !r.ElideComma { + b = append(b, ',') + } + b = alignValueLens[i].appendChar(b, ' ') + + if r.Comment != nil { + b = append(b, " // "+r.Comment.String()...) + } + } + n-- + + return n.appendIndent(append(b, '\n'), d) +} + +func (s textList) alignLens( + skipFunc func(textRecord) bool, + lenFunc func(textRecord) int, +) []repeatCount { + var startIdx, endIdx, maxLen int + lens := make([]repeatCount, len(s)) + for i, r := range s { + if skipFunc(r) { + for j := startIdx; j < endIdx && j < len(s); j++ { + lens[j] = repeatCount(maxLen - lenFunc(s[j])) + } + startIdx, endIdx, maxLen = i+1, i+1, 0 + } else { + if maxLen < lenFunc(r) { + maxLen = lenFunc(r) + } + endIdx = i + 1 + } + } + for j := startIdx; j < endIdx && j < len(s); j++ { + lens[j] = repeatCount(maxLen - lenFunc(s[j])) + } + return lens +} + +// textLine is a single-line segment of text and is always a leaf node +// in the textNode tree. +type textLine []byte + +var ( + textNil = textLine("nil") + textEllipsis = textLine("...") +) + +func (s textLine) Len() int { + return len(s) +} +func (s1 textLine) Equal(s2 textNode) bool { + if s2, ok := s2.(textLine); ok { + return bytes.Equal([]byte(s1), []byte(s2)) + } + return false +} +func (s textLine) String() string { + return string(s) +} +func (s textLine) formatCompactTo(b []byte, d diffMode) ([]byte, textNode) { + return append(b, s...), s +} +func (s textLine) formatExpandedTo(b []byte, _ diffMode, _ indentMode) []byte { + return append(b, s...) +} + +type diffStats struct { + Name string + NumIgnored int + NumIdentical int + NumRemoved int + NumInserted int + NumModified int +} + +func (s diffStats) IsZero() bool { + s.Name = "" + return s == diffStats{} +} + +func (s diffStats) NumDiff() int { + return s.NumRemoved + s.NumInserted + s.NumModified +} + +func (s diffStats) Append(ds diffStats) diffStats { + assert(s.Name == ds.Name) + s.NumIgnored += ds.NumIgnored + s.NumIdentical += ds.NumIdentical + s.NumRemoved += ds.NumRemoved + s.NumInserted += ds.NumInserted + s.NumModified += ds.NumModified + return s +} + +// String prints a humanly-readable summary of coalesced records. +// +// Example: +// +// diffStats{Name: "Field", NumIgnored: 5}.String() => "5 ignored fields" +func (s diffStats) String() string { + var ss []string + var sum int + labels := [...]string{"ignored", "identical", "removed", "inserted", "modified"} + counts := [...]int{s.NumIgnored, s.NumIdentical, s.NumRemoved, s.NumInserted, s.NumModified} + for i, n := range counts { + if n > 0 { + ss = append(ss, fmt.Sprintf("%d %v", n, labels[i])) + } + sum += n + } + + // Pluralize the name (adjusting for some obscure English grammar rules). + name := s.Name + if sum > 1 { + name += "s" + if strings.HasSuffix(name, "ys") { + name = name[:len(name)-2] + "ies" // e.g., "entrys" => "entries" + } + } + + // Format the list according to English grammar (with Oxford comma). + switch n := len(ss); n { + case 0: + return "" + case 1, 2: + return strings.Join(ss, " and ") + " " + name + default: + return strings.Join(ss[:n-1], ", ") + ", and " + ss[n-1] + " " + name + } +} + +type commentString string + +func (s commentString) String() string { return string(s) } diff --git a/vendor/github.com/google/go-cmp/cmp/report_value.go b/vendor/github.com/google/go-cmp/cmp/report_value.go new file mode 100644 index 00000000000..668d470fd83 --- /dev/null +++ b/vendor/github.com/google/go-cmp/cmp/report_value.go @@ -0,0 +1,121 @@ +// Copyright 2019, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cmp + +import "reflect" + +// valueNode represents a single node within a report, which is a +// structured representation of the value tree, containing information +// regarding which nodes are equal or not. +type valueNode struct { + parent *valueNode + + Type reflect.Type + ValueX reflect.Value + ValueY reflect.Value + + // NumSame is the number of leaf nodes that are equal. + // All descendants are equal only if NumDiff is 0. + NumSame int + // NumDiff is the number of leaf nodes that are not equal. + NumDiff int + // NumIgnored is the number of leaf nodes that are ignored. + NumIgnored int + // NumCompared is the number of leaf nodes that were compared + // using an Equal method or Comparer function. + NumCompared int + // NumTransformed is the number of non-leaf nodes that were transformed. + NumTransformed int + // NumChildren is the number of transitive descendants of this node. + // This counts from zero; thus, leaf nodes have no descendants. + NumChildren int + // MaxDepth is the maximum depth of the tree. This counts from zero; + // thus, leaf nodes have a depth of zero. + MaxDepth int + + // Records is a list of struct fields, slice elements, or map entries. + Records []reportRecord // If populated, implies Value is not populated + + // Value is the result of a transformation, pointer indirect, of + // type assertion. + Value *valueNode // If populated, implies Records is not populated + + // TransformerName is the name of the transformer. + TransformerName string // If non-empty, implies Value is populated +} +type reportRecord struct { + Key reflect.Value // Invalid for slice element + Value *valueNode +} + +func (parent *valueNode) PushStep(ps PathStep) (child *valueNode) { + vx, vy := ps.Values() + child = &valueNode{parent: parent, Type: ps.Type(), ValueX: vx, ValueY: vy} + switch s := ps.(type) { + case StructField: + assert(parent.Value == nil) + parent.Records = append(parent.Records, reportRecord{Key: reflect.ValueOf(s.Name()), Value: child}) + case SliceIndex: + assert(parent.Value == nil) + parent.Records = append(parent.Records, reportRecord{Value: child}) + case MapIndex: + assert(parent.Value == nil) + parent.Records = append(parent.Records, reportRecord{Key: s.Key(), Value: child}) + case Indirect: + assert(parent.Value == nil && parent.Records == nil) + parent.Value = child + case TypeAssertion: + assert(parent.Value == nil && parent.Records == nil) + parent.Value = child + case Transform: + assert(parent.Value == nil && parent.Records == nil) + parent.Value = child + parent.TransformerName = s.Name() + parent.NumTransformed++ + default: + assert(parent == nil) // Must be the root step + } + return child +} + +func (r *valueNode) Report(rs Result) { + assert(r.MaxDepth == 0) // May only be called on leaf nodes + + if rs.ByIgnore() { + r.NumIgnored++ + } else { + if rs.Equal() { + r.NumSame++ + } else { + r.NumDiff++ + } + } + assert(r.NumSame+r.NumDiff+r.NumIgnored == 1) + + if rs.ByMethod() { + r.NumCompared++ + } + if rs.ByFunc() { + r.NumCompared++ + } + assert(r.NumCompared <= 1) +} + +func (child *valueNode) PopStep() (parent *valueNode) { + if child.parent == nil { + return nil + } + parent = child.parent + parent.NumSame += child.NumSame + parent.NumDiff += child.NumDiff + parent.NumIgnored += child.NumIgnored + parent.NumCompared += child.NumCompared + parent.NumTransformed += child.NumTransformed + parent.NumChildren += child.NumChildren + 1 + if parent.MaxDepth < child.MaxDepth+1 { + parent.MaxDepth = child.MaxDepth + 1 + } + return parent +} diff --git a/vendor/github.com/google/uuid/null.go b/vendor/github.com/google/uuid/null.go new file mode 100644 index 00000000000..d7fcbf28651 --- /dev/null +++ b/vendor/github.com/google/uuid/null.go @@ -0,0 +1,118 @@ +// Copyright 2021 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "bytes" + "database/sql/driver" + "encoding/json" + "fmt" +) + +var jsonNull = []byte("null") + +// NullUUID represents a UUID that may be null. +// NullUUID implements the SQL driver.Scanner interface so +// it can be used as a scan destination: +// +// var u uuid.NullUUID +// err := db.QueryRow("SELECT name FROM foo WHERE id=?", id).Scan(&u) +// ... +// if u.Valid { +// // use u.UUID +// } else { +// // NULL value +// } +// +type NullUUID struct { + UUID UUID + Valid bool // Valid is true if UUID is not NULL +} + +// Scan implements the SQL driver.Scanner interface. +func (nu *NullUUID) Scan(value interface{}) error { + if value == nil { + nu.UUID, nu.Valid = Nil, false + return nil + } + + err := nu.UUID.Scan(value) + if err != nil { + nu.Valid = false + return err + } + + nu.Valid = true + return nil +} + +// Value implements the driver Valuer interface. +func (nu NullUUID) Value() (driver.Value, error) { + if !nu.Valid { + return nil, nil + } + // Delegate to UUID Value function + return nu.UUID.Value() +} + +// MarshalBinary implements encoding.BinaryMarshaler. +func (nu NullUUID) MarshalBinary() ([]byte, error) { + if nu.Valid { + return nu.UUID[:], nil + } + + return []byte(nil), nil +} + +// UnmarshalBinary implements encoding.BinaryUnmarshaler. +func (nu *NullUUID) UnmarshalBinary(data []byte) error { + if len(data) != 16 { + return fmt.Errorf("invalid UUID (got %d bytes)", len(data)) + } + copy(nu.UUID[:], data) + nu.Valid = true + return nil +} + +// MarshalText implements encoding.TextMarshaler. +func (nu NullUUID) MarshalText() ([]byte, error) { + if nu.Valid { + return nu.UUID.MarshalText() + } + + return jsonNull, nil +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (nu *NullUUID) UnmarshalText(data []byte) error { + id, err := ParseBytes(data) + if err != nil { + nu.Valid = false + return err + } + nu.UUID = id + nu.Valid = true + return nil +} + +// MarshalJSON implements json.Marshaler. +func (nu NullUUID) MarshalJSON() ([]byte, error) { + if nu.Valid { + return json.Marshal(nu.UUID) + } + + return jsonNull, nil +} + +// UnmarshalJSON implements json.Unmarshaler. +func (nu *NullUUID) UnmarshalJSON(data []byte) error { + if bytes.Equal(data, jsonNull) { + *nu = NullUUID{} + return nil // valid null UUID + } + err := json.Unmarshal(data, &nu.UUID) + nu.Valid = err == nil + return err +} diff --git a/vendor/github.com/google/uuid/uuid.go b/vendor/github.com/google/uuid/uuid.go index 60d26bb50c6..a57207aeb6f 100644 --- a/vendor/github.com/google/uuid/uuid.go +++ b/vendor/github.com/google/uuid/uuid.go @@ -12,6 +12,7 @@ import ( "fmt" "io" "strings" + "sync" ) // A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC @@ -33,7 +34,15 @@ const ( Future // Reserved for future definition. ) -var rander = rand.Reader // random function +const randPoolSize = 16 * 16 + +var ( + rander = rand.Reader // random function + poolEnabled = false + poolMu sync.Mutex + poolPos = randPoolSize // protected with poolMu + pool [randPoolSize]byte // protected with poolMu +) type invalidLengthError struct{ len int } @@ -41,6 +50,12 @@ func (err invalidLengthError) Error() string { return fmt.Sprintf("invalid UUID length: %d", err.len) } +// IsInvalidLengthError is matcher function for custom error invalidLengthError +func IsInvalidLengthError(err error) bool { + _, ok := err.(invalidLengthError) + return ok +} + // Parse decodes s into a UUID or returns an error. Both the standard UUID // forms of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded as well as the @@ -249,3 +264,31 @@ func SetRand(r io.Reader) { } rander = r } + +// EnableRandPool enables internal randomness pool used for Random +// (Version 4) UUID generation. The pool contains random bytes read from +// the random number generator on demand in batches. Enabling the pool +// may improve the UUID generation throughput significantly. +// +// Since the pool is stored on the Go heap, this feature may be a bad fit +// for security sensitive applications. +// +// Both EnableRandPool and DisableRandPool are not thread-safe and should +// only be called when there is no possibility that New or any other +// UUID Version 4 generation function will be called concurrently. +func EnableRandPool() { + poolEnabled = true +} + +// DisableRandPool disables the randomness pool if it was previously +// enabled with EnableRandPool. +// +// Both EnableRandPool and DisableRandPool are not thread-safe and should +// only be called when there is no possibility that New or any other +// UUID Version 4 generation function will be called concurrently. +func DisableRandPool() { + poolEnabled = false + defer poolMu.Unlock() + poolMu.Lock() + poolPos = randPoolSize +} diff --git a/vendor/github.com/google/uuid/version4.go b/vendor/github.com/google/uuid/version4.go index 86160fbd072..7697802e4d1 100644 --- a/vendor/github.com/google/uuid/version4.go +++ b/vendor/github.com/google/uuid/version4.go @@ -27,6 +27,8 @@ func NewString() string { // The strength of the UUIDs is based on the strength of the crypto/rand // package. // +// Uses the randomness pool if it was enabled with EnableRandPool. +// // A note about uniqueness derived from the UUID Wikipedia entry: // // Randomly generated UUIDs have 122 random bits. One's annual risk of being @@ -35,7 +37,10 @@ func NewString() string { // equivalent to the odds of creating a few tens of trillions of UUIDs in a // year and having one duplicate. func NewRandom() (UUID, error) { - return NewRandomFromReader(rander) + if !poolEnabled { + return NewRandomFromReader(rander) + } + return newRandomFromPool() } // NewRandomFromReader returns a UUID based on bytes read from a given io.Reader. @@ -49,3 +54,23 @@ func NewRandomFromReader(r io.Reader) (UUID, error) { uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10 return uuid, nil } + +func newRandomFromPool() (UUID, error) { + var uuid UUID + poolMu.Lock() + if poolPos == randPoolSize { + _, err := io.ReadFull(rander, pool[:]) + if err != nil { + poolMu.Unlock() + return Nil, err + } + poolPos = 0 + } + copy(uuid[:], pool[poolPos:(poolPos+16)]) + poolPos += 16 + poolMu.Unlock() + + uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4 + uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10 + return uuid, nil +} diff --git a/vendor/github.com/googleapis/enterprise-certificate-proxy/LICENSE b/vendor/github.com/googleapis/enterprise-certificate-proxy/LICENSE new file mode 100644 index 00000000000..d6456956733 --- /dev/null +++ b/vendor/github.com/googleapis/enterprise-certificate-proxy/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/googleapis/enterprise-certificate-proxy/client/client.go b/vendor/github.com/googleapis/enterprise-certificate-proxy/client/client.go new file mode 100644 index 00000000000..b3283b81588 --- /dev/null +++ b/vendor/github.com/googleapis/enterprise-certificate-proxy/client/client.go @@ -0,0 +1,185 @@ +// Copyright 2022 Google LLC. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package client is a cross-platform client for the signer binary (a.k.a."EnterpriseCertSigner"). +// +// The signer binary is OS-specific, but exposes a standard set of APIs for the client to use. +package client + +import ( + "crypto" + "crypto/ecdsa" + "crypto/rsa" + "crypto/x509" + "encoding/gob" + "errors" + "fmt" + "io" + "net/rpc" + "os" + "os/exec" + + "github.com/googleapis/enterprise-certificate-proxy/client/util" +) + +const signAPI = "EnterpriseCertSigner.Sign" +const certificateChainAPI = "EnterpriseCertSigner.CertificateChain" +const publicKeyAPI = "EnterpriseCertSigner.Public" + +// A Connection wraps a pair of unidirectional streams as an io.ReadWriteCloser. +type Connection struct { + io.ReadCloser + io.WriteCloser +} + +// Close closes c's underlying ReadCloser and WriteCloser. +func (c *Connection) Close() error { + rerr := c.ReadCloser.Close() + werr := c.WriteCloser.Close() + if rerr != nil { + return rerr + } + return werr +} + +func init() { + gob.Register(crypto.SHA256) + gob.Register(&rsa.PSSOptions{}) +} + +// SignArgs contains arguments to a crypto Signer.Sign method. +type SignArgs struct { + Digest []byte // The content to sign. + Opts crypto.SignerOpts // Options for signing, such as Hash identifier. +} + +// Key implements credential.Credential by holding the executed signer subprocess. +type Key struct { + cmd *exec.Cmd // Pointer to the signer subprocess. + client *rpc.Client // Pointer to the rpc client that communicates with the signer subprocess. + publicKey crypto.PublicKey // Public key of loaded certificate. + chain [][]byte // Certificate chain of loaded certificate. +} + +// CertificateChain returns the credential as a raw X509 cert chain. This contains the public key. +func (k *Key) CertificateChain() [][]byte { + return k.chain +} + +// Close closes the RPC connection and kills the signer subprocess. +// Call this to free up resources when the Key object is no longer needed. +func (k *Key) Close() error { + if err := k.cmd.Process.Kill(); err != nil { + return fmt.Errorf("failed to kill signer process: %w", err) + } + // Wait for cmd to exit and release resources. Since the process is forcefully killed, this + // will return a non-nil error (varies by OS), which we will ignore. + _ = k.cmd.Wait() + // The Pipes connecting the RPC client should have been closed when the signer subprocess was killed. + // Calling `k.client.Close()` before `k.cmd.Process.Kill()` or `k.cmd.Wait()` _will_ cause a segfault. + if err := k.client.Close(); err.Error() != "close |0: file already closed" { + return fmt.Errorf("failed to close RPC connection: %w", err) + } + return nil +} + +// Public returns the public key for this Key. +func (k *Key) Public() crypto.PublicKey { + return k.publicKey +} + +// Sign signs a message digest, using the specified signer options. +func (k *Key) Sign(_ io.Reader, digest []byte, opts crypto.SignerOpts) (signed []byte, err error) { + if opts != nil && opts.HashFunc() != 0 && len(digest) != opts.HashFunc().Size() { + return nil, fmt.Errorf("Digest length of %v bytes does not match Hash function size of %v bytes", len(digest), opts.HashFunc().Size()) + } + err = k.client.Call(signAPI, SignArgs{Digest: digest, Opts: opts}, &signed) + return +} + +// ErrCredUnavailable is a sentinel error that indicates ECP Cred is unavailable, +// possibly due to missing config or missing binary path. +var ErrCredUnavailable = errors.New("Cred is unavailable") + +// Cred spawns a signer subprocess that listens on stdin/stdout to perform certificate +// related operations, including signing messages with the private key. +// +// The signer binary path is read from the specified configFilePath, if provided. +// Otherwise, use the default config file path. +// +// The config file also specifies which certificate the signer should use. +func Cred(configFilePath string) (*Key, error) { + if configFilePath == "" { + configFilePath = util.GetDefaultConfigFilePath() + } + enterpriseCertSignerPath, err := util.LoadSignerBinaryPath(configFilePath) + if err != nil { + if errors.Is(err, util.ErrConfigUnavailable) { + return nil, ErrCredUnavailable + } + return nil, err + } + k := &Key{ + cmd: exec.Command(enterpriseCertSignerPath, configFilePath), + } + + // Redirect errors from subprocess to parent process. + k.cmd.Stderr = os.Stderr + + // RPC client will communicate with subprocess over stdin/stdout. + kin, err := k.cmd.StdinPipe() + if err != nil { + return nil, err + } + kout, err := k.cmd.StdoutPipe() + if err != nil { + return nil, err + } + k.client = rpc.NewClient(&Connection{kout, kin}) + + if err := k.cmd.Start(); err != nil { + return nil, fmt.Errorf("starting enterprise cert signer subprocess: %w", err) + } + + if err := k.client.Call(certificateChainAPI, struct{}{}, &k.chain); err != nil { + return nil, fmt.Errorf("failed to retrieve certificate chain: %w", err) + } + + var publicKeyBytes []byte + if err := k.client.Call(publicKeyAPI, struct{}{}, &publicKeyBytes); err != nil { + return nil, fmt.Errorf("failed to retrieve public key: %w", err) + } + + publicKey, err := x509.ParsePKIXPublicKey(publicKeyBytes) + if err != nil { + return nil, fmt.Errorf("failed to parse public key: %w", err) + } + + var ok bool + k.publicKey, ok = publicKey.(crypto.PublicKey) + if !ok { + return nil, fmt.Errorf("invalid public key type: %T", publicKey) + } + + switch pub := k.publicKey.(type) { + case *rsa.PublicKey: + if pub.Size() < 256 { + return nil, fmt.Errorf("RSA modulus size is less than 2048 bits: %v", pub.Size()*8) + } + case *ecdsa.PublicKey: + default: + return nil, fmt.Errorf("unsupported public key type: %v", pub) + } + + return k, nil +} diff --git a/vendor/github.com/googleapis/enterprise-certificate-proxy/client/util/util.go b/vendor/github.com/googleapis/enterprise-certificate-proxy/client/util/util.go new file mode 100644 index 00000000000..1640ec1c9e3 --- /dev/null +++ b/vendor/github.com/googleapis/enterprise-certificate-proxy/client/util/util.go @@ -0,0 +1,91 @@ +// Copyright 2022 Google LLC. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package util provides helper functions for the client. +package util + +import ( + "encoding/json" + "errors" + "io" + "os" + "os/user" + "path/filepath" + "runtime" +) + +const configFileName = "certificate_config.json" + +// EnterpriseCertificateConfig contains parameters for initializing signer. +type EnterpriseCertificateConfig struct { + Libs Libs `json:"libs"` +} + +// Libs specifies the locations of helper libraries. +type Libs struct { + ECP string `json:"ecp"` +} + +// ErrConfigUnavailable is a sentinel error that indicates ECP config is unavailable, +// possibly due to entire config missing or missing binary path. +var ErrConfigUnavailable = errors.New("Config is unavailable") + +// LoadSignerBinaryPath retrieves the path of the signer binary from the config file. +func LoadSignerBinaryPath(configFilePath string) (path string, err error) { + jsonFile, err := os.Open(configFilePath) + if err != nil { + if errors.Is(err, os.ErrNotExist) { + return "", ErrConfigUnavailable + } + return "", err + } + + byteValue, err := io.ReadAll(jsonFile) + if err != nil { + return "", err + } + var config EnterpriseCertificateConfig + err = json.Unmarshal(byteValue, &config) + if err != nil { + return "", err + } + signerBinaryPath := config.Libs.ECP + if signerBinaryPath == "" { + return "", ErrConfigUnavailable + } + return signerBinaryPath, nil +} + +func guessHomeDir() string { + // Prefer $HOME over user.Current due to glibc bug: golang.org/issue/13470 + if v := os.Getenv("HOME"); v != "" { + return v + } + // Else, fall back to user.Current: + if u, err := user.Current(); err == nil { + return u.HomeDir + } + return "" +} + +func getDefaultConfigFileDirectory() (directory string) { + if runtime.GOOS == "windows" { + return filepath.Join(os.Getenv("APPDATA"), "gcloud") + } + return filepath.Join(guessHomeDir(), ".config/gcloud") +} + +// GetDefaultConfigFilePath returns the default path of the enterprise certificate config file created by gCloud. +func GetDefaultConfigFilePath() (path string) { + return filepath.Join(getDefaultConfigFileDirectory(), configFileName) +} diff --git a/vendor/github.com/googleapis/gax-go/v2/.release-please-manifest.json b/vendor/github.com/googleapis/gax-go/v2/.release-please-manifest.json new file mode 100644 index 00000000000..10295639c5a --- /dev/null +++ b/vendor/github.com/googleapis/gax-go/v2/.release-please-manifest.json @@ -0,0 +1,3 @@ +{ + "v2": "2.7.1" +} diff --git a/vendor/github.com/googleapis/gax-go/v2/CHANGES.md b/vendor/github.com/googleapis/gax-go/v2/CHANGES.md new file mode 100644 index 00000000000..41a7ca94d4d --- /dev/null +++ b/vendor/github.com/googleapis/gax-go/v2/CHANGES.md @@ -0,0 +1,54 @@ +# Changelog + +## [2.7.1](https://github.com/googleapis/gax-go/compare/v2.7.0...v2.7.1) (2023-03-06) + + +### Bug Fixes + +* **v2/apierror:** return Unknown GRPCStatus when err source is HTTP ([#260](https://github.com/googleapis/gax-go/issues/260)) ([043b734](https://github.com/googleapis/gax-go/commit/043b73437a240a91229207fb3ee52a9935a36f23)), refs [#254](https://github.com/googleapis/gax-go/issues/254) + +## [2.7.0](https://github.com/googleapis/gax-go/compare/v2.6.0...v2.7.0) (2022-11-02) + + +### Features + +* update google.golang.org/api to latest ([#240](https://github.com/googleapis/gax-go/issues/240)) ([f690a02](https://github.com/googleapis/gax-go/commit/f690a02c806a2903bdee943ede3a58e3a331ebd6)) +* **v2/apierror:** add apierror.FromWrappingError ([#238](https://github.com/googleapis/gax-go/issues/238)) ([9dbd96d](https://github.com/googleapis/gax-go/commit/9dbd96d59b9d54ceb7c025513aa8c1a9d727382f)) + +## [2.6.0](https://github.com/googleapis/gax-go/compare/v2.5.1...v2.6.0) (2022-10-13) + + +### Features + +* **v2:** copy DetermineContentType functionality ([#230](https://github.com/googleapis/gax-go/issues/230)) ([2c52a70](https://github.com/googleapis/gax-go/commit/2c52a70bae965397f740ed27d46aabe89ff249b3)) + +## [2.5.1](https://github.com/googleapis/gax-go/compare/v2.5.0...v2.5.1) (2022-08-04) + + +### Bug Fixes + +* **v2:** resolve bad genproto pseudoversion in go.mod ([#218](https://github.com/googleapis/gax-go/issues/218)) ([1379b27](https://github.com/googleapis/gax-go/commit/1379b27e9846d959f7e1163b9ef298b3c92c8d23)) + +## [2.5.0](https://github.com/googleapis/gax-go/compare/v2.4.0...v2.5.0) (2022-08-04) + + +### Features + +* add ExtractProtoMessage to apierror ([#213](https://github.com/googleapis/gax-go/issues/213)) ([a6ce70c](https://github.com/googleapis/gax-go/commit/a6ce70c725c890533a9de6272d3b5ba2e336d6bb)) + +## [2.4.0](https://github.com/googleapis/gax-go/compare/v2.3.0...v2.4.0) (2022-05-09) + + +### Features + +* **v2:** add OnHTTPCodes CallOption ([#188](https://github.com/googleapis/gax-go/issues/188)) ([ba7c534](https://github.com/googleapis/gax-go/commit/ba7c5348363ab6c33e1cee3c03c0be68a46ca07c)) + + +### Bug Fixes + +* **v2/apierror:** use errors.As in FromError ([#189](https://github.com/googleapis/gax-go/issues/189)) ([f30f05b](https://github.com/googleapis/gax-go/commit/f30f05be583828f4c09cca4091333ea88ff8d79e)) + + +### Miscellaneous Chores + +* **v2:** bump release-please processing ([#192](https://github.com/googleapis/gax-go/issues/192)) ([56172f9](https://github.com/googleapis/gax-go/commit/56172f971d1141d7687edaac053ad3470af76719)) diff --git a/vendor/github.com/googleapis/gax-go/v2/apierror/apierror.go b/vendor/github.com/googleapis/gax-go/v2/apierror/apierror.go new file mode 100644 index 00000000000..ed862c8b398 --- /dev/null +++ b/vendor/github.com/googleapis/gax-go/v2/apierror/apierror.go @@ -0,0 +1,347 @@ +// Copyright 2021, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Package apierror implements a wrapper error for parsing error details from +// API calls. Both HTTP & gRPC status errors are supported. +package apierror + +import ( + "errors" + "fmt" + "strings" + + jsonerror "github.com/googleapis/gax-go/v2/apierror/internal/proto" + "google.golang.org/api/googleapi" + "google.golang.org/genproto/googleapis/rpc/errdetails" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" +) + +// ErrDetails holds the google/rpc/error_details.proto messages. +type ErrDetails struct { + ErrorInfo *errdetails.ErrorInfo + BadRequest *errdetails.BadRequest + PreconditionFailure *errdetails.PreconditionFailure + QuotaFailure *errdetails.QuotaFailure + RetryInfo *errdetails.RetryInfo + ResourceInfo *errdetails.ResourceInfo + RequestInfo *errdetails.RequestInfo + DebugInfo *errdetails.DebugInfo + Help *errdetails.Help + LocalizedMessage *errdetails.LocalizedMessage + + // Unknown stores unidentifiable error details. + Unknown []interface{} +} + +// ErrMessageNotFound is used to signal ExtractProtoMessage found no matching messages. +var ErrMessageNotFound = errors.New("message not found") + +// ExtractProtoMessage provides a mechanism for extracting protobuf messages from the +// Unknown error details. If ExtractProtoMessage finds an unknown message of the same type, +// the content of the message is copied to the provided message. +// +// ExtractProtoMessage will return ErrMessageNotFound if there are no message matching the +// protocol buffer type of the provided message. +func (e ErrDetails) ExtractProtoMessage(v proto.Message) error { + if v == nil { + return ErrMessageNotFound + } + for _, elem := range e.Unknown { + if elemProto, ok := elem.(proto.Message); ok { + if v.ProtoReflect().Type() == elemProto.ProtoReflect().Type() { + proto.Merge(v, elemProto) + return nil + } + } + } + return ErrMessageNotFound +} + +func (e ErrDetails) String() string { + var d strings.Builder + if e.ErrorInfo != nil { + d.WriteString(fmt.Sprintf("error details: name = ErrorInfo reason = %s domain = %s metadata = %s\n", + e.ErrorInfo.GetReason(), e.ErrorInfo.GetDomain(), e.ErrorInfo.GetMetadata())) + } + + if e.BadRequest != nil { + v := e.BadRequest.GetFieldViolations() + var f []string + var desc []string + for _, x := range v { + f = append(f, x.GetField()) + desc = append(desc, x.GetDescription()) + } + d.WriteString(fmt.Sprintf("error details: name = BadRequest field = %s desc = %s\n", + strings.Join(f, " "), strings.Join(desc, " "))) + } + + if e.PreconditionFailure != nil { + v := e.PreconditionFailure.GetViolations() + var t []string + var s []string + var desc []string + for _, x := range v { + t = append(t, x.GetType()) + s = append(s, x.GetSubject()) + desc = append(desc, x.GetDescription()) + } + d.WriteString(fmt.Sprintf("error details: name = PreconditionFailure type = %s subj = %s desc = %s\n", strings.Join(t, " "), + strings.Join(s, " "), strings.Join(desc, " "))) + } + + if e.QuotaFailure != nil { + v := e.QuotaFailure.GetViolations() + var s []string + var desc []string + for _, x := range v { + s = append(s, x.GetSubject()) + desc = append(desc, x.GetDescription()) + } + d.WriteString(fmt.Sprintf("error details: name = QuotaFailure subj = %s desc = %s\n", + strings.Join(s, " "), strings.Join(desc, " "))) + } + + if e.RequestInfo != nil { + d.WriteString(fmt.Sprintf("error details: name = RequestInfo id = %s data = %s\n", + e.RequestInfo.GetRequestId(), e.RequestInfo.GetServingData())) + } + + if e.ResourceInfo != nil { + d.WriteString(fmt.Sprintf("error details: name = ResourceInfo type = %s resourcename = %s owner = %s desc = %s\n", + e.ResourceInfo.GetResourceType(), e.ResourceInfo.GetResourceName(), + e.ResourceInfo.GetOwner(), e.ResourceInfo.GetDescription())) + + } + if e.RetryInfo != nil { + d.WriteString(fmt.Sprintf("error details: retry in %s\n", e.RetryInfo.GetRetryDelay().AsDuration())) + + } + if e.Unknown != nil { + var s []string + for _, x := range e.Unknown { + s = append(s, fmt.Sprintf("%v", x)) + } + d.WriteString(fmt.Sprintf("error details: name = Unknown desc = %s\n", strings.Join(s, " "))) + } + + if e.DebugInfo != nil { + d.WriteString(fmt.Sprintf("error details: name = DebugInfo detail = %s stack = %s\n", e.DebugInfo.GetDetail(), + strings.Join(e.DebugInfo.GetStackEntries(), " "))) + } + if e.Help != nil { + var desc []string + var url []string + for _, x := range e.Help.Links { + desc = append(desc, x.GetDescription()) + url = append(url, x.GetUrl()) + } + d.WriteString(fmt.Sprintf("error details: name = Help desc = %s url = %s\n", + strings.Join(desc, " "), strings.Join(url, " "))) + } + if e.LocalizedMessage != nil { + d.WriteString(fmt.Sprintf("error details: name = LocalizedMessage locale = %s msg = %s\n", + e.LocalizedMessage.GetLocale(), e.LocalizedMessage.GetMessage())) + } + + return d.String() +} + +// APIError wraps either a gRPC Status error or a HTTP googleapi.Error. It +// implements error and Status interfaces. +type APIError struct { + err error + status *status.Status + httpErr *googleapi.Error + details ErrDetails +} + +// Details presents the error details of the APIError. +func (a *APIError) Details() ErrDetails { + return a.details +} + +// Unwrap extracts the original error. +func (a *APIError) Unwrap() error { + return a.err +} + +// Error returns a readable representation of the APIError. +func (a *APIError) Error() string { + var msg string + if a.httpErr != nil { + // Truncate the googleapi.Error message because it dumps the Details in + // an ugly way. + msg = fmt.Sprintf("googleapi: Error %d: %s", a.httpErr.Code, a.httpErr.Message) + } else if a.status != nil { + msg = a.err.Error() + } + return strings.TrimSpace(fmt.Sprintf("%s\n%s", msg, a.details)) +} + +// GRPCStatus extracts the underlying gRPC Status error. +// This method is necessary to fulfill the interface +// described in https://pkg.go.dev/google.golang.org/grpc/status#FromError. +func (a *APIError) GRPCStatus() *status.Status { + return a.status +} + +// Reason returns the reason in an ErrorInfo. +// If ErrorInfo is nil, it returns an empty string. +func (a *APIError) Reason() string { + return a.details.ErrorInfo.GetReason() +} + +// Domain returns the domain in an ErrorInfo. +// If ErrorInfo is nil, it returns an empty string. +func (a *APIError) Domain() string { + return a.details.ErrorInfo.GetDomain() +} + +// Metadata returns the metadata in an ErrorInfo. +// If ErrorInfo is nil, it returns nil. +func (a *APIError) Metadata() map[string]string { + return a.details.ErrorInfo.GetMetadata() + +} + +// setDetailsFromError parses a Status error or a googleapi.Error +// and sets status and details or httpErr and details, respectively. +// It returns false if neither Status nor googleapi.Error can be parsed. +// When err is a googleapi.Error, the status of the returned error will +// be set to an Unknown error, rather than nil, since a nil code is +// interpreted as OK in the gRPC status package. +func (a *APIError) setDetailsFromError(err error) bool { + st, isStatus := status.FromError(err) + var herr *googleapi.Error + isHTTPErr := errors.As(err, &herr) + + switch { + case isStatus: + a.status = st + a.details = parseDetails(st.Details()) + case isHTTPErr: + a.httpErr = herr + a.details = parseHTTPDetails(herr) + a.status = status.New(codes.Unknown, herr.Message) + default: + return false + } + return true +} + +// FromError parses a Status error or a googleapi.Error and builds an +// APIError, wrapping the provided error in the new APIError. It +// returns false if neither Status nor googleapi.Error can be parsed. +func FromError(err error) (*APIError, bool) { + return ParseError(err, true) +} + +// ParseError parses a Status error or a googleapi.Error and builds an +// APIError. If wrap is true, it wraps the error in the new APIError. +// It returns false if neither Status nor googleapi.Error can be parsed. +func ParseError(err error, wrap bool) (*APIError, bool) { + if err == nil { + return nil, false + } + ae := APIError{} + if wrap { + ae = APIError{err: err} + } + if !ae.setDetailsFromError(err) { + return nil, false + } + return &ae, true +} + +// parseDetails accepts a slice of interface{} that should be backed by some +// sort of proto.Message that can be cast to the google/rpc/error_details.proto +// types. +// +// This is for internal use only. +func parseDetails(details []interface{}) ErrDetails { + var ed ErrDetails + for _, d := range details { + switch d := d.(type) { + case *errdetails.ErrorInfo: + ed.ErrorInfo = d + case *errdetails.BadRequest: + ed.BadRequest = d + case *errdetails.PreconditionFailure: + ed.PreconditionFailure = d + case *errdetails.QuotaFailure: + ed.QuotaFailure = d + case *errdetails.RetryInfo: + ed.RetryInfo = d + case *errdetails.ResourceInfo: + ed.ResourceInfo = d + case *errdetails.RequestInfo: + ed.RequestInfo = d + case *errdetails.DebugInfo: + ed.DebugInfo = d + case *errdetails.Help: + ed.Help = d + case *errdetails.LocalizedMessage: + ed.LocalizedMessage = d + default: + ed.Unknown = append(ed.Unknown, d) + } + } + + return ed +} + +// parseHTTPDetails will convert the given googleapi.Error into the protobuf +// representation then parse the Any values that contain the error details. +// +// This is for internal use only. +func parseHTTPDetails(gae *googleapi.Error) ErrDetails { + e := &jsonerror.Error{} + if err := protojson.Unmarshal([]byte(gae.Body), e); err != nil { + // If the error body does not conform to the error schema, ignore it + // altogther. See https://cloud.google.com/apis/design/errors#http_mapping. + return ErrDetails{} + } + + // Coerce the Any messages into proto.Message then parse the details. + details := []interface{}{} + for _, any := range e.GetError().GetDetails() { + m, err := any.UnmarshalNew() + if err != nil { + // Ignore malformed Any values. + continue + } + details = append(details, m) + } + + return parseDetails(details) +} diff --git a/vendor/github.com/googleapis/gax-go/v2/apierror/internal/proto/README.md b/vendor/github.com/googleapis/gax-go/v2/apierror/internal/proto/README.md new file mode 100644 index 00000000000..9ff0caea946 --- /dev/null +++ b/vendor/github.com/googleapis/gax-go/v2/apierror/internal/proto/README.md @@ -0,0 +1,30 @@ +# HTTP JSON Error Schema + +The `error.proto` represents the HTTP-JSON schema used by Google APIs to convey +error payloads as described by https://cloud.google.com/apis/design/errors#http_mapping. +This package is for internal parsing logic only and should not be used in any +other context. + +## Regeneration + +To regenerate the protobuf Go code you will need the following: + +* A local copy of [googleapis], the absolute path to which should be exported to +the environment variable `GOOGLEAPIS` +* The protobuf compiler [protoc] +* The Go [protobuf plugin] +* The [goimports] tool + +From this directory run the following command: +```sh +protoc -I $GOOGLEAPIS -I. --go_out=. --go_opt=module=github.com/googleapis/gax-go/v2/apierror/internal/proto error.proto +goimports -w . +``` + +Note: the `module` plugin option ensures the generated code is placed in this +directory, and not in several nested directories defined by `go_package` option. + +[googleapis]: https://github.com/googleapis/googleapis +[protoc]: https://github.com/protocolbuffers/protobuf#protocol-compiler-installation +[protobuf plugin]: https://developers.google.com/protocol-buffers/docs/reference/go-generated +[goimports]: https://pkg.go.dev/golang.org/x/tools/cmd/goimports \ No newline at end of file diff --git a/vendor/github.com/googleapis/gax-go/v2/apierror/internal/proto/custom_error.pb.go b/vendor/github.com/googleapis/gax-go/v2/apierror/internal/proto/custom_error.pb.go new file mode 100644 index 00000000000..e4b03f161d8 --- /dev/null +++ b/vendor/github.com/googleapis/gax-go/v2/apierror/internal/proto/custom_error.pb.go @@ -0,0 +1,256 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.0 +// protoc v3.17.3 +// source: custom_error.proto + +package jsonerror + +import ( + reflect "reflect" + sync "sync" + + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// Error code for `CustomError`. +type CustomError_CustomErrorCode int32 + +const ( + // Default error. + CustomError_CUSTOM_ERROR_CODE_UNSPECIFIED CustomError_CustomErrorCode = 0 + // Too many foo. + CustomError_TOO_MANY_FOO CustomError_CustomErrorCode = 1 + // Not enough foo. + CustomError_NOT_ENOUGH_FOO CustomError_CustomErrorCode = 2 + // Catastrophic error. + CustomError_UNIVERSE_WAS_DESTROYED CustomError_CustomErrorCode = 3 +) + +// Enum value maps for CustomError_CustomErrorCode. +var ( + CustomError_CustomErrorCode_name = map[int32]string{ + 0: "CUSTOM_ERROR_CODE_UNSPECIFIED", + 1: "TOO_MANY_FOO", + 2: "NOT_ENOUGH_FOO", + 3: "UNIVERSE_WAS_DESTROYED", + } + CustomError_CustomErrorCode_value = map[string]int32{ + "CUSTOM_ERROR_CODE_UNSPECIFIED": 0, + "TOO_MANY_FOO": 1, + "NOT_ENOUGH_FOO": 2, + "UNIVERSE_WAS_DESTROYED": 3, + } +) + +func (x CustomError_CustomErrorCode) Enum() *CustomError_CustomErrorCode { + p := new(CustomError_CustomErrorCode) + *p = x + return p +} + +func (x CustomError_CustomErrorCode) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (CustomError_CustomErrorCode) Descriptor() protoreflect.EnumDescriptor { + return file_custom_error_proto_enumTypes[0].Descriptor() +} + +func (CustomError_CustomErrorCode) Type() protoreflect.EnumType { + return &file_custom_error_proto_enumTypes[0] +} + +func (x CustomError_CustomErrorCode) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use CustomError_CustomErrorCode.Descriptor instead. +func (CustomError_CustomErrorCode) EnumDescriptor() ([]byte, []int) { + return file_custom_error_proto_rawDescGZIP(), []int{0, 0} +} + +// CustomError is an example of a custom error message which may be included +// in an rpc status. It is not meant to reflect a standard error. +type CustomError struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Error code specific to the custom API being invoked. + Code CustomError_CustomErrorCode `protobuf:"varint,1,opt,name=code,proto3,enum=error.CustomError_CustomErrorCode" json:"code,omitempty"` + // Name of the failed entity. + Entity string `protobuf:"bytes,2,opt,name=entity,proto3" json:"entity,omitempty"` + // Message that describes the error. + ErrorMessage string `protobuf:"bytes,3,opt,name=error_message,json=errorMessage,proto3" json:"error_message,omitempty"` +} + +func (x *CustomError) Reset() { + *x = CustomError{} + if protoimpl.UnsafeEnabled { + mi := &file_custom_error_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CustomError) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CustomError) ProtoMessage() {} + +func (x *CustomError) ProtoReflect() protoreflect.Message { + mi := &file_custom_error_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CustomError.ProtoReflect.Descriptor instead. +func (*CustomError) Descriptor() ([]byte, []int) { + return file_custom_error_proto_rawDescGZIP(), []int{0} +} + +func (x *CustomError) GetCode() CustomError_CustomErrorCode { + if x != nil { + return x.Code + } + return CustomError_CUSTOM_ERROR_CODE_UNSPECIFIED +} + +func (x *CustomError) GetEntity() string { + if x != nil { + return x.Entity + } + return "" +} + +func (x *CustomError) GetErrorMessage() string { + if x != nil { + return x.ErrorMessage + } + return "" +} + +var File_custom_error_proto protoreflect.FileDescriptor + +var file_custom_error_proto_rawDesc = []byte{ + 0x0a, 0x12, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0xfa, 0x01, 0x0a, 0x0b, + 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x36, 0x0a, 0x04, 0x63, + 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x65, 0x72, 0x72, 0x6f, + 0x72, 0x2e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x2e, 0x43, 0x75, + 0x73, 0x74, 0x6f, 0x6d, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x63, + 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x23, 0x0a, 0x0d, 0x65, + 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x22, 0x76, 0x0a, 0x0f, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x43, + 0x6f, 0x64, 0x65, 0x12, 0x21, 0x0a, 0x1d, 0x43, 0x55, 0x53, 0x54, 0x4f, 0x4d, 0x5f, 0x45, 0x52, + 0x52, 0x4f, 0x52, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, + 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x54, 0x4f, 0x4f, 0x5f, 0x4d, 0x41, + 0x4e, 0x59, 0x5f, 0x46, 0x4f, 0x4f, 0x10, 0x01, 0x12, 0x12, 0x0a, 0x0e, 0x4e, 0x4f, 0x54, 0x5f, + 0x45, 0x4e, 0x4f, 0x55, 0x47, 0x48, 0x5f, 0x46, 0x4f, 0x4f, 0x10, 0x02, 0x12, 0x1a, 0x0a, 0x16, + 0x55, 0x4e, 0x49, 0x56, 0x45, 0x52, 0x53, 0x45, 0x5f, 0x57, 0x41, 0x53, 0x5f, 0x44, 0x45, 0x53, + 0x54, 0x52, 0x4f, 0x59, 0x45, 0x44, 0x10, 0x03, 0x42, 0x43, 0x5a, 0x41, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, + 0x73, 0x2f, 0x67, 0x61, 0x78, 0x2d, 0x67, 0x6f, 0x2f, 0x76, 0x32, 0x2f, 0x61, 0x70, 0x69, 0x65, + 0x72, 0x72, 0x6f, 0x72, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x3b, 0x6a, 0x73, 0x6f, 0x6e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_custom_error_proto_rawDescOnce sync.Once + file_custom_error_proto_rawDescData = file_custom_error_proto_rawDesc +) + +func file_custom_error_proto_rawDescGZIP() []byte { + file_custom_error_proto_rawDescOnce.Do(func() { + file_custom_error_proto_rawDescData = protoimpl.X.CompressGZIP(file_custom_error_proto_rawDescData) + }) + return file_custom_error_proto_rawDescData +} + +var file_custom_error_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_custom_error_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_custom_error_proto_goTypes = []interface{}{ + (CustomError_CustomErrorCode)(0), // 0: error.CustomError.CustomErrorCode + (*CustomError)(nil), // 1: error.CustomError +} +var file_custom_error_proto_depIdxs = []int32{ + 0, // 0: error.CustomError.code:type_name -> error.CustomError.CustomErrorCode + 1, // [1:1] is the sub-list for method output_type + 1, // [1:1] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_custom_error_proto_init() } +func file_custom_error_proto_init() { + if File_custom_error_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_custom_error_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CustomError); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_custom_error_proto_rawDesc, + NumEnums: 1, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_custom_error_proto_goTypes, + DependencyIndexes: file_custom_error_proto_depIdxs, + EnumInfos: file_custom_error_proto_enumTypes, + MessageInfos: file_custom_error_proto_msgTypes, + }.Build() + File_custom_error_proto = out.File + file_custom_error_proto_rawDesc = nil + file_custom_error_proto_goTypes = nil + file_custom_error_proto_depIdxs = nil +} diff --git a/vendor/github.com/googleapis/gax-go/v2/apierror/internal/proto/custom_error.proto b/vendor/github.com/googleapis/gax-go/v2/apierror/internal/proto/custom_error.proto new file mode 100644 index 00000000000..21678ae65c9 --- /dev/null +++ b/vendor/github.com/googleapis/gax-go/v2/apierror/internal/proto/custom_error.proto @@ -0,0 +1,50 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package error; + +option go_package = "github.com/googleapis/gax-go/v2/apierror/internal/proto;jsonerror"; + + +// CustomError is an example of a custom error message which may be included +// in an rpc status. It is not meant to reflect a standard error. +message CustomError { + + // Error code for `CustomError`. + enum CustomErrorCode { + // Default error. + CUSTOM_ERROR_CODE_UNSPECIFIED = 0; + + // Too many foo. + TOO_MANY_FOO = 1; + + // Not enough foo. + NOT_ENOUGH_FOO = 2; + + // Catastrophic error. + UNIVERSE_WAS_DESTROYED = 3; + + } + + // Error code specific to the custom API being invoked. + CustomErrorCode code = 1; + + // Name of the failed entity. + string entity = 2; + + // Message that describes the error. + string error_message = 3; +} diff --git a/vendor/github.com/googleapis/gax-go/v2/apierror/internal/proto/error.pb.go b/vendor/github.com/googleapis/gax-go/v2/apierror/internal/proto/error.pb.go new file mode 100644 index 00000000000..7dd9b83739a --- /dev/null +++ b/vendor/github.com/googleapis/gax-go/v2/apierror/internal/proto/error.pb.go @@ -0,0 +1,280 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.0 +// protoc v3.15.8 +// source: apierror/internal/proto/error.proto + +package jsonerror + +import ( + reflect "reflect" + sync "sync" + + code "google.golang.org/genproto/googleapis/rpc/code" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + anypb "google.golang.org/protobuf/types/known/anypb" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// The error format v2 for Google JSON REST APIs. +// Copied from https://cloud.google.com/apis/design/errors#http_mapping. +// +// NOTE: This schema is not used for other wire protocols. +type Error struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The actual error payload. The nested message structure is for backward + // compatibility with Google API client libraries. It also makes the error + // more readable to developers. + Error *Error_Status `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *Error) Reset() { + *x = Error{} + if protoimpl.UnsafeEnabled { + mi := &file_apierror_internal_proto_error_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Error) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Error) ProtoMessage() {} + +func (x *Error) ProtoReflect() protoreflect.Message { + mi := &file_apierror_internal_proto_error_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Error.ProtoReflect.Descriptor instead. +func (*Error) Descriptor() ([]byte, []int) { + return file_apierror_internal_proto_error_proto_rawDescGZIP(), []int{0} +} + +func (x *Error) GetError() *Error_Status { + if x != nil { + return x.Error + } + return nil +} + +// This message has the same semantics as `google.rpc.Status`. It uses HTTP +// status code instead of gRPC status code. It has an extra field `status` +// for backward compatibility with Google API Client Libraries. +type Error_Status struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The HTTP status code that corresponds to `google.rpc.Status.code`. + Code int32 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"` + // This corresponds to `google.rpc.Status.message`. + Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` + // This is the enum version for `google.rpc.Status.code`. + Status code.Code `protobuf:"varint,4,opt,name=status,proto3,enum=google.rpc.Code" json:"status,omitempty"` + // This corresponds to `google.rpc.Status.details`. + Details []*anypb.Any `protobuf:"bytes,5,rep,name=details,proto3" json:"details,omitempty"` +} + +func (x *Error_Status) Reset() { + *x = Error_Status{} + if protoimpl.UnsafeEnabled { + mi := &file_apierror_internal_proto_error_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Error_Status) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Error_Status) ProtoMessage() {} + +func (x *Error_Status) ProtoReflect() protoreflect.Message { + mi := &file_apierror_internal_proto_error_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Error_Status.ProtoReflect.Descriptor instead. +func (*Error_Status) Descriptor() ([]byte, []int) { + return file_apierror_internal_proto_error_proto_rawDescGZIP(), []int{0, 0} +} + +func (x *Error_Status) GetCode() int32 { + if x != nil { + return x.Code + } + return 0 +} + +func (x *Error_Status) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +func (x *Error_Status) GetStatus() code.Code { + if x != nil { + return x.Status + } + return code.Code(0) +} + +func (x *Error_Status) GetDetails() []*anypb.Any { + if x != nil { + return x.Details + } + return nil +} + +var File_apierror_internal_proto_error_proto protoreflect.FileDescriptor + +var file_apierror_internal_proto_error_proto_rawDesc = []byte{ + 0x0a, 0x23, 0x61, 0x70, 0x69, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x1a, 0x19, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e, + 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, + 0x72, 0x70, 0x63, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc5, + 0x01, 0x0a, 0x05, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x29, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, + 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x2e, + 0x45, 0x72, 0x72, 0x6f, 0x72, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x05, 0x65, 0x72, + 0x72, 0x6f, 0x72, 0x1a, 0x90, 0x01, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x12, + 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x63, 0x6f, + 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x28, 0x0a, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x10, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x2e, 0x0a, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, + 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x07, 0x64, + 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x42, 0x43, 0x5a, 0x41, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2f, + 0x67, 0x61, 0x78, 0x2d, 0x67, 0x6f, 0x2f, 0x76, 0x32, 0x2f, 0x61, 0x70, 0x69, 0x65, 0x72, 0x72, + 0x6f, 0x72, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x3b, 0x6a, 0x73, 0x6f, 0x6e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, +} + +var ( + file_apierror_internal_proto_error_proto_rawDescOnce sync.Once + file_apierror_internal_proto_error_proto_rawDescData = file_apierror_internal_proto_error_proto_rawDesc +) + +func file_apierror_internal_proto_error_proto_rawDescGZIP() []byte { + file_apierror_internal_proto_error_proto_rawDescOnce.Do(func() { + file_apierror_internal_proto_error_proto_rawDescData = protoimpl.X.CompressGZIP(file_apierror_internal_proto_error_proto_rawDescData) + }) + return file_apierror_internal_proto_error_proto_rawDescData +} + +var file_apierror_internal_proto_error_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_apierror_internal_proto_error_proto_goTypes = []interface{}{ + (*Error)(nil), // 0: error.Error + (*Error_Status)(nil), // 1: error.Error.Status + (code.Code)(0), // 2: google.rpc.Code + (*anypb.Any)(nil), // 3: google.protobuf.Any +} +var file_apierror_internal_proto_error_proto_depIdxs = []int32{ + 1, // 0: error.Error.error:type_name -> error.Error.Status + 2, // 1: error.Error.Status.status:type_name -> google.rpc.Code + 3, // 2: error.Error.Status.details:type_name -> google.protobuf.Any + 3, // [3:3] is the sub-list for method output_type + 3, // [3:3] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name +} + +func init() { file_apierror_internal_proto_error_proto_init() } +func file_apierror_internal_proto_error_proto_init() { + if File_apierror_internal_proto_error_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_apierror_internal_proto_error_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Error); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_apierror_internal_proto_error_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Error_Status); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_apierror_internal_proto_error_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_apierror_internal_proto_error_proto_goTypes, + DependencyIndexes: file_apierror_internal_proto_error_proto_depIdxs, + MessageInfos: file_apierror_internal_proto_error_proto_msgTypes, + }.Build() + File_apierror_internal_proto_error_proto = out.File + file_apierror_internal_proto_error_proto_rawDesc = nil + file_apierror_internal_proto_error_proto_goTypes = nil + file_apierror_internal_proto_error_proto_depIdxs = nil +} diff --git a/vendor/github.com/googleapis/gax-go/v2/apierror/internal/proto/error.proto b/vendor/github.com/googleapis/gax-go/v2/apierror/internal/proto/error.proto new file mode 100644 index 00000000000..4b9b13ce111 --- /dev/null +++ b/vendor/github.com/googleapis/gax-go/v2/apierror/internal/proto/error.proto @@ -0,0 +1,46 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package error; + +import "google/protobuf/any.proto"; +import "google/rpc/code.proto"; + +option go_package = "github.com/googleapis/gax-go/v2/apierror/internal/proto;jsonerror"; + +// The error format v2 for Google JSON REST APIs. +// Copied from https://cloud.google.com/apis/design/errors#http_mapping. +// +// NOTE: This schema is not used for other wire protocols. +message Error { + // This message has the same semantics as `google.rpc.Status`. It uses HTTP + // status code instead of gRPC status code. It has an extra field `status` + // for backward compatibility with Google API Client Libraries. + message Status { + // The HTTP status code that corresponds to `google.rpc.Status.code`. + int32 code = 1; + // This corresponds to `google.rpc.Status.message`. + string message = 2; + // This is the enum version for `google.rpc.Status.code`. + google.rpc.Code status = 4; + // This corresponds to `google.rpc.Status.details`. + repeated google.protobuf.Any details = 5; + } + // The actual error payload. The nested message structure is for backward + // compatibility with Google API client libraries. It also makes the error + // more readable to developers. + Status error = 1; +} diff --git a/vendor/github.com/googleapis/gax-go/v2/call_option.go b/vendor/github.com/googleapis/gax-go/v2/call_option.go index b1d53dd19cb..e092005563b 100644 --- a/vendor/github.com/googleapis/gax-go/v2/call_option.go +++ b/vendor/github.com/googleapis/gax-go/v2/call_option.go @@ -30,9 +30,11 @@ package gax import ( + "errors" "math/rand" "time" + "google.golang.org/api/googleapi" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -47,7 +49,7 @@ type CallOption interface { // Retryer is used by Invoke to determine retry behavior. type Retryer interface { - // Retry reports whether a request should be retriedand how long to pause before retrying + // Retry reports whether a request should be retried and how long to pause before retrying // if the previous attempt returned with err. Invoke never calls Retry with nil error. Retry(err error) (pause time.Duration, shouldRetry bool) } @@ -63,6 +65,31 @@ func WithRetry(fn func() Retryer) CallOption { return retryerOption(fn) } +// OnErrorFunc returns a Retryer that retries if and only if the previous attempt +// returns an error that satisfies shouldRetry. +// +// Pause times between retries are specified by bo. bo is only used for its +// parameters; each Retryer has its own copy. +func OnErrorFunc(bo Backoff, shouldRetry func(err error) bool) Retryer { + return &errorRetryer{ + shouldRetry: shouldRetry, + backoff: bo, + } +} + +type errorRetryer struct { + backoff Backoff + shouldRetry func(err error) bool +} + +func (r *errorRetryer) Retry(err error) (time.Duration, bool) { + if r.shouldRetry(err) { + return r.backoff.Pause(), true + } + + return 0, false +} + // OnCodes returns a Retryer that retries if and only if // the previous attempt returns a GRPC error whose error code is stored in cc. // Pause times between retries are specified by bo. @@ -94,22 +121,60 @@ func (r *boRetryer) Retry(err error) (time.Duration, bool) { return 0, false } -// Backoff implements exponential backoff. -// The wait time between retries is a random value between 0 and the "retry envelope". -// The envelope starts at Initial and increases by the factor of Multiplier every retry, -// but is capped at Max. +// OnHTTPCodes returns a Retryer that retries if and only if +// the previous attempt returns a googleapi.Error whose status code is stored in +// cc. Pause times between retries are specified by bo. +// +// bo is only used for its parameters; each Retryer has its own copy. +func OnHTTPCodes(bo Backoff, cc ...int) Retryer { + codes := make(map[int]bool, len(cc)) + for _, c := range cc { + codes[c] = true + } + + return &httpRetryer{ + backoff: bo, + codes: codes, + } +} + +type httpRetryer struct { + backoff Backoff + codes map[int]bool +} + +func (r *httpRetryer) Retry(err error) (time.Duration, bool) { + var gerr *googleapi.Error + if !errors.As(err, &gerr) { + return 0, false + } + + if r.codes[gerr.Code] { + return r.backoff.Pause(), true + } + + return 0, false +} + +// Backoff implements exponential backoff. The wait time between retries is a +// random value between 0 and the "retry period" - the time between retries. The +// retry period starts at Initial and increases by the factor of Multiplier +// every retry, but is capped at Max. +// +// Note: MaxNumRetries / RPCDeadline is specifically not provided. These should +// be built on top of Backoff. type Backoff struct { - // Initial is the initial value of the retry envelope, defaults to 1 second. + // Initial is the initial value of the retry period, defaults to 1 second. Initial time.Duration - // Max is the maximum value of the retry envelope, defaults to 30 seconds. + // Max is the maximum value of the retry period, defaults to 30 seconds. Max time.Duration - // Multiplier is the factor by which the retry envelope increases. + // Multiplier is the factor by which the retry period increases. // It should be greater than 1 and defaults to 2. Multiplier float64 - // cur is the current retry envelope + // cur is the current retry period. cur time.Duration } @@ -145,6 +210,21 @@ func (o grpcOpt) Resolve(s *CallSettings) { s.GRPC = o } +type pathOpt struct { + p string +} + +func (p pathOpt) Resolve(s *CallSettings) { + s.Path = p.p +} + +// WithPath applies a Path override to the HTTP-based APICall. +// +// This is for internal use only. +func WithPath(p string) CallOption { + return &pathOpt{p: p} +} + // WithGRPCOptions allows passing gRPC call options during client creation. func WithGRPCOptions(opt ...grpc.CallOption) CallOption { return grpcOpt(append([]grpc.CallOption(nil), opt...)) @@ -158,4 +238,7 @@ type CallSettings struct { // CallOptions to be forwarded to GRPC. GRPC []grpc.CallOption + + // Path is an HTTP override for an APICall. + Path string } diff --git a/vendor/github.com/googleapis/gax-go/v2/content_type.go b/vendor/github.com/googleapis/gax-go/v2/content_type.go new file mode 100644 index 00000000000..1b53d0a3ac1 --- /dev/null +++ b/vendor/github.com/googleapis/gax-go/v2/content_type.go @@ -0,0 +1,112 @@ +// Copyright 2022, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package gax + +import ( + "io" + "io/ioutil" + "net/http" +) + +const sniffBuffSize = 512 + +func newContentSniffer(r io.Reader) *contentSniffer { + return &contentSniffer{r: r} +} + +// contentSniffer wraps a Reader, and reports the content type determined by sniffing up to 512 bytes from the Reader. +type contentSniffer struct { + r io.Reader + start []byte // buffer for the sniffed bytes. + err error // set to any error encountered while reading bytes to be sniffed. + + ctype string // set on first sniff. + sniffed bool // set to true on first sniff. +} + +func (cs *contentSniffer) Read(p []byte) (n int, err error) { + // Ensure that the content type is sniffed before any data is consumed from Reader. + _, _ = cs.ContentType() + + if len(cs.start) > 0 { + n := copy(p, cs.start) + cs.start = cs.start[n:] + return n, nil + } + + // We may have read some bytes into start while sniffing, even if the read ended in an error. + // We should first return those bytes, then the error. + if cs.err != nil { + return 0, cs.err + } + + // Now we have handled all bytes that were buffered while sniffing. Now just delegate to the underlying reader. + return cs.r.Read(p) +} + +// ContentType returns the sniffed content type, and whether the content type was successfully sniffed. +func (cs *contentSniffer) ContentType() (string, bool) { + if cs.sniffed { + return cs.ctype, cs.ctype != "" + } + cs.sniffed = true + // If ReadAll hits EOF, it returns err==nil. + cs.start, cs.err = ioutil.ReadAll(io.LimitReader(cs.r, sniffBuffSize)) + + // Don't try to detect the content type based on possibly incomplete data. + if cs.err != nil { + return "", false + } + + cs.ctype = http.DetectContentType(cs.start) + return cs.ctype, true +} + +// DetermineContentType determines the content type of the supplied reader. +// The content of media will be sniffed to determine the content type. +// After calling DetectContentType the caller must not perform further reads on +// media, but rather read from the Reader that is returned. +func DetermineContentType(media io.Reader) (io.Reader, string) { + // For backwards compatibility, allow clients to set content + // type by providing a ContentTyper for media. + // Note: This is an anonymous interface definition copied from googleapi.ContentTyper. + if typer, ok := media.(interface { + ContentType() string + }); ok { + return media, typer.ContentType() + } + + sniffer := newContentSniffer(media) + if ctype, ok := sniffer.ContentType(); ok { + return sniffer, ctype + } + // If content type could not be sniffed, reads from sniffer will eventually fail with an error. + return sniffer, "" +} diff --git a/vendor/github.com/googleapis/gax-go/v2/gax.go b/vendor/github.com/googleapis/gax-go/v2/gax.go index 3fd1b0b84b0..36cdfa33e35 100644 --- a/vendor/github.com/googleapis/gax-go/v2/gax.go +++ b/vendor/github.com/googleapis/gax-go/v2/gax.go @@ -35,5 +35,7 @@ // to simplify code generation and to provide more convenient and idiomatic API surfaces. package gax +import "github.com/googleapis/gax-go/v2/internal" + // Version specifies the gax-go version being used. -const Version = "2.0.4" +const Version = internal.Version diff --git a/vendor/github.com/googleapis/gax-go/v2/internal/version.go b/vendor/github.com/googleapis/gax-go/v2/internal/version.go new file mode 100644 index 00000000000..936873ec4f8 --- /dev/null +++ b/vendor/github.com/googleapis/gax-go/v2/internal/version.go @@ -0,0 +1,33 @@ +// Copyright 2022, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package internal + +// Version is the current tagged release of the library. +const Version = "2.7.1" diff --git a/vendor/github.com/googleapis/gax-go/v2/invoke.go b/vendor/github.com/googleapis/gax-go/v2/invoke.go index fe31dd004e9..9fcc29959b9 100644 --- a/vendor/github.com/googleapis/gax-go/v2/invoke.go +++ b/vendor/github.com/googleapis/gax-go/v2/invoke.go @@ -33,13 +33,15 @@ import ( "context" "strings" "time" + + "github.com/googleapis/gax-go/v2/apierror" ) // APICall is a user defined call stub. type APICall func(context.Context, CallSettings) error -// Invoke calls the given APICall, -// performing retries as specified by opts, if any. +// Invoke calls the given APICall, performing retries as specified by opts, if +// any. func Invoke(ctx context.Context, call APICall, opts ...CallOption) error { var settings CallSettings for _, opt := range opts { @@ -71,9 +73,6 @@ func invoke(ctx context.Context, call APICall, settings CallSettings, sp sleeper if err == nil { return nil } - if settings.Retry == nil { - return err - } // Never retry permanent certificate errors. (e.x. if ca-certificates // are not installed). We should only make very few, targeted // exceptions: many (other) status=Unavailable should be retried, such @@ -83,6 +82,12 @@ func invoke(ctx context.Context, call APICall, settings CallSettings, sp sleeper if strings.Contains(err.Error(), "x509: certificate signed by unknown authority") { return err } + if apierr, ok := apierror.FromError(err); ok { + err = apierr + } + if settings.Retry == nil { + return err + } if retryer == nil { if r := settings.Retry(); r != nil { retryer = r diff --git a/vendor/github.com/googleapis/gax-go/v2/proto_json_stream.go b/vendor/github.com/googleapis/gax-go/v2/proto_json_stream.go new file mode 100644 index 00000000000..cc4486eb9e5 --- /dev/null +++ b/vendor/github.com/googleapis/gax-go/v2/proto_json_stream.go @@ -0,0 +1,126 @@ +// Copyright 2022, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package gax + +import ( + "encoding/json" + "errors" + "io" + + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protoreflect" +) + +var ( + arrayOpen = json.Delim('[') + arrayClose = json.Delim(']') + errBadOpening = errors.New("unexpected opening token, expected '['") +) + +// ProtoJSONStream represents a wrapper for consuming a stream of protobuf +// messages encoded using protobuf-JSON format. More information on this format +// can be found at https://developers.google.com/protocol-buffers/docs/proto3#json. +// The stream must appear as a comma-delimited, JSON array of obbjects with +// opening and closing square braces. +// +// This is for internal use only. +type ProtoJSONStream struct { + first, closed bool + reader io.ReadCloser + stream *json.Decoder + typ protoreflect.MessageType +} + +// NewProtoJSONStreamReader accepts a stream of bytes via an io.ReadCloser that are +// protobuf-JSON encoded protobuf messages of the given type. The ProtoJSONStream +// must be closed when done. +// +// This is for internal use only. +func NewProtoJSONStreamReader(rc io.ReadCloser, typ protoreflect.MessageType) *ProtoJSONStream { + return &ProtoJSONStream{ + first: true, + reader: rc, + stream: json.NewDecoder(rc), + typ: typ, + } +} + +// Recv decodes the next protobuf message in the stream or returns io.EOF if +// the stream is done. It is not safe to call Recv on the same stream from +// different goroutines, just like it is not safe to do so with a single gRPC +// stream. Type-cast the protobuf message returned to the type provided at +// ProtoJSONStream creation. +// Calls to Recv after calling Close will produce io.EOF. +func (s *ProtoJSONStream) Recv() (proto.Message, error) { + if s.closed { + return nil, io.EOF + } + if s.first { + s.first = false + + // Consume the opening '[' so Decode gets one object at a time. + if t, err := s.stream.Token(); err != nil { + return nil, err + } else if t != arrayOpen { + return nil, errBadOpening + } + } + + // Capture the next block of data for the item (a JSON object) in the stream. + var raw json.RawMessage + if err := s.stream.Decode(&raw); err != nil { + e := err + // To avoid checking the first token of each stream, just attempt to + // Decode the next blob and if that fails, double check if it is just + // the closing token ']'. If it is the closing, return io.EOF. If it + // isn't, return the original error. + if t, _ := s.stream.Token(); t == arrayClose { + e = io.EOF + } + return nil, e + } + + // Initialize a new instance of the protobuf message to unmarshal the + // raw data into. + m := s.typ.New().Interface() + err := protojson.Unmarshal(raw, m) + + return m, err +} + +// Close closes the stream so that resources are cleaned up. +func (s *ProtoJSONStream) Close() error { + // Dereference the *json.Decoder so that the memory is gc'd. + s.stream = nil + s.closed = true + + return s.reader.Close() +} diff --git a/vendor/github.com/googleapis/gax-go/v2/release-please-config.json b/vendor/github.com/googleapis/gax-go/v2/release-please-config.json new file mode 100644 index 00000000000..61ee266a159 --- /dev/null +++ b/vendor/github.com/googleapis/gax-go/v2/release-please-config.json @@ -0,0 +1,10 @@ +{ + "release-type": "go-yoshi", + "separate-pull-requests": true, + "include-component-in-tag": false, + "packages": { + "v2": { + "component": "v2" + } + } +} diff --git a/vendor/github.com/jstemmer/go-junit-report/.gitignore b/vendor/github.com/jstemmer/go-junit-report/.gitignore deleted file mode 100644 index 720bda6070d..00000000000 --- a/vendor/github.com/jstemmer/go-junit-report/.gitignore +++ /dev/null @@ -1 +0,0 @@ -go-junit-report diff --git a/vendor/github.com/jstemmer/go-junit-report/.travis.yml b/vendor/github.com/jstemmer/go-junit-report/.travis.yml deleted file mode 100644 index d0dff3ef8e5..00000000000 --- a/vendor/github.com/jstemmer/go-junit-report/.travis.yml +++ /dev/null @@ -1,16 +0,0 @@ -language: go - -go: - - tip - - "1.13.x" - - "1.12.x" - - "1.11.x" - - "1.10.x" - - "1.9.x" - - "1.8.x" - - "1.7.x" - - "1.6.x" - - "1.5.x" - - "1.4.x" - - "1.3.x" - - "1.2.x" diff --git a/vendor/github.com/jstemmer/go-junit-report/LICENSE b/vendor/github.com/jstemmer/go-junit-report/LICENSE deleted file mode 100644 index f346564cefd..00000000000 --- a/vendor/github.com/jstemmer/go-junit-report/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2012 Joel Stemmer - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/jstemmer/go-junit-report/README.md b/vendor/github.com/jstemmer/go-junit-report/README.md deleted file mode 100644 index 5b5f608be3d..00000000000 --- a/vendor/github.com/jstemmer/go-junit-report/README.md +++ /dev/null @@ -1,49 +0,0 @@ -# go-junit-report - -Converts `go test` output to an xml report, suitable for applications that -expect junit xml reports (e.g. [Jenkins](http://jenkins-ci.org)). - -[![Build Status][travis-badge]][travis-link] -[![Report Card][report-badge]][report-link] - -## Installation - -Go version 1.2 or higher is required. Install or update using the `go get` -command: - -```bash -go get -u github.com/jstemmer/go-junit-report -``` - -## Usage - -go-junit-report reads the `go test` verbose output from standard in and writes -junit compatible XML to standard out. - -```bash -go test -v 2>&1 | go-junit-report > report.xml -``` - -Note that it also can parse benchmark output with `-bench` flag: -```bash -go test -v -bench . -count 5 2>&1 | go-junit-report > report.xml -``` - -## Contribution - -Create an Issue and discuss the fix or feature, then fork the package. -Clone to github.com/jstemmer/go-junit-report. This is necessary because go import uses this path. -Fix or implement feature. Test and then commit change. -Specify #Issue and describe change in the commit message. -Create Pull Request. It can be merged by owner or administrator then. - -### Run Tests - -```bash -go test -``` - -[travis-badge]: https://travis-ci.org/jstemmer/go-junit-report.svg -[travis-link]: https://travis-ci.org/jstemmer/go-junit-report -[report-badge]: https://goreportcard.com/badge/github.com/jstemmer/go-junit-report -[report-link]: https://goreportcard.com/report/github.com/jstemmer/go-junit-report diff --git a/vendor/github.com/jstemmer/go-junit-report/formatter/formatter.go b/vendor/github.com/jstemmer/go-junit-report/formatter/formatter.go deleted file mode 100644 index 6e1a0f31d68..00000000000 --- a/vendor/github.com/jstemmer/go-junit-report/formatter/formatter.go +++ /dev/null @@ -1,182 +0,0 @@ -package formatter - -import ( - "bufio" - "encoding/xml" - "fmt" - "io" - "runtime" - "strings" - "time" - - "github.com/jstemmer/go-junit-report/parser" -) - -// JUnitTestSuites is a collection of JUnit test suites. -type JUnitTestSuites struct { - XMLName xml.Name `xml:"testsuites"` - Suites []JUnitTestSuite `xml:"testsuite"` -} - -// JUnitTestSuite is a single JUnit test suite which may contain many -// testcases. -type JUnitTestSuite struct { - XMLName xml.Name `xml:"testsuite"` - Tests int `xml:"tests,attr"` - Failures int `xml:"failures,attr"` - Time string `xml:"time,attr"` - Name string `xml:"name,attr"` - Properties []JUnitProperty `xml:"properties>property,omitempty"` - TestCases []JUnitTestCase `xml:"testcase"` -} - -// JUnitTestCase is a single test case with its result. -type JUnitTestCase struct { - XMLName xml.Name `xml:"testcase"` - Classname string `xml:"classname,attr"` - Name string `xml:"name,attr"` - Time string `xml:"time,attr"` - SkipMessage *JUnitSkipMessage `xml:"skipped,omitempty"` - Failure *JUnitFailure `xml:"failure,omitempty"` -} - -// JUnitSkipMessage contains the reason why a testcase was skipped. -type JUnitSkipMessage struct { - Message string `xml:"message,attr"` -} - -// JUnitProperty represents a key/value pair used to define properties. -type JUnitProperty struct { - Name string `xml:"name,attr"` - Value string `xml:"value,attr"` -} - -// JUnitFailure contains data related to a failed test. -type JUnitFailure struct { - Message string `xml:"message,attr"` - Type string `xml:"type,attr"` - Contents string `xml:",chardata"` -} - -// JUnitReportXML writes a JUnit xml representation of the given report to w -// in the format described at http://windyroad.org/dl/Open%20Source/JUnit.xsd -func JUnitReportXML(report *parser.Report, noXMLHeader bool, goVersion string, w io.Writer) error { - suites := JUnitTestSuites{} - - // convert Report to JUnit test suites - for _, pkg := range report.Packages { - pkg.Benchmarks = mergeBenchmarks(pkg.Benchmarks) - ts := JUnitTestSuite{ - Tests: len(pkg.Tests) + len(pkg.Benchmarks), - Failures: 0, - Time: formatTime(pkg.Duration), - Name: pkg.Name, - Properties: []JUnitProperty{}, - TestCases: []JUnitTestCase{}, - } - - classname := pkg.Name - if idx := strings.LastIndex(classname, "/"); idx > -1 && idx < len(pkg.Name) { - classname = pkg.Name[idx+1:] - } - - // properties - if goVersion == "" { - // if goVersion was not specified as a flag, fall back to version reported by runtime - goVersion = runtime.Version() - } - ts.Properties = append(ts.Properties, JUnitProperty{"go.version", goVersion}) - if pkg.CoveragePct != "" { - ts.Properties = append(ts.Properties, JUnitProperty{"coverage.statements.pct", pkg.CoveragePct}) - } - - // individual test cases - for _, test := range pkg.Tests { - testCase := JUnitTestCase{ - Classname: classname, - Name: test.Name, - Time: formatTime(test.Duration), - Failure: nil, - } - - if test.Result == parser.FAIL { - ts.Failures++ - testCase.Failure = &JUnitFailure{ - Message: "Failed", - Type: "", - Contents: strings.Join(test.Output, "\n"), - } - } - - if test.Result == parser.SKIP { - testCase.SkipMessage = &JUnitSkipMessage{strings.Join(test.Output, "\n")} - } - - ts.TestCases = append(ts.TestCases, testCase) - } - - // individual benchmarks - for _, benchmark := range pkg.Benchmarks { - benchmarkCase := JUnitTestCase{ - Classname: classname, - Name: benchmark.Name, - Time: formatBenchmarkTime(benchmark.Duration), - } - - ts.TestCases = append(ts.TestCases, benchmarkCase) - } - - suites.Suites = append(suites.Suites, ts) - } - - // to xml - bytes, err := xml.MarshalIndent(suites, "", "\t") - if err != nil { - return err - } - - writer := bufio.NewWriter(w) - - if !noXMLHeader { - writer.WriteString(xml.Header) - } - - writer.Write(bytes) - writer.WriteByte('\n') - writer.Flush() - - return nil -} - -func mergeBenchmarks(benchmarks []*parser.Benchmark) []*parser.Benchmark { - var merged []*parser.Benchmark - benchmap := make(map[string][]*parser.Benchmark) - for _, bm := range benchmarks { - if _, ok := benchmap[bm.Name]; !ok { - merged = append(merged, &parser.Benchmark{Name: bm.Name}) - } - benchmap[bm.Name] = append(benchmap[bm.Name], bm) - } - - for _, bm := range merged { - for _, b := range benchmap[bm.Name] { - bm.Allocs += b.Allocs - bm.Bytes += b.Bytes - bm.Duration += b.Duration - } - n := len(benchmap[bm.Name]) - bm.Allocs /= n - bm.Bytes /= n - bm.Duration /= time.Duration(n) - } - - return merged -} - -func formatTime(d time.Duration) string { - return fmt.Sprintf("%.3f", d.Seconds()) -} - -func formatBenchmarkTime(d time.Duration) string { - return fmt.Sprintf("%.9f", d.Seconds()) -} diff --git a/vendor/github.com/jstemmer/go-junit-report/go-junit-report.go b/vendor/github.com/jstemmer/go-junit-report/go-junit-report.go deleted file mode 100644 index 1332f3b65b1..00000000000 --- a/vendor/github.com/jstemmer/go-junit-report/go-junit-report.go +++ /dev/null @@ -1,45 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "os" - - "github.com/jstemmer/go-junit-report/formatter" - "github.com/jstemmer/go-junit-report/parser" -) - -var ( - noXMLHeader = flag.Bool("no-xml-header", false, "do not print xml header") - packageName = flag.String("package-name", "", "specify a package name (compiled test have no package name in output)") - goVersionFlag = flag.String("go-version", "", "specify the value to use for the go.version property in the generated XML") - setExitCode = flag.Bool("set-exit-code", false, "set exit code to 1 if tests failed") -) - -func main() { - flag.Parse() - - if flag.NArg() != 0 { - fmt.Fprintf(os.Stderr, "%s does not accept positional arguments\n", os.Args[0]) - flag.Usage() - os.Exit(1) - } - - // Read input - report, err := parser.Parse(os.Stdin, *packageName) - if err != nil { - fmt.Printf("Error reading input: %s\n", err) - os.Exit(1) - } - - // Write xml - err = formatter.JUnitReportXML(report, *noXMLHeader, *goVersionFlag, os.Stdout) - if err != nil { - fmt.Printf("Error writing XML: %s\n", err) - os.Exit(1) - } - - if *setExitCode && report.Failures() > 0 { - os.Exit(1) - } -} diff --git a/vendor/github.com/jstemmer/go-junit-report/parser/parser.go b/vendor/github.com/jstemmer/go-junit-report/parser/parser.go deleted file mode 100644 index e268128a2dc..00000000000 --- a/vendor/github.com/jstemmer/go-junit-report/parser/parser.go +++ /dev/null @@ -1,319 +0,0 @@ -package parser - -import ( - "bufio" - "io" - "regexp" - "strconv" - "strings" - "time" -) - -// Result represents a test result. -type Result int - -// Test result constants -const ( - PASS Result = iota - FAIL - SKIP -) - -// Report is a collection of package tests. -type Report struct { - Packages []Package -} - -// Package contains the test results of a single package. -type Package struct { - Name string - Duration time.Duration - Tests []*Test - Benchmarks []*Benchmark - CoveragePct string - - // Time is deprecated, use Duration instead. - Time int // in milliseconds -} - -// Test contains the results of a single test. -type Test struct { - Name string - Duration time.Duration - Result Result - Output []string - - SubtestIndent string - - // Time is deprecated, use Duration instead. - Time int // in milliseconds -} - -// Benchmark contains the results of a single benchmark. -type Benchmark struct { - Name string - Duration time.Duration - // number of B/op - Bytes int - // number of allocs/op - Allocs int -} - -var ( - regexStatus = regexp.MustCompile(`--- (PASS|FAIL|SKIP): (.+) \((\d+\.\d+)(?: seconds|s)\)`) - regexIndent = regexp.MustCompile(`^([ \t]+)---`) - regexCoverage = regexp.MustCompile(`^coverage:\s+(\d+\.\d+)%\s+of\s+statements(?:\sin\s.+)?$`) - regexResult = regexp.MustCompile(`^(ok|FAIL)\s+([^ ]+)\s+(?:(\d+\.\d+)s|\(cached\)|(\[\w+ failed]))(?:\s+coverage:\s+(\d+\.\d+)%\sof\sstatements(?:\sin\s.+)?)?$`) - // regexBenchmark captures 3-5 groups: benchmark name, number of times ran, ns/op (with or without decimal), B/op (optional), and allocs/op (optional). - regexBenchmark = regexp.MustCompile(`^(Benchmark[^ -]+)(?:-\d+\s+|\s+)(\d+)\s+(\d+|\d+\.\d+)\sns/op(?:\s+(\d+)\sB/op)?(?:\s+(\d+)\sallocs/op)?`) - regexOutput = regexp.MustCompile(`( )*\t(.*)`) - regexSummary = regexp.MustCompile(`^(PASS|FAIL|SKIP)$`) - regexPackageWithTest = regexp.MustCompile(`^# ([^\[\]]+) \[[^\]]+\]$`) -) - -// Parse parses go test output from reader r and returns a report with the -// results. An optional pkgName can be given, which is used in case a package -// result line is missing. -func Parse(r io.Reader, pkgName string) (*Report, error) { - reader := bufio.NewReader(r) - - report := &Report{make([]Package, 0)} - - // keep track of tests we find - var tests []*Test - - // keep track of benchmarks we find - var benchmarks []*Benchmark - - // sum of tests' time, use this if current test has no result line (when it is compiled test) - var testsTime time.Duration - - // current test - var cur string - - // coverage percentage report for current package - var coveragePct string - - // stores mapping between package name and output of build failures - var packageCaptures = map[string][]string{} - - // the name of the package which it's build failure output is being captured - var capturedPackage string - - // capture any non-test output - var buffers = map[string][]string{} - - // parse lines - for { - l, _, err := reader.ReadLine() - if err != nil && err == io.EOF { - break - } else if err != nil { - return nil, err - } - - line := string(l) - - if strings.HasPrefix(line, "=== RUN ") { - // new test - cur = strings.TrimSpace(line[8:]) - tests = append(tests, &Test{ - Name: cur, - Result: FAIL, - Output: make([]string, 0), - }) - - // clear the current build package, so output lines won't be added to that build - capturedPackage = "" - } else if matches := regexBenchmark.FindStringSubmatch(line); len(matches) == 6 { - bytes, _ := strconv.Atoi(matches[4]) - allocs, _ := strconv.Atoi(matches[5]) - - benchmarks = append(benchmarks, &Benchmark{ - Name: matches[1], - Duration: parseNanoseconds(matches[3]), - Bytes: bytes, - Allocs: allocs, - }) - } else if strings.HasPrefix(line, "=== PAUSE ") { - continue - } else if strings.HasPrefix(line, "=== CONT ") { - cur = strings.TrimSpace(line[8:]) - continue - } else if matches := regexResult.FindStringSubmatch(line); len(matches) == 6 { - if matches[5] != "" { - coveragePct = matches[5] - } - if strings.HasSuffix(matches[4], "failed]") { - // the build of the package failed, inject a dummy test into the package - // which indicate about the failure and contain the failure description. - tests = append(tests, &Test{ - Name: matches[4], - Result: FAIL, - Output: packageCaptures[matches[2]], - }) - } else if matches[1] == "FAIL" && !containsFailures(tests) && len(buffers[cur]) > 0 { - // This package didn't have any failing tests, but still it - // failed with some output. Create a dummy test with the - // output. - tests = append(tests, &Test{ - Name: "Failure", - Result: FAIL, - Output: buffers[cur], - }) - buffers[cur] = buffers[cur][0:0] - } - - // all tests in this package are finished - report.Packages = append(report.Packages, Package{ - Name: matches[2], - Duration: parseSeconds(matches[3]), - Tests: tests, - Benchmarks: benchmarks, - CoveragePct: coveragePct, - - Time: int(parseSeconds(matches[3]) / time.Millisecond), // deprecated - }) - - buffers[cur] = buffers[cur][0:0] - tests = make([]*Test, 0) - benchmarks = make([]*Benchmark, 0) - coveragePct = "" - cur = "" - testsTime = 0 - } else if matches := regexStatus.FindStringSubmatch(line); len(matches) == 4 { - cur = matches[2] - test := findTest(tests, cur) - if test == nil { - continue - } - - // test status - if matches[1] == "PASS" { - test.Result = PASS - } else if matches[1] == "SKIP" { - test.Result = SKIP - } else { - test.Result = FAIL - } - - if matches := regexIndent.FindStringSubmatch(line); len(matches) == 2 { - test.SubtestIndent = matches[1] - } - - test.Output = buffers[cur] - - test.Name = matches[2] - test.Duration = parseSeconds(matches[3]) - testsTime += test.Duration - - test.Time = int(test.Duration / time.Millisecond) // deprecated - } else if matches := regexCoverage.FindStringSubmatch(line); len(matches) == 2 { - coveragePct = matches[1] - } else if matches := regexOutput.FindStringSubmatch(line); capturedPackage == "" && len(matches) == 3 { - // Sub-tests start with one or more series of 4-space indents, followed by a hard tab, - // followed by the test output - // Top-level tests start with a hard tab. - test := findTest(tests, cur) - if test == nil { - continue - } - test.Output = append(test.Output, matches[2]) - } else if strings.HasPrefix(line, "# ") { - // indicates a capture of build output of a package. set the current build package. - packageWithTestBinary := regexPackageWithTest.FindStringSubmatch(line) - if packageWithTestBinary != nil { - // Sometimes, the text after "# " shows the name of the test binary - // (".test") in addition to the package - // e.g.: "# package/name [package/name.test]" - capturedPackage = packageWithTestBinary[1] - } else { - capturedPackage = line[2:] - } - } else if capturedPackage != "" { - // current line is build failure capture for the current built package - packageCaptures[capturedPackage] = append(packageCaptures[capturedPackage], line) - } else if regexSummary.MatchString(line) { - // unset current test name so any additional output after the - // summary is captured separately. - cur = "" - } else { - // buffer anything else that we didn't recognize - buffers[cur] = append(buffers[cur], line) - - // if we have a current test, also append to its output - test := findTest(tests, cur) - if test != nil { - if strings.HasPrefix(line, test.SubtestIndent+" ") { - test.Output = append(test.Output, strings.TrimPrefix(line, test.SubtestIndent+" ")) - } - } - } - } - - if len(tests) > 0 { - // no result line found - report.Packages = append(report.Packages, Package{ - Name: pkgName, - Duration: testsTime, - Time: int(testsTime / time.Millisecond), - Tests: tests, - Benchmarks: benchmarks, - CoveragePct: coveragePct, - }) - } - - return report, nil -} - -func parseSeconds(t string) time.Duration { - if t == "" { - return time.Duration(0) - } - // ignore error - d, _ := time.ParseDuration(t + "s") - return d -} - -func parseNanoseconds(t string) time.Duration { - // note: if input < 1 ns precision, result will be 0s. - if t == "" { - return time.Duration(0) - } - // ignore error - d, _ := time.ParseDuration(t + "ns") - return d -} - -func findTest(tests []*Test, name string) *Test { - for i := len(tests) - 1; i >= 0; i-- { - if tests[i].Name == name { - return tests[i] - } - } - return nil -} - -func containsFailures(tests []*Test) bool { - for _, test := range tests { - if test.Result == FAIL { - return true - } - } - return false -} - -// Failures counts the number of failed tests in this report -func (r *Report) Failures() int { - count := 0 - - for _, p := range r.Packages { - for _, t := range p.Tests { - if t.Result == FAIL { - count++ - } - } - } - - return count -} diff --git a/vendor/go.opencensus.io/plugin/ocgrpc/client.go b/vendor/go.opencensus.io/plugin/ocgrpc/client.go new file mode 100644 index 00000000000..a6c466ae82e --- /dev/null +++ b/vendor/go.opencensus.io/plugin/ocgrpc/client.go @@ -0,0 +1,56 @@ +// Copyright 2018, OpenCensus Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ocgrpc + +import ( + "go.opencensus.io/trace" + "golang.org/x/net/context" + + "google.golang.org/grpc/stats" +) + +// ClientHandler implements a gRPC stats.Handler for recording OpenCensus stats and +// traces. Use with gRPC clients only. +type ClientHandler struct { + // StartOptions allows configuring the StartOptions used to create new spans. + // + // StartOptions.SpanKind will always be set to trace.SpanKindClient + // for spans started by this handler. + StartOptions trace.StartOptions +} + +// HandleConn exists to satisfy gRPC stats.Handler. +func (c *ClientHandler) HandleConn(ctx context.Context, cs stats.ConnStats) { + // no-op +} + +// TagConn exists to satisfy gRPC stats.Handler. +func (c *ClientHandler) TagConn(ctx context.Context, cti *stats.ConnTagInfo) context.Context { + // no-op + return ctx +} + +// HandleRPC implements per-RPC tracing and stats instrumentation. +func (c *ClientHandler) HandleRPC(ctx context.Context, rs stats.RPCStats) { + traceHandleRPC(ctx, rs) + statsHandleRPC(ctx, rs) +} + +// TagRPC implements per-RPC context management. +func (c *ClientHandler) TagRPC(ctx context.Context, rti *stats.RPCTagInfo) context.Context { + ctx = c.traceTagRPC(ctx, rti) + ctx = c.statsTagRPC(ctx, rti) + return ctx +} diff --git a/vendor/go.opencensus.io/plugin/ocgrpc/client_metrics.go b/vendor/go.opencensus.io/plugin/ocgrpc/client_metrics.go new file mode 100644 index 00000000000..abe978b67b8 --- /dev/null +++ b/vendor/go.opencensus.io/plugin/ocgrpc/client_metrics.go @@ -0,0 +1,107 @@ +// Copyright 2017, OpenCensus Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package ocgrpc + +import ( + "go.opencensus.io/stats" + "go.opencensus.io/stats/view" + "go.opencensus.io/tag" +) + +// The following variables are measures are recorded by ClientHandler: +var ( + ClientSentMessagesPerRPC = stats.Int64("grpc.io/client/sent_messages_per_rpc", "Number of messages sent in the RPC (always 1 for non-streaming RPCs).", stats.UnitDimensionless) + ClientSentBytesPerRPC = stats.Int64("grpc.io/client/sent_bytes_per_rpc", "Total bytes sent across all request messages per RPC.", stats.UnitBytes) + ClientReceivedMessagesPerRPC = stats.Int64("grpc.io/client/received_messages_per_rpc", "Number of response messages received per RPC (always 1 for non-streaming RPCs).", stats.UnitDimensionless) + ClientReceivedBytesPerRPC = stats.Int64("grpc.io/client/received_bytes_per_rpc", "Total bytes received across all response messages per RPC.", stats.UnitBytes) + ClientRoundtripLatency = stats.Float64("grpc.io/client/roundtrip_latency", "Time between first byte of request sent to last byte of response received, or terminal error.", stats.UnitMilliseconds) + ClientServerLatency = stats.Float64("grpc.io/client/server_latency", `Propagated from the server and should have the same value as "grpc.io/server/latency".`, stats.UnitMilliseconds) +) + +// Predefined views may be registered to collect data for the above measures. +// As always, you may also define your own custom views over measures collected by this +// package. These are declared as a convenience only; none are registered by +// default. +var ( + ClientSentBytesPerRPCView = &view.View{ + Measure: ClientSentBytesPerRPC, + Name: "grpc.io/client/sent_bytes_per_rpc", + Description: "Distribution of bytes sent per RPC, by method.", + TagKeys: []tag.Key{KeyClientMethod}, + Aggregation: DefaultBytesDistribution, + } + + ClientReceivedBytesPerRPCView = &view.View{ + Measure: ClientReceivedBytesPerRPC, + Name: "grpc.io/client/received_bytes_per_rpc", + Description: "Distribution of bytes received per RPC, by method.", + TagKeys: []tag.Key{KeyClientMethod}, + Aggregation: DefaultBytesDistribution, + } + + ClientRoundtripLatencyView = &view.View{ + Measure: ClientRoundtripLatency, + Name: "grpc.io/client/roundtrip_latency", + Description: "Distribution of round-trip latency, by method.", + TagKeys: []tag.Key{KeyClientMethod}, + Aggregation: DefaultMillisecondsDistribution, + } + + ClientCompletedRPCsView = &view.View{ + Measure: ClientRoundtripLatency, + Name: "grpc.io/client/completed_rpcs", + Description: "Count of RPCs by method and status.", + TagKeys: []tag.Key{KeyClientMethod, KeyClientStatus}, + Aggregation: view.Count(), + } + + ClientSentMessagesPerRPCView = &view.View{ + Measure: ClientSentMessagesPerRPC, + Name: "grpc.io/client/sent_messages_per_rpc", + Description: "Distribution of sent messages count per RPC, by method.", + TagKeys: []tag.Key{KeyClientMethod}, + Aggregation: DefaultMessageCountDistribution, + } + + ClientReceivedMessagesPerRPCView = &view.View{ + Measure: ClientReceivedMessagesPerRPC, + Name: "grpc.io/client/received_messages_per_rpc", + Description: "Distribution of received messages count per RPC, by method.", + TagKeys: []tag.Key{KeyClientMethod}, + Aggregation: DefaultMessageCountDistribution, + } + + ClientServerLatencyView = &view.View{ + Measure: ClientServerLatency, + Name: "grpc.io/client/server_latency", + Description: "Distribution of server latency as viewed by client, by method.", + TagKeys: []tag.Key{KeyClientMethod}, + Aggregation: DefaultMillisecondsDistribution, + } +) + +// DefaultClientViews are the default client views provided by this package. +var DefaultClientViews = []*view.View{ + ClientSentBytesPerRPCView, + ClientReceivedBytesPerRPCView, + ClientRoundtripLatencyView, + ClientCompletedRPCsView, +} + +// TODO(jbd): Add roundtrip_latency, uncompressed_request_bytes, uncompressed_response_bytes, request_count, response_count. +// TODO(acetechnologist): This is temporary and will need to be replaced by a +// mechanism to load these defaults from a common repository/config shared by +// all supported languages. Likely a serialized protobuf of these defaults. diff --git a/vendor/go.opencensus.io/plugin/ocgrpc/client_stats_handler.go b/vendor/go.opencensus.io/plugin/ocgrpc/client_stats_handler.go new file mode 100644 index 00000000000..303c607f632 --- /dev/null +++ b/vendor/go.opencensus.io/plugin/ocgrpc/client_stats_handler.go @@ -0,0 +1,49 @@ +// Copyright 2017, OpenCensus Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package ocgrpc + +import ( + "time" + + "go.opencensus.io/tag" + "golang.org/x/net/context" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/stats" +) + +// statsTagRPC gets the tag.Map populated by the application code, serializes +// its tags into the GRPC metadata in order to be sent to the server. +func (h *ClientHandler) statsTagRPC(ctx context.Context, info *stats.RPCTagInfo) context.Context { + startTime := time.Now() + if info == nil { + if grpclog.V(2) { + grpclog.Infof("clientHandler.TagRPC called with nil info.", info.FullMethodName) + } + return ctx + } + + d := &rpcData{ + startTime: startTime, + method: info.FullMethodName, + } + ts := tag.FromContext(ctx) + if ts != nil { + encoded := tag.Encode(ts) + ctx = stats.SetTags(ctx, encoded) + } + + return context.WithValue(ctx, rpcDataKey, d) +} diff --git a/vendor/go.opencensus.io/plugin/ocgrpc/doc.go b/vendor/go.opencensus.io/plugin/ocgrpc/doc.go new file mode 100644 index 00000000000..1370323fb71 --- /dev/null +++ b/vendor/go.opencensus.io/plugin/ocgrpc/doc.go @@ -0,0 +1,19 @@ +// Copyright 2017, OpenCensus Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package ocgrpc contains OpenCensus stats and trace +// integrations for gRPC. +// +// Use ServerHandler for servers and ClientHandler for clients. +package ocgrpc // import "go.opencensus.io/plugin/ocgrpc" diff --git a/vendor/go.opencensus.io/plugin/ocgrpc/server.go b/vendor/go.opencensus.io/plugin/ocgrpc/server.go new file mode 100644 index 00000000000..b67b3e2be2a --- /dev/null +++ b/vendor/go.opencensus.io/plugin/ocgrpc/server.go @@ -0,0 +1,80 @@ +// Copyright 2018, OpenCensus Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ocgrpc + +import ( + "go.opencensus.io/trace" + "golang.org/x/net/context" + + "google.golang.org/grpc/stats" +) + +// ServerHandler implements gRPC stats.Handler recording OpenCensus stats and +// traces. Use with gRPC servers. +// +// When installed (see Example), tracing metadata is read from inbound RPCs +// by default. If no tracing metadata is present, or if the tracing metadata is +// present but the SpanContext isn't sampled, then a new trace may be started +// (as determined by Sampler). +type ServerHandler struct { + // IsPublicEndpoint may be set to true to always start a new trace around + // each RPC. Any SpanContext in the RPC metadata will be added as a linked + // span instead of making it the parent of the span created around the + // server RPC. + // + // Be aware that if you leave this false (the default) on a public-facing + // server, callers will be able to send tracing metadata in gRPC headers + // and trigger traces in your backend. + IsPublicEndpoint bool + + // StartOptions to use for to spans started around RPCs handled by this server. + // + // These will apply even if there is tracing metadata already + // present on the inbound RPC but the SpanContext is not sampled. This + // ensures that each service has some opportunity to be traced. If you would + // like to not add any additional traces for this gRPC service, set: + // + // StartOptions.Sampler = trace.ProbabilitySampler(0.0) + // + // StartOptions.SpanKind will always be set to trace.SpanKindServer + // for spans started by this handler. + StartOptions trace.StartOptions +} + +var _ stats.Handler = (*ServerHandler)(nil) + +// HandleConn exists to satisfy gRPC stats.Handler. +func (s *ServerHandler) HandleConn(ctx context.Context, cs stats.ConnStats) { + // no-op +} + +// TagConn exists to satisfy gRPC stats.Handler. +func (s *ServerHandler) TagConn(ctx context.Context, cti *stats.ConnTagInfo) context.Context { + // no-op + return ctx +} + +// HandleRPC implements per-RPC tracing and stats instrumentation. +func (s *ServerHandler) HandleRPC(ctx context.Context, rs stats.RPCStats) { + traceHandleRPC(ctx, rs) + statsHandleRPC(ctx, rs) +} + +// TagRPC implements per-RPC context management. +func (s *ServerHandler) TagRPC(ctx context.Context, rti *stats.RPCTagInfo) context.Context { + ctx = s.traceTagRPC(ctx, rti) + ctx = s.statsTagRPC(ctx, rti) + return ctx +} diff --git a/vendor/go.opencensus.io/plugin/ocgrpc/server_metrics.go b/vendor/go.opencensus.io/plugin/ocgrpc/server_metrics.go new file mode 100644 index 00000000000..609d9ed248b --- /dev/null +++ b/vendor/go.opencensus.io/plugin/ocgrpc/server_metrics.go @@ -0,0 +1,97 @@ +// Copyright 2017, OpenCensus Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package ocgrpc + +import ( + "go.opencensus.io/stats" + "go.opencensus.io/stats/view" + "go.opencensus.io/tag" +) + +// The following variables are measures are recorded by ServerHandler: +var ( + ServerReceivedMessagesPerRPC = stats.Int64("grpc.io/server/received_messages_per_rpc", "Number of messages received in each RPC. Has value 1 for non-streaming RPCs.", stats.UnitDimensionless) + ServerReceivedBytesPerRPC = stats.Int64("grpc.io/server/received_bytes_per_rpc", "Total bytes received across all messages per RPC.", stats.UnitBytes) + ServerSentMessagesPerRPC = stats.Int64("grpc.io/server/sent_messages_per_rpc", "Number of messages sent in each RPC. Has value 1 for non-streaming RPCs.", stats.UnitDimensionless) + ServerSentBytesPerRPC = stats.Int64("grpc.io/server/sent_bytes_per_rpc", "Total bytes sent in across all response messages per RPC.", stats.UnitBytes) + ServerLatency = stats.Float64("grpc.io/server/server_latency", "Time between first byte of request received to last byte of response sent, or terminal error.", stats.UnitMilliseconds) +) + +// TODO(acetechnologist): This is temporary and will need to be replaced by a +// mechanism to load these defaults from a common repository/config shared by +// all supported languages. Likely a serialized protobuf of these defaults. + +// Predefined views may be registered to collect data for the above measures. +// As always, you may also define your own custom views over measures collected by this +// package. These are declared as a convenience only; none are registered by +// default. +var ( + ServerReceivedBytesPerRPCView = &view.View{ + Name: "grpc.io/server/received_bytes_per_rpc", + Description: "Distribution of received bytes per RPC, by method.", + Measure: ServerReceivedBytesPerRPC, + TagKeys: []tag.Key{KeyServerMethod}, + Aggregation: DefaultBytesDistribution, + } + + ServerSentBytesPerRPCView = &view.View{ + Name: "grpc.io/server/sent_bytes_per_rpc", + Description: "Distribution of total sent bytes per RPC, by method.", + Measure: ServerSentBytesPerRPC, + TagKeys: []tag.Key{KeyServerMethod}, + Aggregation: DefaultBytesDistribution, + } + + ServerLatencyView = &view.View{ + Name: "grpc.io/server/server_latency", + Description: "Distribution of server latency in milliseconds, by method.", + TagKeys: []tag.Key{KeyServerMethod}, + Measure: ServerLatency, + Aggregation: DefaultMillisecondsDistribution, + } + + ServerCompletedRPCsView = &view.View{ + Name: "grpc.io/server/completed_rpcs", + Description: "Count of RPCs by method and status.", + TagKeys: []tag.Key{KeyServerMethod, KeyServerStatus}, + Measure: ServerLatency, + Aggregation: view.Count(), + } + + ServerReceivedMessagesPerRPCView = &view.View{ + Name: "grpc.io/server/received_messages_per_rpc", + Description: "Distribution of messages received count per RPC, by method.", + TagKeys: []tag.Key{KeyServerMethod}, + Measure: ServerReceivedMessagesPerRPC, + Aggregation: DefaultMessageCountDistribution, + } + + ServerSentMessagesPerRPCView = &view.View{ + Name: "grpc.io/server/sent_messages_per_rpc", + Description: "Distribution of messages sent count per RPC, by method.", + TagKeys: []tag.Key{KeyServerMethod}, + Measure: ServerSentMessagesPerRPC, + Aggregation: DefaultMessageCountDistribution, + } +) + +// DefaultServerViews are the default server views provided by this package. +var DefaultServerViews = []*view.View{ + ServerReceivedBytesPerRPCView, + ServerSentBytesPerRPCView, + ServerLatencyView, + ServerCompletedRPCsView, +} diff --git a/vendor/go.opencensus.io/plugin/ocgrpc/server_stats_handler.go b/vendor/go.opencensus.io/plugin/ocgrpc/server_stats_handler.go new file mode 100644 index 00000000000..7847c1a912e --- /dev/null +++ b/vendor/go.opencensus.io/plugin/ocgrpc/server_stats_handler.go @@ -0,0 +1,63 @@ +// Copyright 2017, OpenCensus Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package ocgrpc + +import ( + "time" + + "golang.org/x/net/context" + + "go.opencensus.io/tag" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/stats" +) + +// statsTagRPC gets the metadata from gRPC context, extracts the encoded tags from +// it and creates a new tag.Map and puts them into the returned context. +func (h *ServerHandler) statsTagRPC(ctx context.Context, info *stats.RPCTagInfo) context.Context { + startTime := time.Now() + if info == nil { + if grpclog.V(2) { + grpclog.Infof("opencensus: TagRPC called with nil info.") + } + return ctx + } + d := &rpcData{ + startTime: startTime, + method: info.FullMethodName, + } + propagated := h.extractPropagatedTags(ctx) + ctx = tag.NewContext(ctx, propagated) + ctx, _ = tag.New(ctx, tag.Upsert(KeyServerMethod, methodName(info.FullMethodName))) + return context.WithValue(ctx, rpcDataKey, d) +} + +// extractPropagatedTags creates a new tag map containing the tags extracted from the +// gRPC metadata. +func (h *ServerHandler) extractPropagatedTags(ctx context.Context) *tag.Map { + buf := stats.Tags(ctx) + if buf == nil { + return nil + } + propagated, err := tag.Decode(buf) + if err != nil { + if grpclog.V(2) { + grpclog.Warningf("opencensus: Failed to decode tags from gRPC metadata failed to decode: %v", err) + } + return nil + } + return propagated +} diff --git a/vendor/go.opencensus.io/plugin/ocgrpc/stats_common.go b/vendor/go.opencensus.io/plugin/ocgrpc/stats_common.go new file mode 100644 index 00000000000..e9991fe0fb1 --- /dev/null +++ b/vendor/go.opencensus.io/plugin/ocgrpc/stats_common.go @@ -0,0 +1,208 @@ +// Copyright 2017, OpenCensus Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package ocgrpc + +import ( + "context" + "strconv" + "strings" + "sync/atomic" + "time" + + ocstats "go.opencensus.io/stats" + "go.opencensus.io/stats/view" + "go.opencensus.io/tag" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/stats" + "google.golang.org/grpc/status" +) + +type grpcInstrumentationKey string + +// rpcData holds the instrumentation RPC data that is needed between the start +// and end of an call. It holds the info that this package needs to keep track +// of between the various GRPC events. +type rpcData struct { + // reqCount and respCount has to be the first words + // in order to be 64-aligned on 32-bit architectures. + sentCount, sentBytes, recvCount, recvBytes int64 // access atomically + + // startTime represents the time at which TagRPC was invoked at the + // beginning of an RPC. It is an appoximation of the time when the + // application code invoked GRPC code. + startTime time.Time + method string +} + +// The following variables define the default hard-coded auxiliary data used by +// both the default GRPC client and GRPC server metrics. +var ( + DefaultBytesDistribution = view.Distribution(1024, 2048, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216, 67108864, 268435456, 1073741824, 4294967296) + DefaultMillisecondsDistribution = view.Distribution(0.01, 0.05, 0.1, 0.3, 0.6, 0.8, 1, 2, 3, 4, 5, 6, 8, 10, 13, 16, 20, 25, 30, 40, 50, 65, 80, 100, 130, 160, 200, 250, 300, 400, 500, 650, 800, 1000, 2000, 5000, 10000, 20000, 50000, 100000) + DefaultMessageCountDistribution = view.Distribution(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536) +) + +// Server tags are applied to the context used to process each RPC, as well as +// the measures at the end of each RPC. +var ( + KeyServerMethod, _ = tag.NewKey("grpc_server_method") + KeyServerStatus, _ = tag.NewKey("grpc_server_status") +) + +// Client tags are applied to measures at the end of each RPC. +var ( + KeyClientMethod, _ = tag.NewKey("grpc_client_method") + KeyClientStatus, _ = tag.NewKey("grpc_client_status") +) + +var ( + rpcDataKey = grpcInstrumentationKey("opencensus-rpcData") +) + +func methodName(fullname string) string { + return strings.TrimLeft(fullname, "/") +} + +// statsHandleRPC processes the RPC events. +func statsHandleRPC(ctx context.Context, s stats.RPCStats) { + switch st := s.(type) { + case *stats.Begin, *stats.OutHeader, *stats.InHeader, *stats.InTrailer, *stats.OutTrailer: + // do nothing for client + case *stats.OutPayload: + handleRPCOutPayload(ctx, st) + case *stats.InPayload: + handleRPCInPayload(ctx, st) + case *stats.End: + handleRPCEnd(ctx, st) + default: + grpclog.Infof("unexpected stats: %T", st) + } +} + +func handleRPCOutPayload(ctx context.Context, s *stats.OutPayload) { + d, ok := ctx.Value(rpcDataKey).(*rpcData) + if !ok { + if grpclog.V(2) { + grpclog.Infoln("Failed to retrieve *rpcData from context.") + } + return + } + + atomic.AddInt64(&d.sentBytes, int64(s.Length)) + atomic.AddInt64(&d.sentCount, 1) +} + +func handleRPCInPayload(ctx context.Context, s *stats.InPayload) { + d, ok := ctx.Value(rpcDataKey).(*rpcData) + if !ok { + if grpclog.V(2) { + grpclog.Infoln("Failed to retrieve *rpcData from context.") + } + return + } + + atomic.AddInt64(&d.recvBytes, int64(s.Length)) + atomic.AddInt64(&d.recvCount, 1) +} + +func handleRPCEnd(ctx context.Context, s *stats.End) { + d, ok := ctx.Value(rpcDataKey).(*rpcData) + if !ok { + if grpclog.V(2) { + grpclog.Infoln("Failed to retrieve *rpcData from context.") + } + return + } + + elapsedTime := time.Since(d.startTime) + + var st string + if s.Error != nil { + s, ok := status.FromError(s.Error) + if ok { + st = statusCodeToString(s) + } + } else { + st = "OK" + } + + latencyMillis := float64(elapsedTime) / float64(time.Millisecond) + if s.Client { + ocstats.RecordWithTags(ctx, + []tag.Mutator{ + tag.Upsert(KeyClientMethod, methodName(d.method)), + tag.Upsert(KeyClientStatus, st), + }, + ClientSentBytesPerRPC.M(atomic.LoadInt64(&d.sentBytes)), + ClientSentMessagesPerRPC.M(atomic.LoadInt64(&d.sentCount)), + ClientReceivedMessagesPerRPC.M(atomic.LoadInt64(&d.recvCount)), + ClientReceivedBytesPerRPC.M(atomic.LoadInt64(&d.recvBytes)), + ClientRoundtripLatency.M(latencyMillis)) + } else { + ocstats.RecordWithTags(ctx, + []tag.Mutator{ + tag.Upsert(KeyServerStatus, st), + }, + ServerSentBytesPerRPC.M(atomic.LoadInt64(&d.sentBytes)), + ServerSentMessagesPerRPC.M(atomic.LoadInt64(&d.sentCount)), + ServerReceivedMessagesPerRPC.M(atomic.LoadInt64(&d.recvCount)), + ServerReceivedBytesPerRPC.M(atomic.LoadInt64(&d.recvBytes)), + ServerLatency.M(latencyMillis)) + } +} + +func statusCodeToString(s *status.Status) string { + // see https://github.com/grpc/grpc/blob/master/doc/statuscodes.md + switch c := s.Code(); c { + case codes.OK: + return "OK" + case codes.Canceled: + return "CANCELLED" + case codes.Unknown: + return "UNKNOWN" + case codes.InvalidArgument: + return "INVALID_ARGUMENT" + case codes.DeadlineExceeded: + return "DEADLINE_EXCEEDED" + case codes.NotFound: + return "NOT_FOUND" + case codes.AlreadyExists: + return "ALREADY_EXISTS" + case codes.PermissionDenied: + return "PERMISSION_DENIED" + case codes.ResourceExhausted: + return "RESOURCE_EXHAUSTED" + case codes.FailedPrecondition: + return "FAILED_PRECONDITION" + case codes.Aborted: + return "ABORTED" + case codes.OutOfRange: + return "OUT_OF_RANGE" + case codes.Unimplemented: + return "UNIMPLEMENTED" + case codes.Internal: + return "INTERNAL" + case codes.Unavailable: + return "UNAVAILABLE" + case codes.DataLoss: + return "DATA_LOSS" + case codes.Unauthenticated: + return "UNAUTHENTICATED" + default: + return "CODE_" + strconv.FormatInt(int64(c), 10) + } +} diff --git a/vendor/go.opencensus.io/plugin/ocgrpc/trace_common.go b/vendor/go.opencensus.io/plugin/ocgrpc/trace_common.go new file mode 100644 index 00000000000..720f381c275 --- /dev/null +++ b/vendor/go.opencensus.io/plugin/ocgrpc/trace_common.go @@ -0,0 +1,107 @@ +// Copyright 2017, OpenCensus Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ocgrpc + +import ( + "strings" + + "google.golang.org/grpc/codes" + + "go.opencensus.io/trace" + "go.opencensus.io/trace/propagation" + "golang.org/x/net/context" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/stats" + "google.golang.org/grpc/status" +) + +const traceContextKey = "grpc-trace-bin" + +// TagRPC creates a new trace span for the client side of the RPC. +// +// It returns ctx with the new trace span added and a serialization of the +// SpanContext added to the outgoing gRPC metadata. +func (c *ClientHandler) traceTagRPC(ctx context.Context, rti *stats.RPCTagInfo) context.Context { + name := strings.TrimPrefix(rti.FullMethodName, "/") + name = strings.Replace(name, "/", ".", -1) + ctx, span := trace.StartSpan(ctx, name, + trace.WithSampler(c.StartOptions.Sampler), + trace.WithSpanKind(trace.SpanKindClient)) // span is ended by traceHandleRPC + traceContextBinary := propagation.Binary(span.SpanContext()) + return metadata.AppendToOutgoingContext(ctx, traceContextKey, string(traceContextBinary)) +} + +// TagRPC creates a new trace span for the server side of the RPC. +// +// It checks the incoming gRPC metadata in ctx for a SpanContext, and if +// it finds one, uses that SpanContext as the parent context of the new span. +// +// It returns ctx, with the new trace span added. +func (s *ServerHandler) traceTagRPC(ctx context.Context, rti *stats.RPCTagInfo) context.Context { + md, _ := metadata.FromIncomingContext(ctx) + name := strings.TrimPrefix(rti.FullMethodName, "/") + name = strings.Replace(name, "/", ".", -1) + traceContext := md[traceContextKey] + var ( + parent trace.SpanContext + haveParent bool + ) + if len(traceContext) > 0 { + // Metadata with keys ending in -bin are actually binary. They are base64 + // encoded before being put on the wire, see: + // https://github.com/grpc/grpc-go/blob/08d6261/Documentation/grpc-metadata.md#storing-binary-data-in-metadata + traceContextBinary := []byte(traceContext[0]) + parent, haveParent = propagation.FromBinary(traceContextBinary) + if haveParent && !s.IsPublicEndpoint { + ctx, _ := trace.StartSpanWithRemoteParent(ctx, name, parent, + trace.WithSpanKind(trace.SpanKindServer), + trace.WithSampler(s.StartOptions.Sampler), + ) + return ctx + } + } + ctx, span := trace.StartSpan(ctx, name, + trace.WithSpanKind(trace.SpanKindServer), + trace.WithSampler(s.StartOptions.Sampler)) + if haveParent { + span.AddLink(trace.Link{TraceID: parent.TraceID, SpanID: parent.SpanID, Type: trace.LinkTypeChild}) + } + return ctx +} + +func traceHandleRPC(ctx context.Context, rs stats.RPCStats) { + span := trace.FromContext(ctx) + // TODO: compressed and uncompressed sizes are not populated in every message. + switch rs := rs.(type) { + case *stats.Begin: + span.AddAttributes( + trace.BoolAttribute("Client", rs.Client), + trace.BoolAttribute("FailFast", rs.FailFast)) + case *stats.InPayload: + span.AddMessageReceiveEvent(0 /* TODO: messageID */, int64(rs.Length), int64(rs.WireLength)) + case *stats.OutPayload: + span.AddMessageSendEvent(0, int64(rs.Length), int64(rs.WireLength)) + case *stats.End: + if rs.Error != nil { + s, ok := status.FromError(rs.Error) + if ok { + span.SetStatus(trace.Status{Code: int32(s.Code()), Message: s.Message()}) + } else { + span.SetStatus(trace.Status{Code: int32(codes.Internal), Message: rs.Error.Error()}) + } + } + span.End() + } +} diff --git a/vendor/golang.org/x/lint/.travis.yml b/vendor/golang.org/x/lint/.travis.yml deleted file mode 100644 index 50553ebd004..00000000000 --- a/vendor/golang.org/x/lint/.travis.yml +++ /dev/null @@ -1,19 +0,0 @@ -sudo: false -language: go -go: - - 1.10.x - - 1.11.x - - master - -go_import_path: golang.org/x/lint - -install: - - go get -t -v ./... - -script: - - go test -v -race ./... - -matrix: - allow_failures: - - go: master - fast_finish: true diff --git a/vendor/golang.org/x/lint/CONTRIBUTING.md b/vendor/golang.org/x/lint/CONTRIBUTING.md deleted file mode 100644 index 1fadda62d2f..00000000000 --- a/vendor/golang.org/x/lint/CONTRIBUTING.md +++ /dev/null @@ -1,15 +0,0 @@ -# Contributing to Golint - -## Before filing an issue: - -### Are you having trouble building golint? - -Check you have the latest version of its dependencies. Run -``` -go get -u golang.org/x/lint/golint -``` -If you still have problems, consider searching for existing issues before filing a new issue. - -## Before sending a pull request: - -Have you understood the purpose of golint? Make sure to carefully read `README`. diff --git a/vendor/golang.org/x/lint/README.md b/vendor/golang.org/x/lint/README.md deleted file mode 100644 index 4968b13aef7..00000000000 --- a/vendor/golang.org/x/lint/README.md +++ /dev/null @@ -1,88 +0,0 @@ -Golint is a linter for Go source code. - -[![Build Status](https://travis-ci.org/golang/lint.svg?branch=master)](https://travis-ci.org/golang/lint) - -## Installation - -Golint requires a -[supported release of Go](https://golang.org/doc/devel/release.html#policy). - - go get -u golang.org/x/lint/golint - -To find out where `golint` was installed you can run `go list -f {{.Target}} golang.org/x/lint/golint`. For `golint` to be used globally add that directory to the `$PATH` environment setting. - -## Usage - -Invoke `golint` with one or more filenames, directories, or packages named -by its import path. Golint uses the same -[import path syntax](https://golang.org/cmd/go/#hdr-Import_path_syntax) as -the `go` command and therefore -also supports relative import paths like `./...`. Additionally the `...` -wildcard can be used as suffix on relative and absolute file paths to recurse -into them. - -The output of this tool is a list of suggestions in Vim quickfix format, -which is accepted by lots of different editors. - -## Purpose - -Golint differs from gofmt. Gofmt reformats Go source code, whereas -golint prints out style mistakes. - -Golint differs from govet. Govet is concerned with correctness, whereas -golint is concerned with coding style. Golint is in use at Google, and it -seeks to match the accepted style of the open source Go project. - -The suggestions made by golint are exactly that: suggestions. -Golint is not perfect, and has both false positives and false negatives. -Do not treat its output as a gold standard. We will not be adding pragmas -or other knobs to suppress specific warnings, so do not expect or require -code to be completely "lint-free". -In short, this tool is not, and will never be, trustworthy enough for its -suggestions to be enforced automatically, for example as part of a build process. -Golint makes suggestions for many of the mechanically checkable items listed in -[Effective Go](https://golang.org/doc/effective_go.html) and the -[CodeReviewComments wiki page](https://golang.org/wiki/CodeReviewComments). - -## Scope - -Golint is meant to carry out the stylistic conventions put forth in -[Effective Go](https://golang.org/doc/effective_go.html) and -[CodeReviewComments](https://golang.org/wiki/CodeReviewComments). -Changes that are not aligned with those documents will not be considered. - -## Contributions - -Contributions to this project are welcome provided they are [in scope](#scope), -though please send mail before starting work on anything major. -Contributors retain their copyright, so we need you to fill out -[a short form](https://developers.google.com/open-source/cla/individual) -before we can accept your contribution. - -## Vim - -Add this to your ~/.vimrc: - - set rtp+=$GOPATH/src/golang.org/x/lint/misc/vim - -If you have multiple entries in your GOPATH, replace `$GOPATH` with the right value. - -Running `:Lint` will run golint on the current file and populate the quickfix list. - -Optionally, add this to your `~/.vimrc` to automatically run `golint` on `:w` - - autocmd BufWritePost,FileWritePost *.go execute 'Lint' | cwindow - - -## Emacs - -Add this to your `.emacs` file: - - (add-to-list 'load-path (concat (getenv "GOPATH") "/src/golang.org/x/lint/misc/emacs/")) - (require 'golint) - -If you have multiple entries in your GOPATH, replace `$GOPATH` with the right value. - -Running M-x golint will run golint on the current file. - -For more usage, see [Compilation-Mode](http://www.gnu.org/software/emacs/manual/html_node/emacs/Compilation-Mode.html). diff --git a/vendor/golang.org/x/lint/golint/golint.go b/vendor/golang.org/x/lint/golint/golint.go deleted file mode 100644 index ac024b6d26f..00000000000 --- a/vendor/golang.org/x/lint/golint/golint.go +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright (c) 2013 The Go Authors. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file or at -// https://developers.google.com/open-source/licenses/bsd. - -// golint lints the Go source files named on its command line. -package main - -import ( - "flag" - "fmt" - "go/build" - "io/ioutil" - "os" - "path/filepath" - "strings" - - "golang.org/x/lint" -) - -var ( - minConfidence = flag.Float64("min_confidence", 0.8, "minimum confidence of a problem to print it") - setExitStatus = flag.Bool("set_exit_status", false, "set exit status to 1 if any issues are found") - suggestions int -) - -func usage() { - fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0]) - fmt.Fprintf(os.Stderr, "\tgolint [flags] # runs on package in current directory\n") - fmt.Fprintf(os.Stderr, "\tgolint [flags] [packages]\n") - fmt.Fprintf(os.Stderr, "\tgolint [flags] [directories] # where a '/...' suffix includes all sub-directories\n") - fmt.Fprintf(os.Stderr, "\tgolint [flags] [files] # all must belong to a single package\n") - fmt.Fprintf(os.Stderr, "Flags:\n") - flag.PrintDefaults() -} - -func main() { - flag.Usage = usage - flag.Parse() - - if flag.NArg() == 0 { - lintDir(".") - } else { - // dirsRun, filesRun, and pkgsRun indicate whether golint is applied to - // directory, file or package targets. The distinction affects which - // checks are run. It is no valid to mix target types. - var dirsRun, filesRun, pkgsRun int - var args []string - for _, arg := range flag.Args() { - if strings.HasSuffix(arg, "/...") && isDir(arg[:len(arg)-len("/...")]) { - dirsRun = 1 - for _, dirname := range allPackagesInFS(arg) { - args = append(args, dirname) - } - } else if isDir(arg) { - dirsRun = 1 - args = append(args, arg) - } else if exists(arg) { - filesRun = 1 - args = append(args, arg) - } else { - pkgsRun = 1 - args = append(args, arg) - } - } - - if dirsRun+filesRun+pkgsRun != 1 { - usage() - os.Exit(2) - } - switch { - case dirsRun == 1: - for _, dir := range args { - lintDir(dir) - } - case filesRun == 1: - lintFiles(args...) - case pkgsRun == 1: - for _, pkg := range importPaths(args) { - lintPackage(pkg) - } - } - } - - if *setExitStatus && suggestions > 0 { - fmt.Fprintf(os.Stderr, "Found %d lint suggestions; failing.\n", suggestions) - os.Exit(1) - } -} - -func isDir(filename string) bool { - fi, err := os.Stat(filename) - return err == nil && fi.IsDir() -} - -func exists(filename string) bool { - _, err := os.Stat(filename) - return err == nil -} - -func lintFiles(filenames ...string) { - files := make(map[string][]byte) - for _, filename := range filenames { - src, err := ioutil.ReadFile(filename) - if err != nil { - fmt.Fprintln(os.Stderr, err) - continue - } - files[filename] = src - } - - l := new(lint.Linter) - ps, err := l.LintFiles(files) - if err != nil { - fmt.Fprintf(os.Stderr, "%v\n", err) - return - } - for _, p := range ps { - if p.Confidence >= *minConfidence { - fmt.Printf("%v: %s\n", p.Position, p.Text) - suggestions++ - } - } -} - -func lintDir(dirname string) { - pkg, err := build.ImportDir(dirname, 0) - lintImportedPackage(pkg, err) -} - -func lintPackage(pkgname string) { - pkg, err := build.Import(pkgname, ".", 0) - lintImportedPackage(pkg, err) -} - -func lintImportedPackage(pkg *build.Package, err error) { - if err != nil { - if _, nogo := err.(*build.NoGoError); nogo { - // Don't complain if the failure is due to no Go source files. - return - } - fmt.Fprintln(os.Stderr, err) - return - } - - var files []string - files = append(files, pkg.GoFiles...) - files = append(files, pkg.CgoFiles...) - files = append(files, pkg.TestGoFiles...) - if pkg.Dir != "." { - for i, f := range files { - files[i] = filepath.Join(pkg.Dir, f) - } - } - // TODO(dsymonds): Do foo_test too (pkg.XTestGoFiles) - - lintFiles(files...) -} diff --git a/vendor/golang.org/x/lint/golint/import.go b/vendor/golang.org/x/lint/golint/import.go deleted file mode 100644 index 2ba9dea7792..00000000000 --- a/vendor/golang.org/x/lint/golint/import.go +++ /dev/null @@ -1,309 +0,0 @@ -package main - -/* - -This file holds a direct copy of the import path matching code of -https://github.com/golang/go/blob/master/src/cmd/go/main.go. It can be -replaced when https://golang.org/issue/8768 is resolved. - -It has been updated to follow upstream changes in a few ways. - -*/ - -import ( - "fmt" - "go/build" - "log" - "os" - "path" - "path/filepath" - "regexp" - "runtime" - "strings" -) - -var ( - buildContext = build.Default - goroot = filepath.Clean(runtime.GOROOT()) - gorootSrc = filepath.Join(goroot, "src") -) - -// importPathsNoDotExpansion returns the import paths to use for the given -// command line, but it does no ... expansion. -func importPathsNoDotExpansion(args []string) []string { - if len(args) == 0 { - return []string{"."} - } - var out []string - for _, a := range args { - // Arguments are supposed to be import paths, but - // as a courtesy to Windows developers, rewrite \ to / - // in command-line arguments. Handles .\... and so on. - if filepath.Separator == '\\' { - a = strings.Replace(a, `\`, `/`, -1) - } - - // Put argument in canonical form, but preserve leading ./. - if strings.HasPrefix(a, "./") { - a = "./" + path.Clean(a) - if a == "./." { - a = "." - } - } else { - a = path.Clean(a) - } - if a == "all" || a == "std" { - out = append(out, allPackages(a)...) - continue - } - out = append(out, a) - } - return out -} - -// importPaths returns the import paths to use for the given command line. -func importPaths(args []string) []string { - args = importPathsNoDotExpansion(args) - var out []string - for _, a := range args { - if strings.Contains(a, "...") { - if build.IsLocalImport(a) { - out = append(out, allPackagesInFS(a)...) - } else { - out = append(out, allPackages(a)...) - } - continue - } - out = append(out, a) - } - return out -} - -// matchPattern(pattern)(name) reports whether -// name matches pattern. Pattern is a limited glob -// pattern in which '...' means 'any string' and there -// is no other special syntax. -func matchPattern(pattern string) func(name string) bool { - re := regexp.QuoteMeta(pattern) - re = strings.Replace(re, `\.\.\.`, `.*`, -1) - // Special case: foo/... matches foo too. - if strings.HasSuffix(re, `/.*`) { - re = re[:len(re)-len(`/.*`)] + `(/.*)?` - } - reg := regexp.MustCompile(`^` + re + `$`) - return func(name string) bool { - return reg.MatchString(name) - } -} - -// hasPathPrefix reports whether the path s begins with the -// elements in prefix. -func hasPathPrefix(s, prefix string) bool { - switch { - default: - return false - case len(s) == len(prefix): - return s == prefix - case len(s) > len(prefix): - if prefix != "" && prefix[len(prefix)-1] == '/' { - return strings.HasPrefix(s, prefix) - } - return s[len(prefix)] == '/' && s[:len(prefix)] == prefix - } -} - -// treeCanMatchPattern(pattern)(name) reports whether -// name or children of name can possibly match pattern. -// Pattern is the same limited glob accepted by matchPattern. -func treeCanMatchPattern(pattern string) func(name string) bool { - wildCard := false - if i := strings.Index(pattern, "..."); i >= 0 { - wildCard = true - pattern = pattern[:i] - } - return func(name string) bool { - return len(name) <= len(pattern) && hasPathPrefix(pattern, name) || - wildCard && strings.HasPrefix(name, pattern) - } -} - -// allPackages returns all the packages that can be found -// under the $GOPATH directories and $GOROOT matching pattern. -// The pattern is either "all" (all packages), "std" (standard packages) -// or a path including "...". -func allPackages(pattern string) []string { - pkgs := matchPackages(pattern) - if len(pkgs) == 0 { - fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern) - } - return pkgs -} - -func matchPackages(pattern string) []string { - match := func(string) bool { return true } - treeCanMatch := func(string) bool { return true } - if pattern != "all" && pattern != "std" { - match = matchPattern(pattern) - treeCanMatch = treeCanMatchPattern(pattern) - } - - have := map[string]bool{ - "builtin": true, // ignore pseudo-package that exists only for documentation - } - if !buildContext.CgoEnabled { - have["runtime/cgo"] = true // ignore during walk - } - var pkgs []string - - // Commands - cmd := filepath.Join(goroot, "src/cmd") + string(filepath.Separator) - filepath.Walk(cmd, func(path string, fi os.FileInfo, err error) error { - if err != nil || !fi.IsDir() || path == cmd { - return nil - } - name := path[len(cmd):] - if !treeCanMatch(name) { - return filepath.SkipDir - } - // Commands are all in cmd/, not in subdirectories. - if strings.Contains(name, string(filepath.Separator)) { - return filepath.SkipDir - } - - // We use, e.g., cmd/gofmt as the pseudo import path for gofmt. - name = "cmd/" + name - if have[name] { - return nil - } - have[name] = true - if !match(name) { - return nil - } - _, err = buildContext.ImportDir(path, 0) - if err != nil { - if _, noGo := err.(*build.NoGoError); !noGo { - log.Print(err) - } - return nil - } - pkgs = append(pkgs, name) - return nil - }) - - for _, src := range buildContext.SrcDirs() { - if (pattern == "std" || pattern == "cmd") && src != gorootSrc { - continue - } - src = filepath.Clean(src) + string(filepath.Separator) - root := src - if pattern == "cmd" { - root += "cmd" + string(filepath.Separator) - } - filepath.Walk(root, func(path string, fi os.FileInfo, err error) error { - if err != nil || !fi.IsDir() || path == src { - return nil - } - - // Avoid .foo, _foo, and testdata directory trees. - _, elem := filepath.Split(path) - if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" { - return filepath.SkipDir - } - - name := filepath.ToSlash(path[len(src):]) - if pattern == "std" && (strings.Contains(name, ".") || name == "cmd") { - // The name "std" is only the standard library. - // If the name is cmd, it's the root of the command tree. - return filepath.SkipDir - } - if !treeCanMatch(name) { - return filepath.SkipDir - } - if have[name] { - return nil - } - have[name] = true - if !match(name) { - return nil - } - _, err = buildContext.ImportDir(path, 0) - if err != nil { - if _, noGo := err.(*build.NoGoError); noGo { - return nil - } - } - pkgs = append(pkgs, name) - return nil - }) - } - return pkgs -} - -// allPackagesInFS is like allPackages but is passed a pattern -// beginning ./ or ../, meaning it should scan the tree rooted -// at the given directory. There are ... in the pattern too. -func allPackagesInFS(pattern string) []string { - pkgs := matchPackagesInFS(pattern) - if len(pkgs) == 0 { - fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern) - } - return pkgs -} - -func matchPackagesInFS(pattern string) []string { - // Find directory to begin the scan. - // Could be smarter but this one optimization - // is enough for now, since ... is usually at the - // end of a path. - i := strings.Index(pattern, "...") - dir, _ := path.Split(pattern[:i]) - - // pattern begins with ./ or ../. - // path.Clean will discard the ./ but not the ../. - // We need to preserve the ./ for pattern matching - // and in the returned import paths. - prefix := "" - if strings.HasPrefix(pattern, "./") { - prefix = "./" - } - match := matchPattern(pattern) - - var pkgs []string - filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error { - if err != nil || !fi.IsDir() { - return nil - } - if path == dir { - // filepath.Walk starts at dir and recurses. For the recursive case, - // the path is the result of filepath.Join, which calls filepath.Clean. - // The initial case is not Cleaned, though, so we do this explicitly. - // - // This converts a path like "./io/" to "io". Without this step, running - // "cd $GOROOT/src/pkg; go list ./io/..." would incorrectly skip the io - // package, because prepending the prefix "./" to the unclean path would - // result in "././io", and match("././io") returns false. - path = filepath.Clean(path) - } - - // Avoid .foo, _foo, and testdata directory trees, but do not avoid "." or "..". - _, elem := filepath.Split(path) - dot := strings.HasPrefix(elem, ".") && elem != "." && elem != ".." - if dot || strings.HasPrefix(elem, "_") || elem == "testdata" { - return filepath.SkipDir - } - - name := prefix + filepath.ToSlash(path) - if !match(name) { - return nil - } - if _, err = build.ImportDir(path, 0); err != nil { - if _, noGo := err.(*build.NoGoError); !noGo { - log.Print(err) - } - return nil - } - pkgs = append(pkgs, name) - return nil - }) - return pkgs -} diff --git a/vendor/golang.org/x/lint/golint/importcomment.go b/vendor/golang.org/x/lint/golint/importcomment.go deleted file mode 100644 index d5b32f73464..00000000000 --- a/vendor/golang.org/x/lint/golint/importcomment.go +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) 2018 The Go Authors. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file or at -// https://developers.google.com/open-source/licenses/bsd. - -// +build go1.12 - -// Require use of the correct import path only for Go 1.12+ users, so -// any breakages coincide with people updating their CI configs or -// whatnot. - -package main // import "golang.org/x/lint/golint" diff --git a/vendor/golang.org/x/lint/lint.go b/vendor/golang.org/x/lint/lint.go deleted file mode 100644 index 7d813e061ad..00000000000 --- a/vendor/golang.org/x/lint/lint.go +++ /dev/null @@ -1,1615 +0,0 @@ -// Copyright (c) 2013 The Go Authors. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file or at -// https://developers.google.com/open-source/licenses/bsd. - -// Package lint contains a linter for Go source code. -package lint // import "golang.org/x/lint" - -import ( - "bufio" - "bytes" - "fmt" - "go/ast" - "go/parser" - "go/printer" - "go/token" - "go/types" - "regexp" - "sort" - "strconv" - "strings" - "unicode" - "unicode/utf8" - - "golang.org/x/tools/go/ast/astutil" - "golang.org/x/tools/go/gcexportdata" -) - -const styleGuideBase = "https://golang.org/wiki/CodeReviewComments" - -// A Linter lints Go source code. -type Linter struct { -} - -// Problem represents a problem in some source code. -type Problem struct { - Position token.Position // position in source file - Text string // the prose that describes the problem - Link string // (optional) the link to the style guide for the problem - Confidence float64 // a value in (0,1] estimating the confidence in this problem's correctness - LineText string // the source line - Category string // a short name for the general category of the problem - - // If the problem has a suggested fix (the minority case), - // ReplacementLine is a full replacement for the relevant line of the source file. - ReplacementLine string -} - -func (p *Problem) String() string { - if p.Link != "" { - return p.Text + "\n\n" + p.Link - } - return p.Text -} - -type byPosition []Problem - -func (p byPosition) Len() int { return len(p) } -func (p byPosition) Swap(i, j int) { p[i], p[j] = p[j], p[i] } - -func (p byPosition) Less(i, j int) bool { - pi, pj := p[i].Position, p[j].Position - - if pi.Filename != pj.Filename { - return pi.Filename < pj.Filename - } - if pi.Line != pj.Line { - return pi.Line < pj.Line - } - if pi.Column != pj.Column { - return pi.Column < pj.Column - } - - return p[i].Text < p[j].Text -} - -// Lint lints src. -func (l *Linter) Lint(filename string, src []byte) ([]Problem, error) { - return l.LintFiles(map[string][]byte{filename: src}) -} - -// LintFiles lints a set of files of a single package. -// The argument is a map of filename to source. -func (l *Linter) LintFiles(files map[string][]byte) ([]Problem, error) { - pkg := &pkg{ - fset: token.NewFileSet(), - files: make(map[string]*file), - } - var pkgName string - for filename, src := range files { - if isGenerated(src) { - continue // See issue #239 - } - f, err := parser.ParseFile(pkg.fset, filename, src, parser.ParseComments) - if err != nil { - return nil, err - } - if pkgName == "" { - pkgName = f.Name.Name - } else if f.Name.Name != pkgName { - return nil, fmt.Errorf("%s is in package %s, not %s", filename, f.Name.Name, pkgName) - } - pkg.files[filename] = &file{ - pkg: pkg, - f: f, - fset: pkg.fset, - src: src, - filename: filename, - } - } - if len(pkg.files) == 0 { - return nil, nil - } - return pkg.lint(), nil -} - -var ( - genHdr = []byte("// Code generated ") - genFtr = []byte(" DO NOT EDIT.") -) - -// isGenerated reports whether the source file is generated code -// according the rules from https://golang.org/s/generatedcode. -func isGenerated(src []byte) bool { - sc := bufio.NewScanner(bytes.NewReader(src)) - for sc.Scan() { - b := sc.Bytes() - if bytes.HasPrefix(b, genHdr) && bytes.HasSuffix(b, genFtr) && len(b) >= len(genHdr)+len(genFtr) { - return true - } - } - return false -} - -// pkg represents a package being linted. -type pkg struct { - fset *token.FileSet - files map[string]*file - - typesPkg *types.Package - typesInfo *types.Info - - // sortable is the set of types in the package that implement sort.Interface. - sortable map[string]bool - // main is whether this is a "main" package. - main bool - - problems []Problem -} - -func (p *pkg) lint() []Problem { - if err := p.typeCheck(); err != nil { - /* TODO(dsymonds): Consider reporting these errors when golint operates on entire packages. - if e, ok := err.(types.Error); ok { - pos := p.fset.Position(e.Pos) - conf := 1.0 - if strings.Contains(e.Msg, "can't find import: ") { - // Golint is probably being run in a context that doesn't support - // typechecking (e.g. package files aren't found), so don't warn about it. - conf = 0 - } - if conf > 0 { - p.errorfAt(pos, conf, category("typechecking"), e.Msg) - } - - // TODO(dsymonds): Abort if !e.Soft? - } - */ - } - - p.scanSortable() - p.main = p.isMain() - - for _, f := range p.files { - f.lint() - } - - sort.Sort(byPosition(p.problems)) - - return p.problems -} - -// file represents a file being linted. -type file struct { - pkg *pkg - f *ast.File - fset *token.FileSet - src []byte - filename string -} - -func (f *file) isTest() bool { return strings.HasSuffix(f.filename, "_test.go") } - -func (f *file) lint() { - f.lintPackageComment() - f.lintImports() - f.lintBlankImports() - f.lintExported() - f.lintNames() - f.lintElses() - f.lintRanges() - f.lintErrorf() - f.lintErrors() - f.lintErrorStrings() - f.lintReceiverNames() - f.lintIncDec() - f.lintErrorReturn() - f.lintUnexportedReturn() - f.lintTimeNames() - f.lintContextKeyTypes() - f.lintContextArgs() -} - -type link string -type category string - -// The variadic arguments may start with link and category types, -// and must end with a format string and any arguments. -// It returns the new Problem. -func (f *file) errorf(n ast.Node, confidence float64, args ...interface{}) *Problem { - pos := f.fset.Position(n.Pos()) - if pos.Filename == "" { - pos.Filename = f.filename - } - return f.pkg.errorfAt(pos, confidence, args...) -} - -func (p *pkg) errorfAt(pos token.Position, confidence float64, args ...interface{}) *Problem { - problem := Problem{ - Position: pos, - Confidence: confidence, - } - if pos.Filename != "" { - // The file might not exist in our mapping if a //line directive was encountered. - if f, ok := p.files[pos.Filename]; ok { - problem.LineText = srcLine(f.src, pos) - } - } - -argLoop: - for len(args) > 1 { // always leave at least the format string in args - switch v := args[0].(type) { - case link: - problem.Link = string(v) - case category: - problem.Category = string(v) - default: - break argLoop - } - args = args[1:] - } - - problem.Text = fmt.Sprintf(args[0].(string), args[1:]...) - - p.problems = append(p.problems, problem) - return &p.problems[len(p.problems)-1] -} - -var newImporter = func(fset *token.FileSet) types.ImporterFrom { - return gcexportdata.NewImporter(fset, make(map[string]*types.Package)) -} - -func (p *pkg) typeCheck() error { - config := &types.Config{ - // By setting a no-op error reporter, the type checker does as much work as possible. - Error: func(error) {}, - Importer: newImporter(p.fset), - } - info := &types.Info{ - Types: make(map[ast.Expr]types.TypeAndValue), - Defs: make(map[*ast.Ident]types.Object), - Uses: make(map[*ast.Ident]types.Object), - Scopes: make(map[ast.Node]*types.Scope), - } - var anyFile *file - var astFiles []*ast.File - for _, f := range p.files { - anyFile = f - astFiles = append(astFiles, f.f) - } - pkg, err := config.Check(anyFile.f.Name.Name, p.fset, astFiles, info) - // Remember the typechecking info, even if config.Check failed, - // since we will get partial information. - p.typesPkg = pkg - p.typesInfo = info - return err -} - -func (p *pkg) typeOf(expr ast.Expr) types.Type { - if p.typesInfo == nil { - return nil - } - return p.typesInfo.TypeOf(expr) -} - -func (p *pkg) isNamedType(typ types.Type, importPath, name string) bool { - n, ok := typ.(*types.Named) - if !ok { - return false - } - tn := n.Obj() - return tn != nil && tn.Pkg() != nil && tn.Pkg().Path() == importPath && tn.Name() == name -} - -// scopeOf returns the tightest scope encompassing id. -func (p *pkg) scopeOf(id *ast.Ident) *types.Scope { - var scope *types.Scope - if obj := p.typesInfo.ObjectOf(id); obj != nil { - scope = obj.Parent() - } - if scope == p.typesPkg.Scope() { - // We were given a top-level identifier. - // Use the file-level scope instead of the package-level scope. - pos := id.Pos() - for _, f := range p.files { - if f.f.Pos() <= pos && pos < f.f.End() { - scope = p.typesInfo.Scopes[f.f] - break - } - } - } - return scope -} - -func (p *pkg) scanSortable() { - p.sortable = make(map[string]bool) - - // bitfield for which methods exist on each type. - const ( - Len = 1 << iota - Less - Swap - ) - nmap := map[string]int{"Len": Len, "Less": Less, "Swap": Swap} - has := make(map[string]int) - for _, f := range p.files { - f.walk(func(n ast.Node) bool { - fn, ok := n.(*ast.FuncDecl) - if !ok || fn.Recv == nil || len(fn.Recv.List) == 0 { - return true - } - // TODO(dsymonds): We could check the signature to be more precise. - recv := receiverType(fn) - if i, ok := nmap[fn.Name.Name]; ok { - has[recv] |= i - } - return false - }) - } - for typ, ms := range has { - if ms == Len|Less|Swap { - p.sortable[typ] = true - } - } -} - -func (p *pkg) isMain() bool { - for _, f := range p.files { - if f.isMain() { - return true - } - } - return false -} - -func (f *file) isMain() bool { - if f.f.Name.Name == "main" { - return true - } - return false -} - -// lintPackageComment checks package comments. It complains if -// there is no package comment, or if it is not of the right form. -// This has a notable false positive in that a package comment -// could rightfully appear in a different file of the same package, -// but that's not easy to fix since this linter is file-oriented. -func (f *file) lintPackageComment() { - if f.isTest() { - return - } - - const ref = styleGuideBase + "#package-comments" - prefix := "Package " + f.f.Name.Name + " " - - // Look for a detached package comment. - // First, scan for the last comment that occurs before the "package" keyword. - var lastCG *ast.CommentGroup - for _, cg := range f.f.Comments { - if cg.Pos() > f.f.Package { - // Gone past "package" keyword. - break - } - lastCG = cg - } - if lastCG != nil && strings.HasPrefix(lastCG.Text(), prefix) { - endPos := f.fset.Position(lastCG.End()) - pkgPos := f.fset.Position(f.f.Package) - if endPos.Line+1 < pkgPos.Line { - // There isn't a great place to anchor this error; - // the start of the blank lines between the doc and the package statement - // is at least pointing at the location of the problem. - pos := token.Position{ - Filename: endPos.Filename, - // Offset not set; it is non-trivial, and doesn't appear to be needed. - Line: endPos.Line + 1, - Column: 1, - } - f.pkg.errorfAt(pos, 0.9, link(ref), category("comments"), "package comment is detached; there should be no blank lines between it and the package statement") - return - } - } - - if f.f.Doc == nil { - f.errorf(f.f, 0.2, link(ref), category("comments"), "should have a package comment, unless it's in another file for this package") - return - } - s := f.f.Doc.Text() - if ts := strings.TrimLeft(s, " \t"); ts != s { - f.errorf(f.f.Doc, 1, link(ref), category("comments"), "package comment should not have leading space") - s = ts - } - // Only non-main packages need to keep to this form. - if !f.pkg.main && !strings.HasPrefix(s, prefix) { - f.errorf(f.f.Doc, 1, link(ref), category("comments"), `package comment should be of the form "%s..."`, prefix) - } -} - -// lintBlankImports complains if a non-main package has blank imports that are -// not documented. -func (f *file) lintBlankImports() { - // In package main and in tests, we don't complain about blank imports. - if f.pkg.main || f.isTest() { - return - } - - // The first element of each contiguous group of blank imports should have - // an explanatory comment of some kind. - for i, imp := range f.f.Imports { - pos := f.fset.Position(imp.Pos()) - - if !isBlank(imp.Name) { - continue // Ignore non-blank imports. - } - if i > 0 { - prev := f.f.Imports[i-1] - prevPos := f.fset.Position(prev.Pos()) - if isBlank(prev.Name) && prevPos.Line+1 == pos.Line { - continue // A subsequent blank in a group. - } - } - - // This is the first blank import of a group. - if imp.Doc == nil && imp.Comment == nil { - ref := "" - f.errorf(imp, 1, link(ref), category("imports"), "a blank import should be only in a main or test package, or have a comment justifying it") - } - } -} - -// lintImports examines import blocks. -func (f *file) lintImports() { - for i, is := range f.f.Imports { - _ = i - if is.Name != nil && is.Name.Name == "." && !f.isTest() { - f.errorf(is, 1, link(styleGuideBase+"#import-dot"), category("imports"), "should not use dot imports") - } - - } -} - -const docCommentsLink = styleGuideBase + "#doc-comments" - -// lintExported examines the exported names. -// It complains if any required doc comments are missing, -// or if they are not of the right form. The exact rules are in -// lintFuncDoc, lintTypeDoc and lintValueSpecDoc; this function -// also tracks the GenDecl structure being traversed to permit -// doc comments for constants to be on top of the const block. -// It also complains if the names stutter when combined with -// the package name. -func (f *file) lintExported() { - if f.isTest() { - return - } - - var lastGen *ast.GenDecl // last GenDecl entered. - - // Set of GenDecls that have already had missing comments flagged. - genDeclMissingComments := make(map[*ast.GenDecl]bool) - - f.walk(func(node ast.Node) bool { - switch v := node.(type) { - case *ast.GenDecl: - if v.Tok == token.IMPORT { - return false - } - // token.CONST, token.TYPE or token.VAR - lastGen = v - return true - case *ast.FuncDecl: - f.lintFuncDoc(v) - if v.Recv == nil { - // Only check for stutter on functions, not methods. - // Method names are not used package-qualified. - f.checkStutter(v.Name, "func") - } - // Don't proceed inside funcs. - return false - case *ast.TypeSpec: - // inside a GenDecl, which usually has the doc - doc := v.Doc - if doc == nil { - doc = lastGen.Doc - } - f.lintTypeDoc(v, doc) - f.checkStutter(v.Name, "type") - // Don't proceed inside types. - return false - case *ast.ValueSpec: - f.lintValueSpecDoc(v, lastGen, genDeclMissingComments) - return false - } - return true - }) -} - -var ( - allCapsRE = regexp.MustCompile(`^[A-Z0-9_]+$`) - anyCapsRE = regexp.MustCompile(`[A-Z]`) -) - -// knownNameExceptions is a set of names that are known to be exempt from naming checks. -// This is usually because they are constrained by having to match names in the -// standard library. -var knownNameExceptions = map[string]bool{ - "LastInsertId": true, // must match database/sql - "kWh": true, -} - -func isInTopLevel(f *ast.File, ident *ast.Ident) bool { - path, _ := astutil.PathEnclosingInterval(f, ident.Pos(), ident.End()) - for _, f := range path { - switch f.(type) { - case *ast.File, *ast.GenDecl, *ast.ValueSpec, *ast.Ident: - continue - } - return false - } - return true -} - -// lintNames examines all names in the file. -// It complains if any use underscores or incorrect known initialisms. -func (f *file) lintNames() { - // Package names need slightly different handling than other names. - if strings.Contains(f.f.Name.Name, "_") && !strings.HasSuffix(f.f.Name.Name, "_test") { - f.errorf(f.f, 1, link("http://golang.org/doc/effective_go.html#package-names"), category("naming"), "don't use an underscore in package name") - } - if anyCapsRE.MatchString(f.f.Name.Name) { - f.errorf(f.f, 1, link("http://golang.org/doc/effective_go.html#package-names"), category("mixed-caps"), "don't use MixedCaps in package name; %s should be %s", f.f.Name.Name, strings.ToLower(f.f.Name.Name)) - } - - check := func(id *ast.Ident, thing string) { - if id.Name == "_" { - return - } - if knownNameExceptions[id.Name] { - return - } - - // Handle two common styles from other languages that don't belong in Go. - if len(id.Name) >= 5 && allCapsRE.MatchString(id.Name) && strings.Contains(id.Name, "_") { - capCount := 0 - for _, c := range id.Name { - if 'A' <= c && c <= 'Z' { - capCount++ - } - } - if capCount >= 2 { - f.errorf(id, 0.8, link(styleGuideBase+"#mixed-caps"), category("naming"), "don't use ALL_CAPS in Go names; use CamelCase") - return - } - } - if thing == "const" || (thing == "var" && isInTopLevel(f.f, id)) { - if len(id.Name) > 2 && id.Name[0] == 'k' && id.Name[1] >= 'A' && id.Name[1] <= 'Z' { - should := string(id.Name[1]+'a'-'A') + id.Name[2:] - f.errorf(id, 0.8, link(styleGuideBase+"#mixed-caps"), category("naming"), "don't use leading k in Go names; %s %s should be %s", thing, id.Name, should) - } - } - - should := lintName(id.Name) - if id.Name == should { - return - } - - if len(id.Name) > 2 && strings.Contains(id.Name[1:], "_") { - f.errorf(id, 0.9, link("http://golang.org/doc/effective_go.html#mixed-caps"), category("naming"), "don't use underscores in Go names; %s %s should be %s", thing, id.Name, should) - return - } - f.errorf(id, 0.8, link(styleGuideBase+"#initialisms"), category("naming"), "%s %s should be %s", thing, id.Name, should) - } - checkList := func(fl *ast.FieldList, thing string) { - if fl == nil { - return - } - for _, f := range fl.List { - for _, id := range f.Names { - check(id, thing) - } - } - } - f.walk(func(node ast.Node) bool { - switch v := node.(type) { - case *ast.AssignStmt: - if v.Tok == token.ASSIGN { - return true - } - for _, exp := range v.Lhs { - if id, ok := exp.(*ast.Ident); ok { - check(id, "var") - } - } - case *ast.FuncDecl: - if f.isTest() && (strings.HasPrefix(v.Name.Name, "Example") || strings.HasPrefix(v.Name.Name, "Test") || strings.HasPrefix(v.Name.Name, "Benchmark")) { - return true - } - - thing := "func" - if v.Recv != nil { - thing = "method" - } - - // Exclude naming warnings for functions that are exported to C but - // not exported in the Go API. - // See https://github.com/golang/lint/issues/144. - if ast.IsExported(v.Name.Name) || !isCgoExported(v) { - check(v.Name, thing) - } - - checkList(v.Type.Params, thing+" parameter") - checkList(v.Type.Results, thing+" result") - case *ast.GenDecl: - if v.Tok == token.IMPORT { - return true - } - var thing string - switch v.Tok { - case token.CONST: - thing = "const" - case token.TYPE: - thing = "type" - case token.VAR: - thing = "var" - } - for _, spec := range v.Specs { - switch s := spec.(type) { - case *ast.TypeSpec: - check(s.Name, thing) - case *ast.ValueSpec: - for _, id := range s.Names { - check(id, thing) - } - } - } - case *ast.InterfaceType: - // Do not check interface method names. - // They are often constrainted by the method names of concrete types. - for _, x := range v.Methods.List { - ft, ok := x.Type.(*ast.FuncType) - if !ok { // might be an embedded interface name - continue - } - checkList(ft.Params, "interface method parameter") - checkList(ft.Results, "interface method result") - } - case *ast.RangeStmt: - if v.Tok == token.ASSIGN { - return true - } - if id, ok := v.Key.(*ast.Ident); ok { - check(id, "range var") - } - if id, ok := v.Value.(*ast.Ident); ok { - check(id, "range var") - } - case *ast.StructType: - for _, f := range v.Fields.List { - for _, id := range f.Names { - check(id, "struct field") - } - } - } - return true - }) -} - -// lintName returns a different name if it should be different. -func lintName(name string) (should string) { - // Fast path for simple cases: "_" and all lowercase. - if name == "_" { - return name - } - allLower := true - for _, r := range name { - if !unicode.IsLower(r) { - allLower = false - break - } - } - if allLower { - return name - } - - // Split camelCase at any lower->upper transition, and split on underscores. - // Check each word for common initialisms. - runes := []rune(name) - w, i := 0, 0 // index of start of word, scan - for i+1 <= len(runes) { - eow := false // whether we hit the end of a word - if i+1 == len(runes) { - eow = true - } else if runes[i+1] == '_' { - // underscore; shift the remainder forward over any run of underscores - eow = true - n := 1 - for i+n+1 < len(runes) && runes[i+n+1] == '_' { - n++ - } - - // Leave at most one underscore if the underscore is between two digits - if i+n+1 < len(runes) && unicode.IsDigit(runes[i]) && unicode.IsDigit(runes[i+n+1]) { - n-- - } - - copy(runes[i+1:], runes[i+n+1:]) - runes = runes[:len(runes)-n] - } else if unicode.IsLower(runes[i]) && !unicode.IsLower(runes[i+1]) { - // lower->non-lower - eow = true - } - i++ - if !eow { - continue - } - - // [w,i) is a word. - word := string(runes[w:i]) - if u := strings.ToUpper(word); commonInitialisms[u] { - // Keep consistent case, which is lowercase only at the start. - if w == 0 && unicode.IsLower(runes[w]) { - u = strings.ToLower(u) - } - // All the common initialisms are ASCII, - // so we can replace the bytes exactly. - copy(runes[w:], []rune(u)) - } else if w > 0 && strings.ToLower(word) == word { - // already all lowercase, and not the first word, so uppercase the first character. - runes[w] = unicode.ToUpper(runes[w]) - } - w = i - } - return string(runes) -} - -// commonInitialisms is a set of common initialisms. -// Only add entries that are highly unlikely to be non-initialisms. -// For instance, "ID" is fine (Freudian code is rare), but "AND" is not. -var commonInitialisms = map[string]bool{ - "ACL": true, - "API": true, - "ASCII": true, - "CPU": true, - "CSS": true, - "DNS": true, - "EOF": true, - "GUID": true, - "HTML": true, - "HTTP": true, - "HTTPS": true, - "ID": true, - "IP": true, - "JSON": true, - "LHS": true, - "QPS": true, - "RAM": true, - "RHS": true, - "RPC": true, - "SLA": true, - "SMTP": true, - "SQL": true, - "SSH": true, - "TCP": true, - "TLS": true, - "TTL": true, - "UDP": true, - "UI": true, - "UID": true, - "UUID": true, - "URI": true, - "URL": true, - "UTF8": true, - "VM": true, - "XML": true, - "XMPP": true, - "XSRF": true, - "XSS": true, -} - -// lintTypeDoc examines the doc comment on a type. -// It complains if they are missing from an exported type, -// or if they are not of the standard form. -func (f *file) lintTypeDoc(t *ast.TypeSpec, doc *ast.CommentGroup) { - if !ast.IsExported(t.Name.Name) { - return - } - if doc == nil { - f.errorf(t, 1, link(docCommentsLink), category("comments"), "exported type %v should have comment or be unexported", t.Name) - return - } - - s := doc.Text() - articles := [...]string{"A", "An", "The"} - for _, a := range articles { - if strings.HasPrefix(s, a+" ") { - s = s[len(a)+1:] - break - } - } - if !strings.HasPrefix(s, t.Name.Name+" ") { - f.errorf(doc, 1, link(docCommentsLink), category("comments"), `comment on exported type %v should be of the form "%v ..." (with optional leading article)`, t.Name, t.Name) - } -} - -var commonMethods = map[string]bool{ - "Error": true, - "Read": true, - "ServeHTTP": true, - "String": true, - "Write": true, - "Unwrap": true, -} - -// lintFuncDoc examines doc comments on functions and methods. -// It complains if they are missing, or not of the right form. -// It has specific exclusions for well-known methods (see commonMethods above). -func (f *file) lintFuncDoc(fn *ast.FuncDecl) { - if !ast.IsExported(fn.Name.Name) { - // func is unexported - return - } - kind := "function" - name := fn.Name.Name - if fn.Recv != nil && len(fn.Recv.List) > 0 { - // method - kind = "method" - recv := receiverType(fn) - if !ast.IsExported(recv) { - // receiver is unexported - return - } - if commonMethods[name] { - return - } - switch name { - case "Len", "Less", "Swap": - if f.pkg.sortable[recv] { - return - } - } - name = recv + "." + name - } - if fn.Doc == nil { - f.errorf(fn, 1, link(docCommentsLink), category("comments"), "exported %s %s should have comment or be unexported", kind, name) - return - } - s := fn.Doc.Text() - prefix := fn.Name.Name + " " - if !strings.HasPrefix(s, prefix) { - f.errorf(fn.Doc, 1, link(docCommentsLink), category("comments"), `comment on exported %s %s should be of the form "%s..."`, kind, name, prefix) - } -} - -// lintValueSpecDoc examines package-global variables and constants. -// It complains if they are not individually declared, -// or if they are not suitably documented in the right form (unless they are in a block that is commented). -func (f *file) lintValueSpecDoc(vs *ast.ValueSpec, gd *ast.GenDecl, genDeclMissingComments map[*ast.GenDecl]bool) { - kind := "var" - if gd.Tok == token.CONST { - kind = "const" - } - - if len(vs.Names) > 1 { - // Check that none are exported except for the first. - for _, n := range vs.Names[1:] { - if ast.IsExported(n.Name) { - f.errorf(vs, 1, category("comments"), "exported %s %s should have its own declaration", kind, n.Name) - return - } - } - } - - // Only one name. - name := vs.Names[0].Name - if !ast.IsExported(name) { - return - } - - if vs.Doc == nil && gd.Doc == nil { - if genDeclMissingComments[gd] { - return - } - block := "" - if kind == "const" && gd.Lparen.IsValid() { - block = " (or a comment on this block)" - } - f.errorf(vs, 1, link(docCommentsLink), category("comments"), "exported %s %s should have comment%s or be unexported", kind, name, block) - genDeclMissingComments[gd] = true - return - } - // If this GenDecl has parens and a comment, we don't check its comment form. - if gd.Lparen.IsValid() && gd.Doc != nil { - return - } - // The relevant text to check will be on either vs.Doc or gd.Doc. - // Use vs.Doc preferentially. - doc := vs.Doc - if doc == nil { - doc = gd.Doc - } - prefix := name + " " - if !strings.HasPrefix(doc.Text(), prefix) { - f.errorf(doc, 1, link(docCommentsLink), category("comments"), `comment on exported %s %s should be of the form "%s..."`, kind, name, prefix) - } -} - -func (f *file) checkStutter(id *ast.Ident, thing string) { - pkg, name := f.f.Name.Name, id.Name - if !ast.IsExported(name) { - // unexported name - return - } - // A name stutters if the package name is a strict prefix - // and the next character of the name starts a new word. - if len(name) <= len(pkg) { - // name is too short to stutter. - // This permits the name to be the same as the package name. - return - } - if !strings.EqualFold(pkg, name[:len(pkg)]) { - return - } - // We can assume the name is well-formed UTF-8. - // If the next rune after the package name is uppercase or an underscore - // the it's starting a new word and thus this name stutters. - rem := name[len(pkg):] - if next, _ := utf8.DecodeRuneInString(rem); next == '_' || unicode.IsUpper(next) { - f.errorf(id, 0.8, link(styleGuideBase+"#package-names"), category("naming"), "%s name will be used as %s.%s by other packages, and that stutters; consider calling this %s", thing, pkg, name, rem) - } -} - -// zeroLiteral is a set of ast.BasicLit values that are zero values. -// It is not exhaustive. -var zeroLiteral = map[string]bool{ - "false": true, // bool - // runes - `'\x00'`: true, - `'\000'`: true, - // strings - `""`: true, - "``": true, - // numerics - "0": true, - "0.": true, - "0.0": true, - "0i": true, -} - -// lintElses examines else blocks. It complains about any else block whose if block ends in a return. -func (f *file) lintElses() { - // We don't want to flag if { } else if { } else { } constructions. - // They will appear as an IfStmt whose Else field is also an IfStmt. - // Record such a node so we ignore it when we visit it. - ignore := make(map[*ast.IfStmt]bool) - - f.walk(func(node ast.Node) bool { - ifStmt, ok := node.(*ast.IfStmt) - if !ok || ifStmt.Else == nil { - return true - } - if elseif, ok := ifStmt.Else.(*ast.IfStmt); ok { - ignore[elseif] = true - return true - } - if ignore[ifStmt] { - return true - } - if _, ok := ifStmt.Else.(*ast.BlockStmt); !ok { - // only care about elses without conditions - return true - } - if len(ifStmt.Body.List) == 0 { - return true - } - shortDecl := false // does the if statement have a ":=" initialization statement? - if ifStmt.Init != nil { - if as, ok := ifStmt.Init.(*ast.AssignStmt); ok && as.Tok == token.DEFINE { - shortDecl = true - } - } - lastStmt := ifStmt.Body.List[len(ifStmt.Body.List)-1] - if _, ok := lastStmt.(*ast.ReturnStmt); ok { - extra := "" - if shortDecl { - extra = " (move short variable declaration to its own line if necessary)" - } - f.errorf(ifStmt.Else, 1, link(styleGuideBase+"#indent-error-flow"), category("indent"), "if block ends with a return statement, so drop this else and outdent its block"+extra) - } - return true - }) -} - -// lintRanges examines range clauses. It complains about redundant constructions. -func (f *file) lintRanges() { - f.walk(func(node ast.Node) bool { - rs, ok := node.(*ast.RangeStmt) - if !ok { - return true - } - - if isIdent(rs.Key, "_") && (rs.Value == nil || isIdent(rs.Value, "_")) { - p := f.errorf(rs.Key, 1, category("range-loop"), "should omit values from range; this loop is equivalent to `for range ...`") - - newRS := *rs // shallow copy - newRS.Value = nil - newRS.Key = nil - p.ReplacementLine = f.firstLineOf(&newRS, rs) - - return true - } - - if isIdent(rs.Value, "_") { - p := f.errorf(rs.Value, 1, category("range-loop"), "should omit 2nd value from range; this loop is equivalent to `for %s %s range ...`", f.render(rs.Key), rs.Tok) - - newRS := *rs // shallow copy - newRS.Value = nil - p.ReplacementLine = f.firstLineOf(&newRS, rs) - } - - return true - }) -} - -// lintErrorf examines errors.New and testing.Error calls. It complains if its only argument is an fmt.Sprintf invocation. -func (f *file) lintErrorf() { - f.walk(func(node ast.Node) bool { - ce, ok := node.(*ast.CallExpr) - if !ok || len(ce.Args) != 1 { - return true - } - isErrorsNew := isPkgDot(ce.Fun, "errors", "New") - var isTestingError bool - se, ok := ce.Fun.(*ast.SelectorExpr) - if ok && se.Sel.Name == "Error" { - if typ := f.pkg.typeOf(se.X); typ != nil { - isTestingError = typ.String() == "*testing.T" - } - } - if !isErrorsNew && !isTestingError { - return true - } - if !f.imports("errors") { - return true - } - arg := ce.Args[0] - ce, ok = arg.(*ast.CallExpr) - if !ok || !isPkgDot(ce.Fun, "fmt", "Sprintf") { - return true - } - errorfPrefix := "fmt" - if isTestingError { - errorfPrefix = f.render(se.X) - } - p := f.errorf(node, 1, category("errors"), "should replace %s(fmt.Sprintf(...)) with %s.Errorf(...)", f.render(se), errorfPrefix) - - m := f.srcLineWithMatch(ce, `^(.*)`+f.render(se)+`\(fmt\.Sprintf\((.*)\)\)(.*)$`) - if m != nil { - p.ReplacementLine = m[1] + errorfPrefix + ".Errorf(" + m[2] + ")" + m[3] - } - - return true - }) -} - -// lintErrors examines global error vars. It complains if they aren't named in the standard way. -func (f *file) lintErrors() { - for _, decl := range f.f.Decls { - gd, ok := decl.(*ast.GenDecl) - if !ok || gd.Tok != token.VAR { - continue - } - for _, spec := range gd.Specs { - spec := spec.(*ast.ValueSpec) - if len(spec.Names) != 1 || len(spec.Values) != 1 { - continue - } - ce, ok := spec.Values[0].(*ast.CallExpr) - if !ok { - continue - } - if !isPkgDot(ce.Fun, "errors", "New") && !isPkgDot(ce.Fun, "fmt", "Errorf") { - continue - } - - id := spec.Names[0] - prefix := "err" - if id.IsExported() { - prefix = "Err" - } - if !strings.HasPrefix(id.Name, prefix) { - f.errorf(id, 0.9, category("naming"), "error var %s should have name of the form %sFoo", id.Name, prefix) - } - } - } -} - -func lintErrorString(s string) (isClean bool, conf float64) { - const basicConfidence = 0.8 - const capConfidence = basicConfidence - 0.2 - first, firstN := utf8.DecodeRuneInString(s) - last, _ := utf8.DecodeLastRuneInString(s) - if last == '.' || last == ':' || last == '!' || last == '\n' { - return false, basicConfidence - } - if unicode.IsUpper(first) { - // People use proper nouns and exported Go identifiers in error strings, - // so decrease the confidence of warnings for capitalization. - if len(s) <= firstN { - return false, capConfidence - } - // Flag strings starting with something that doesn't look like an initialism. - if second, _ := utf8.DecodeRuneInString(s[firstN:]); !unicode.IsUpper(second) { - return false, capConfidence - } - } - return true, 0 -} - -// lintErrorStrings examines error strings. -// It complains if they are capitalized or end in punctuation or a newline. -func (f *file) lintErrorStrings() { - f.walk(func(node ast.Node) bool { - ce, ok := node.(*ast.CallExpr) - if !ok { - return true - } - if !isPkgDot(ce.Fun, "errors", "New") && !isPkgDot(ce.Fun, "fmt", "Errorf") { - return true - } - if len(ce.Args) < 1 { - return true - } - str, ok := ce.Args[0].(*ast.BasicLit) - if !ok || str.Kind != token.STRING { - return true - } - s, _ := strconv.Unquote(str.Value) // can assume well-formed Go - if s == "" { - return true - } - clean, conf := lintErrorString(s) - if clean { - return true - } - - f.errorf(str, conf, link(styleGuideBase+"#error-strings"), category("errors"), - "error strings should not be capitalized or end with punctuation or a newline") - return true - }) -} - -// lintReceiverNames examines receiver names. It complains about inconsistent -// names used for the same type and names such as "this". -func (f *file) lintReceiverNames() { - typeReceiver := map[string]string{} - f.walk(func(n ast.Node) bool { - fn, ok := n.(*ast.FuncDecl) - if !ok || fn.Recv == nil || len(fn.Recv.List) == 0 { - return true - } - names := fn.Recv.List[0].Names - if len(names) < 1 { - return true - } - name := names[0].Name - const ref = styleGuideBase + "#receiver-names" - if name == "_" { - f.errorf(n, 1, link(ref), category("naming"), `receiver name should not be an underscore, omit the name if it is unused`) - return true - } - if name == "this" || name == "self" { - f.errorf(n, 1, link(ref), category("naming"), `receiver name should be a reflection of its identity; don't use generic names such as "this" or "self"`) - return true - } - recv := receiverType(fn) - if prev, ok := typeReceiver[recv]; ok && prev != name { - f.errorf(n, 1, link(ref), category("naming"), "receiver name %s should be consistent with previous receiver name %s for %s", name, prev, recv) - return true - } - typeReceiver[recv] = name - return true - }) -} - -// lintIncDec examines statements that increment or decrement a variable. -// It complains if they don't use x++ or x--. -func (f *file) lintIncDec() { - f.walk(func(n ast.Node) bool { - as, ok := n.(*ast.AssignStmt) - if !ok { - return true - } - if len(as.Lhs) != 1 { - return true - } - if !isOne(as.Rhs[0]) { - return true - } - var suffix string - switch as.Tok { - case token.ADD_ASSIGN: - suffix = "++" - case token.SUB_ASSIGN: - suffix = "--" - default: - return true - } - f.errorf(as, 0.8, category("unary-op"), "should replace %s with %s%s", f.render(as), f.render(as.Lhs[0]), suffix) - return true - }) -} - -// lintErrorReturn examines function declarations that return an error. -// It complains if the error isn't the last parameter. -func (f *file) lintErrorReturn() { - f.walk(func(n ast.Node) bool { - fn, ok := n.(*ast.FuncDecl) - if !ok || fn.Type.Results == nil { - return true - } - ret := fn.Type.Results.List - if len(ret) <= 1 { - return true - } - if isIdent(ret[len(ret)-1].Type, "error") { - return true - } - // An error return parameter should be the last parameter. - // Flag any error parameters found before the last. - for _, r := range ret[:len(ret)-1] { - if isIdent(r.Type, "error") { - f.errorf(fn, 0.9, category("arg-order"), "error should be the last type when returning multiple items") - break // only flag one - } - } - return true - }) -} - -// lintUnexportedReturn examines exported function declarations. -// It complains if any return an unexported type. -func (f *file) lintUnexportedReturn() { - f.walk(func(n ast.Node) bool { - fn, ok := n.(*ast.FuncDecl) - if !ok { - return true - } - if fn.Type.Results == nil { - return false - } - if !fn.Name.IsExported() { - return false - } - thing := "func" - if fn.Recv != nil && len(fn.Recv.List) > 0 { - thing = "method" - if !ast.IsExported(receiverType(fn)) { - // Don't report exported methods of unexported types, - // such as private implementations of sort.Interface. - return false - } - } - for _, ret := range fn.Type.Results.List { - typ := f.pkg.typeOf(ret.Type) - if exportedType(typ) { - continue - } - f.errorf(ret.Type, 0.8, category("unexported-type-in-api"), - "exported %s %s returns unexported type %s, which can be annoying to use", - thing, fn.Name.Name, typ) - break // only flag one - } - return false - }) -} - -// exportedType reports whether typ is an exported type. -// It is imprecise, and will err on the side of returning true, -// such as for composite types. -func exportedType(typ types.Type) bool { - switch T := typ.(type) { - case *types.Named: - // Builtin types have no package. - return T.Obj().Pkg() == nil || T.Obj().Exported() - case *types.Map: - return exportedType(T.Key()) && exportedType(T.Elem()) - case interface { - Elem() types.Type - }: // array, slice, pointer, chan - return exportedType(T.Elem()) - } - // Be conservative about other types, such as struct, interface, etc. - return true -} - -// timeSuffixes is a list of name suffixes that imply a time unit. -// This is not an exhaustive list. -var timeSuffixes = []string{ - "Sec", "Secs", "Seconds", - "Msec", "Msecs", - "Milli", "Millis", "Milliseconds", - "Usec", "Usecs", "Microseconds", - "MS", "Ms", -} - -func (f *file) lintTimeNames() { - f.walk(func(node ast.Node) bool { - v, ok := node.(*ast.ValueSpec) - if !ok { - return true - } - for _, name := range v.Names { - origTyp := f.pkg.typeOf(name) - // Look for time.Duration or *time.Duration; - // the latter is common when using flag.Duration. - typ := origTyp - if pt, ok := typ.(*types.Pointer); ok { - typ = pt.Elem() - } - if !f.pkg.isNamedType(typ, "time", "Duration") { - continue - } - suffix := "" - for _, suf := range timeSuffixes { - if strings.HasSuffix(name.Name, suf) { - suffix = suf - break - } - } - if suffix == "" { - continue - } - f.errorf(v, 0.9, category("time"), "var %s is of type %v; don't use unit-specific suffix %q", name.Name, origTyp, suffix) - } - return true - }) -} - -// lintContextKeyTypes checks for call expressions to context.WithValue with -// basic types used for the key argument. -// See: https://golang.org/issue/17293 -func (f *file) lintContextKeyTypes() { - f.walk(func(node ast.Node) bool { - switch node := node.(type) { - case *ast.CallExpr: - f.checkContextKeyType(node) - } - - return true - }) -} - -// checkContextKeyType reports an error if the call expression calls -// context.WithValue with a key argument of basic type. -func (f *file) checkContextKeyType(x *ast.CallExpr) { - sel, ok := x.Fun.(*ast.SelectorExpr) - if !ok { - return - } - pkg, ok := sel.X.(*ast.Ident) - if !ok || pkg.Name != "context" { - return - } - if sel.Sel.Name != "WithValue" { - return - } - - // key is second argument to context.WithValue - if len(x.Args) != 3 { - return - } - key := f.pkg.typesInfo.Types[x.Args[1]] - - if ktyp, ok := key.Type.(*types.Basic); ok && ktyp.Kind() != types.Invalid { - f.errorf(x, 1.0, category("context"), fmt.Sprintf("should not use basic type %s as key in context.WithValue", key.Type)) - } -} - -// lintContextArgs examines function declarations that contain an -// argument with a type of context.Context -// It complains if that argument isn't the first parameter. -func (f *file) lintContextArgs() { - f.walk(func(n ast.Node) bool { - fn, ok := n.(*ast.FuncDecl) - if !ok || len(fn.Type.Params.List) <= 1 { - return true - } - // A context.Context should be the first parameter of a function. - // Flag any that show up after the first. - for _, arg := range fn.Type.Params.List[1:] { - if isPkgDot(arg.Type, "context", "Context") { - f.errorf(fn, 0.9, link("https://golang.org/pkg/context/"), category("arg-order"), "context.Context should be the first parameter of a function") - break // only flag one - } - } - return true - }) -} - -// containsComments returns whether the interval [start, end) contains any -// comments without "// MATCH " prefix. -func (f *file) containsComments(start, end token.Pos) bool { - for _, cgroup := range f.f.Comments { - comments := cgroup.List - if comments[0].Slash >= end { - // All comments starting with this group are after end pos. - return false - } - if comments[len(comments)-1].Slash < start { - // Comments group ends before start pos. - continue - } - for _, c := range comments { - if start <= c.Slash && c.Slash < end && !strings.HasPrefix(c.Text, "// MATCH ") { - return true - } - } - } - return false -} - -// receiverType returns the named type of the method receiver, sans "*", -// or "invalid-type" if fn.Recv is ill formed. -func receiverType(fn *ast.FuncDecl) string { - switch e := fn.Recv.List[0].Type.(type) { - case *ast.Ident: - return e.Name - case *ast.StarExpr: - if id, ok := e.X.(*ast.Ident); ok { - return id.Name - } - } - // The parser accepts much more than just the legal forms. - return "invalid-type" -} - -func (f *file) walk(fn func(ast.Node) bool) { - ast.Walk(walker(fn), f.f) -} - -func (f *file) render(x interface{}) string { - var buf bytes.Buffer - if err := printer.Fprint(&buf, f.fset, x); err != nil { - panic(err) - } - return buf.String() -} - -func (f *file) debugRender(x interface{}) string { - var buf bytes.Buffer - if err := ast.Fprint(&buf, f.fset, x, nil); err != nil { - panic(err) - } - return buf.String() -} - -// walker adapts a function to satisfy the ast.Visitor interface. -// The function return whether the walk should proceed into the node's children. -type walker func(ast.Node) bool - -func (w walker) Visit(node ast.Node) ast.Visitor { - if w(node) { - return w - } - return nil -} - -func isIdent(expr ast.Expr, ident string) bool { - id, ok := expr.(*ast.Ident) - return ok && id.Name == ident -} - -// isBlank returns whether id is the blank identifier "_". -// If id == nil, the answer is false. -func isBlank(id *ast.Ident) bool { return id != nil && id.Name == "_" } - -func isPkgDot(expr ast.Expr, pkg, name string) bool { - sel, ok := expr.(*ast.SelectorExpr) - return ok && isIdent(sel.X, pkg) && isIdent(sel.Sel, name) -} - -func isOne(expr ast.Expr) bool { - lit, ok := expr.(*ast.BasicLit) - return ok && lit.Kind == token.INT && lit.Value == "1" -} - -func isCgoExported(f *ast.FuncDecl) bool { - if f.Recv != nil || f.Doc == nil { - return false - } - - cgoExport := regexp.MustCompile(fmt.Sprintf("(?m)^//export %s$", regexp.QuoteMeta(f.Name.Name))) - for _, c := range f.Doc.List { - if cgoExport.MatchString(c.Text) { - return true - } - } - return false -} - -var basicTypeKinds = map[types.BasicKind]string{ - types.UntypedBool: "bool", - types.UntypedInt: "int", - types.UntypedRune: "rune", - types.UntypedFloat: "float64", - types.UntypedComplex: "complex128", - types.UntypedString: "string", -} - -// isUntypedConst reports whether expr is an untyped constant, -// and indicates what its default type is. -// scope may be nil. -func (f *file) isUntypedConst(expr ast.Expr) (defType string, ok bool) { - // Re-evaluate expr outside of its context to see if it's untyped. - // (An expr evaluated within, for example, an assignment context will get the type of the LHS.) - exprStr := f.render(expr) - tv, err := types.Eval(f.fset, f.pkg.typesPkg, expr.Pos(), exprStr) - if err != nil { - return "", false - } - if b, ok := tv.Type.(*types.Basic); ok { - if dt, ok := basicTypeKinds[b.Kind()]; ok { - return dt, true - } - } - - return "", false -} - -// firstLineOf renders the given node and returns its first line. -// It will also match the indentation of another node. -func (f *file) firstLineOf(node, match ast.Node) string { - line := f.render(node) - if i := strings.Index(line, "\n"); i >= 0 { - line = line[:i] - } - return f.indentOf(match) + line -} - -func (f *file) indentOf(node ast.Node) string { - line := srcLine(f.src, f.fset.Position(node.Pos())) - for i, r := range line { - switch r { - case ' ', '\t': - default: - return line[:i] - } - } - return line // unusual or empty line -} - -func (f *file) srcLineWithMatch(node ast.Node, pattern string) (m []string) { - line := srcLine(f.src, f.fset.Position(node.Pos())) - line = strings.TrimSuffix(line, "\n") - rx := regexp.MustCompile(pattern) - return rx.FindStringSubmatch(line) -} - -// imports returns true if the current file imports the specified package path. -func (f *file) imports(importPath string) bool { - all := astutil.Imports(f.fset, f.f) - for _, p := range all { - for _, i := range p { - uq, err := strconv.Unquote(i.Path.Value) - if err == nil && importPath == uq { - return true - } - } - } - return false -} - -// srcLine returns the complete line at p, including the terminating newline. -func srcLine(src []byte, p token.Position) string { - // Run to end of line in both directions if not at line start/end. - lo, hi := p.Offset, p.Offset+1 - for lo > 0 && src[lo-1] != '\n' { - lo-- - } - for hi < len(src) && src[hi-1] != '\n' { - hi++ - } - return string(src[lo:hi]) -} diff --git a/vendor/golang.org/x/mod/internal/lazyregexp/lazyre.go b/vendor/golang.org/x/mod/internal/lazyregexp/lazyre.go deleted file mode 100644 index 2681af35af1..00000000000 --- a/vendor/golang.org/x/mod/internal/lazyregexp/lazyre.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package lazyregexp is a thin wrapper over regexp, allowing the use of global -// regexp variables without forcing them to be compiled at init. -package lazyregexp - -import ( - "os" - "regexp" - "strings" - "sync" -) - -// Regexp is a wrapper around regexp.Regexp, where the underlying regexp will be -// compiled the first time it is needed. -type Regexp struct { - str string - once sync.Once - rx *regexp.Regexp -} - -func (r *Regexp) re() *regexp.Regexp { - r.once.Do(r.build) - return r.rx -} - -func (r *Regexp) build() { - r.rx = regexp.MustCompile(r.str) - r.str = "" -} - -func (r *Regexp) FindSubmatch(s []byte) [][]byte { - return r.re().FindSubmatch(s) -} - -func (r *Regexp) FindStringSubmatch(s string) []string { - return r.re().FindStringSubmatch(s) -} - -func (r *Regexp) FindStringSubmatchIndex(s string) []int { - return r.re().FindStringSubmatchIndex(s) -} - -func (r *Regexp) ReplaceAllString(src, repl string) string { - return r.re().ReplaceAllString(src, repl) -} - -func (r *Regexp) FindString(s string) string { - return r.re().FindString(s) -} - -func (r *Regexp) FindAllString(s string, n int) []string { - return r.re().FindAllString(s, n) -} - -func (r *Regexp) MatchString(s string) bool { - return r.re().MatchString(s) -} - -func (r *Regexp) SubexpNames() []string { - return r.re().SubexpNames() -} - -var inTest = len(os.Args) > 0 && strings.HasSuffix(strings.TrimSuffix(os.Args[0], ".exe"), ".test") - -// New creates a new lazy regexp, delaying the compiling work until it is first -// needed. If the code is being run as part of tests, the regexp compiling will -// happen immediately. -func New(str string) *Regexp { - lr := &Regexp{str: str} - if inTest { - // In tests, always compile the regexps early. - lr.re() - } - return lr -} diff --git a/vendor/golang.org/x/mod/module/module.go b/vendor/golang.org/x/mod/module/module.go deleted file mode 100644 index e9dec6e6148..00000000000 --- a/vendor/golang.org/x/mod/module/module.go +++ /dev/null @@ -1,841 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package module defines the module.Version type along with support code. -// -// The module.Version type is a simple Path, Version pair: -// -// type Version struct { -// Path string -// Version string -// } -// -// There are no restrictions imposed directly by use of this structure, -// but additional checking functions, most notably Check, verify that -// a particular path, version pair is valid. -// -// # Escaped Paths -// -// Module paths appear as substrings of file system paths -// (in the download cache) and of web server URLs in the proxy protocol. -// In general we cannot rely on file systems to be case-sensitive, -// nor can we rely on web servers, since they read from file systems. -// That is, we cannot rely on the file system to keep rsc.io/QUOTE -// and rsc.io/quote separate. Windows and macOS don't. -// Instead, we must never require two different casings of a file path. -// Because we want the download cache to match the proxy protocol, -// and because we want the proxy protocol to be possible to serve -// from a tree of static files (which might be stored on a case-insensitive -// file system), the proxy protocol must never require two different casings -// of a URL path either. -// -// One possibility would be to make the escaped form be the lowercase -// hexadecimal encoding of the actual path bytes. This would avoid ever -// needing different casings of a file path, but it would be fairly illegible -// to most programmers when those paths appeared in the file system -// (including in file paths in compiler errors and stack traces) -// in web server logs, and so on. Instead, we want a safe escaped form that -// leaves most paths unaltered. -// -// The safe escaped form is to replace every uppercase letter -// with an exclamation mark followed by the letter's lowercase equivalent. -// -// For example, -// -// github.com/Azure/azure-sdk-for-go -> github.com/!azure/azure-sdk-for-go. -// github.com/GoogleCloudPlatform/cloudsql-proxy -> github.com/!google!cloud!platform/cloudsql-proxy -// github.com/Sirupsen/logrus -> github.com/!sirupsen/logrus. -// -// Import paths that avoid upper-case letters are left unchanged. -// Note that because import paths are ASCII-only and avoid various -// problematic punctuation (like : < and >), the escaped form is also ASCII-only -// and avoids the same problematic punctuation. -// -// Import paths have never allowed exclamation marks, so there is no -// need to define how to escape a literal !. -// -// # Unicode Restrictions -// -// Today, paths are disallowed from using Unicode. -// -// Although paths are currently disallowed from using Unicode, -// we would like at some point to allow Unicode letters as well, to assume that -// file systems and URLs are Unicode-safe (storing UTF-8), and apply -// the !-for-uppercase convention for escaping them in the file system. -// But there are at least two subtle considerations. -// -// First, note that not all case-fold equivalent distinct runes -// form an upper/lower pair. -// For example, U+004B ('K'), U+006B ('k'), and U+212A ('K' for Kelvin) -// are three distinct runes that case-fold to each other. -// When we do add Unicode letters, we must not assume that upper/lower -// are the only case-equivalent pairs. -// Perhaps the Kelvin symbol would be disallowed entirely, for example. -// Or perhaps it would escape as "!!k", or perhaps as "(212A)". -// -// Second, it would be nice to allow Unicode marks as well as letters, -// but marks include combining marks, and then we must deal not -// only with case folding but also normalization: both U+00E9 ('é') -// and U+0065 U+0301 ('e' followed by combining acute accent) -// look the same on the page and are treated by some file systems -// as the same path. If we do allow Unicode marks in paths, there -// must be some kind of normalization to allow only one canonical -// encoding of any character used in an import path. -package module - -// IMPORTANT NOTE -// -// This file essentially defines the set of valid import paths for the go command. -// There are many subtle considerations, including Unicode ambiguity, -// security, network, and file system representations. -// -// This file also defines the set of valid module path and version combinations, -// another topic with many subtle considerations. -// -// Changes to the semantics in this file require approval from rsc. - -import ( - "errors" - "fmt" - "path" - "sort" - "strings" - "unicode" - "unicode/utf8" - - "golang.org/x/mod/semver" -) - -// A Version (for clients, a module.Version) is defined by a module path and version pair. -// These are stored in their plain (unescaped) form. -type Version struct { - // Path is a module path, like "golang.org/x/text" or "rsc.io/quote/v2". - Path string - - // Version is usually a semantic version in canonical form. - // There are three exceptions to this general rule. - // First, the top-level target of a build has no specific version - // and uses Version = "". - // Second, during MVS calculations the version "none" is used - // to represent the decision to take no version of a given module. - // Third, filesystem paths found in "replace" directives are - // represented by a path with an empty version. - Version string `json:",omitempty"` -} - -// String returns a representation of the Version suitable for logging -// (Path@Version, or just Path if Version is empty). -func (m Version) String() string { - if m.Version == "" { - return m.Path - } - return m.Path + "@" + m.Version -} - -// A ModuleError indicates an error specific to a module. -type ModuleError struct { - Path string - Version string - Err error -} - -// VersionError returns a ModuleError derived from a Version and error, -// or err itself if it is already such an error. -func VersionError(v Version, err error) error { - var mErr *ModuleError - if errors.As(err, &mErr) && mErr.Path == v.Path && mErr.Version == v.Version { - return err - } - return &ModuleError{ - Path: v.Path, - Version: v.Version, - Err: err, - } -} - -func (e *ModuleError) Error() string { - if v, ok := e.Err.(*InvalidVersionError); ok { - return fmt.Sprintf("%s@%s: invalid %s: %v", e.Path, v.Version, v.noun(), v.Err) - } - if e.Version != "" { - return fmt.Sprintf("%s@%s: %v", e.Path, e.Version, e.Err) - } - return fmt.Sprintf("module %s: %v", e.Path, e.Err) -} - -func (e *ModuleError) Unwrap() error { return e.Err } - -// An InvalidVersionError indicates an error specific to a version, with the -// module path unknown or specified externally. -// -// A ModuleError may wrap an InvalidVersionError, but an InvalidVersionError -// must not wrap a ModuleError. -type InvalidVersionError struct { - Version string - Pseudo bool - Err error -} - -// noun returns either "version" or "pseudo-version", depending on whether -// e.Version is a pseudo-version. -func (e *InvalidVersionError) noun() string { - if e.Pseudo { - return "pseudo-version" - } - return "version" -} - -func (e *InvalidVersionError) Error() string { - return fmt.Sprintf("%s %q invalid: %s", e.noun(), e.Version, e.Err) -} - -func (e *InvalidVersionError) Unwrap() error { return e.Err } - -// An InvalidPathError indicates a module, import, or file path doesn't -// satisfy all naming constraints. See CheckPath, CheckImportPath, -// and CheckFilePath for specific restrictions. -type InvalidPathError struct { - Kind string // "module", "import", or "file" - Path string - Err error -} - -func (e *InvalidPathError) Error() string { - return fmt.Sprintf("malformed %s path %q: %v", e.Kind, e.Path, e.Err) -} - -func (e *InvalidPathError) Unwrap() error { return e.Err } - -// Check checks that a given module path, version pair is valid. -// In addition to the path being a valid module path -// and the version being a valid semantic version, -// the two must correspond. -// For example, the path "yaml/v2" only corresponds to -// semantic versions beginning with "v2.". -func Check(path, version string) error { - if err := CheckPath(path); err != nil { - return err - } - if !semver.IsValid(version) { - return &ModuleError{ - Path: path, - Err: &InvalidVersionError{Version: version, Err: errors.New("not a semantic version")}, - } - } - _, pathMajor, _ := SplitPathVersion(path) - if err := CheckPathMajor(version, pathMajor); err != nil { - return &ModuleError{Path: path, Err: err} - } - return nil -} - -// firstPathOK reports whether r can appear in the first element of a module path. -// The first element of the path must be an LDH domain name, at least for now. -// To avoid case ambiguity, the domain name must be entirely lower case. -func firstPathOK(r rune) bool { - return r == '-' || r == '.' || - '0' <= r && r <= '9' || - 'a' <= r && r <= 'z' -} - -// modPathOK reports whether r can appear in a module path element. -// Paths can be ASCII letters, ASCII digits, and limited ASCII punctuation: - . _ and ~. -// -// This matches what "go get" has historically recognized in import paths, -// and avoids confusing sequences like '%20' or '+' that would change meaning -// if used in a URL. -// -// TODO(rsc): We would like to allow Unicode letters, but that requires additional -// care in the safe encoding (see "escaped paths" above). -func modPathOK(r rune) bool { - if r < utf8.RuneSelf { - return r == '-' || r == '.' || r == '_' || r == '~' || - '0' <= r && r <= '9' || - 'A' <= r && r <= 'Z' || - 'a' <= r && r <= 'z' - } - return false -} - -// importPathOK reports whether r can appear in a package import path element. -// -// Import paths are intermediate between module paths and file paths: we allow -// disallow characters that would be confusing or ambiguous as arguments to -// 'go get' (such as '@' and ' ' ), but allow certain characters that are -// otherwise-unambiguous on the command line and historically used for some -// binary names (such as '++' as a suffix for compiler binaries and wrappers). -func importPathOK(r rune) bool { - return modPathOK(r) || r == '+' -} - -// fileNameOK reports whether r can appear in a file name. -// For now we allow all Unicode letters but otherwise limit to pathOK plus a few more punctuation characters. -// If we expand the set of allowed characters here, we have to -// work harder at detecting potential case-folding and normalization collisions. -// See note about "escaped paths" above. -func fileNameOK(r rune) bool { - if r < utf8.RuneSelf { - // Entire set of ASCII punctuation, from which we remove characters: - // ! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ ` { | } ~ - // We disallow some shell special characters: " ' * < > ? ` | - // (Note that some of those are disallowed by the Windows file system as well.) - // We also disallow path separators / : and \ (fileNameOK is only called on path element characters). - // We allow spaces (U+0020) in file names. - const allowed = "!#$%&()+,-.=@[]^_{}~ " - if '0' <= r && r <= '9' || 'A' <= r && r <= 'Z' || 'a' <= r && r <= 'z' { - return true - } - return strings.ContainsRune(allowed, r) - } - // It may be OK to add more ASCII punctuation here, but only carefully. - // For example Windows disallows < > \, and macOS disallows :, so we must not allow those. - return unicode.IsLetter(r) -} - -// CheckPath checks that a module path is valid. -// A valid module path is a valid import path, as checked by CheckImportPath, -// with three additional constraints. -// First, the leading path element (up to the first slash, if any), -// by convention a domain name, must contain only lower-case ASCII letters, -// ASCII digits, dots (U+002E), and dashes (U+002D); -// it must contain at least one dot and cannot start with a dash. -// Second, for a final path element of the form /vN, where N looks numeric -// (ASCII digits and dots) must not begin with a leading zero, must not be /v1, -// and must not contain any dots. For paths beginning with "gopkg.in/", -// this second requirement is replaced by a requirement that the path -// follow the gopkg.in server's conventions. -// Third, no path element may begin with a dot. -func CheckPath(path string) (err error) { - defer func() { - if err != nil { - err = &InvalidPathError{Kind: "module", Path: path, Err: err} - } - }() - - if err := checkPath(path, modulePath); err != nil { - return err - } - i := strings.Index(path, "/") - if i < 0 { - i = len(path) - } - if i == 0 { - return fmt.Errorf("leading slash") - } - if !strings.Contains(path[:i], ".") { - return fmt.Errorf("missing dot in first path element") - } - if path[0] == '-' { - return fmt.Errorf("leading dash in first path element") - } - for _, r := range path[:i] { - if !firstPathOK(r) { - return fmt.Errorf("invalid char %q in first path element", r) - } - } - if _, _, ok := SplitPathVersion(path); !ok { - return fmt.Errorf("invalid version") - } - return nil -} - -// CheckImportPath checks that an import path is valid. -// -// A valid import path consists of one or more valid path elements -// separated by slashes (U+002F). (It must not begin with nor end in a slash.) -// -// A valid path element is a non-empty string made up of -// ASCII letters, ASCII digits, and limited ASCII punctuation: - . _ and ~. -// It must not end with a dot (U+002E), nor contain two dots in a row. -// -// The element prefix up to the first dot must not be a reserved file name -// on Windows, regardless of case (CON, com1, NuL, and so on). The element -// must not have a suffix of a tilde followed by one or more ASCII digits -// (to exclude paths elements that look like Windows short-names). -// -// CheckImportPath may be less restrictive in the future, but see the -// top-level package documentation for additional information about -// subtleties of Unicode. -func CheckImportPath(path string) error { - if err := checkPath(path, importPath); err != nil { - return &InvalidPathError{Kind: "import", Path: path, Err: err} - } - return nil -} - -// pathKind indicates what kind of path we're checking. Module paths, -// import paths, and file paths have different restrictions. -type pathKind int - -const ( - modulePath pathKind = iota - importPath - filePath -) - -// checkPath checks that a general path is valid. kind indicates what -// specific constraints should be applied. -// -// checkPath returns an error describing why the path is not valid. -// Because these checks apply to module, import, and file paths, -// and because other checks may be applied, the caller is expected to wrap -// this error with InvalidPathError. -func checkPath(path string, kind pathKind) error { - if !utf8.ValidString(path) { - return fmt.Errorf("invalid UTF-8") - } - if path == "" { - return fmt.Errorf("empty string") - } - if path[0] == '-' && kind != filePath { - return fmt.Errorf("leading dash") - } - if strings.Contains(path, "//") { - return fmt.Errorf("double slash") - } - if path[len(path)-1] == '/' { - return fmt.Errorf("trailing slash") - } - elemStart := 0 - for i, r := range path { - if r == '/' { - if err := checkElem(path[elemStart:i], kind); err != nil { - return err - } - elemStart = i + 1 - } - } - if err := checkElem(path[elemStart:], kind); err != nil { - return err - } - return nil -} - -// checkElem checks whether an individual path element is valid. -func checkElem(elem string, kind pathKind) error { - if elem == "" { - return fmt.Errorf("empty path element") - } - if strings.Count(elem, ".") == len(elem) { - return fmt.Errorf("invalid path element %q", elem) - } - if elem[0] == '.' && kind == modulePath { - return fmt.Errorf("leading dot in path element") - } - if elem[len(elem)-1] == '.' { - return fmt.Errorf("trailing dot in path element") - } - for _, r := range elem { - ok := false - switch kind { - case modulePath: - ok = modPathOK(r) - case importPath: - ok = importPathOK(r) - case filePath: - ok = fileNameOK(r) - default: - panic(fmt.Sprintf("internal error: invalid kind %v", kind)) - } - if !ok { - return fmt.Errorf("invalid char %q", r) - } - } - - // Windows disallows a bunch of path elements, sadly. - // See https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file - short := elem - if i := strings.Index(short, "."); i >= 0 { - short = short[:i] - } - for _, bad := range badWindowsNames { - if strings.EqualFold(bad, short) { - return fmt.Errorf("%q disallowed as path element component on Windows", short) - } - } - - if kind == filePath { - // don't check for Windows short-names in file names. They're - // only an issue for import paths. - return nil - } - - // Reject path components that look like Windows short-names. - // Those usually end in a tilde followed by one or more ASCII digits. - if tilde := strings.LastIndexByte(short, '~'); tilde >= 0 && tilde < len(short)-1 { - suffix := short[tilde+1:] - suffixIsDigits := true - for _, r := range suffix { - if r < '0' || r > '9' { - suffixIsDigits = false - break - } - } - if suffixIsDigits { - return fmt.Errorf("trailing tilde and digits in path element") - } - } - - return nil -} - -// CheckFilePath checks that a slash-separated file path is valid. -// The definition of a valid file path is the same as the definition -// of a valid import path except that the set of allowed characters is larger: -// all Unicode letters, ASCII digits, the ASCII space character (U+0020), -// and the ASCII punctuation characters -// “!#$%&()+,-.=@[]^_{}~”. -// (The excluded punctuation characters, " * < > ? ` ' | / \ and :, -// have special meanings in certain shells or operating systems.) -// -// CheckFilePath may be less restrictive in the future, but see the -// top-level package documentation for additional information about -// subtleties of Unicode. -func CheckFilePath(path string) error { - if err := checkPath(path, filePath); err != nil { - return &InvalidPathError{Kind: "file", Path: path, Err: err} - } - return nil -} - -// badWindowsNames are the reserved file path elements on Windows. -// See https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file -var badWindowsNames = []string{ - "CON", - "PRN", - "AUX", - "NUL", - "COM1", - "COM2", - "COM3", - "COM4", - "COM5", - "COM6", - "COM7", - "COM8", - "COM9", - "LPT1", - "LPT2", - "LPT3", - "LPT4", - "LPT5", - "LPT6", - "LPT7", - "LPT8", - "LPT9", -} - -// SplitPathVersion returns prefix and major version such that prefix+pathMajor == path -// and version is either empty or "/vN" for N >= 2. -// As a special case, gopkg.in paths are recognized directly; -// they require ".vN" instead of "/vN", and for all N, not just N >= 2. -// SplitPathVersion returns with ok = false when presented with -// a path whose last path element does not satisfy the constraints -// applied by CheckPath, such as "example.com/pkg/v1" or "example.com/pkg/v1.2". -func SplitPathVersion(path string) (prefix, pathMajor string, ok bool) { - if strings.HasPrefix(path, "gopkg.in/") { - return splitGopkgIn(path) - } - - i := len(path) - dot := false - for i > 0 && ('0' <= path[i-1] && path[i-1] <= '9' || path[i-1] == '.') { - if path[i-1] == '.' { - dot = true - } - i-- - } - if i <= 1 || i == len(path) || path[i-1] != 'v' || path[i-2] != '/' { - return path, "", true - } - prefix, pathMajor = path[:i-2], path[i-2:] - if dot || len(pathMajor) <= 2 || pathMajor[2] == '0' || pathMajor == "/v1" { - return path, "", false - } - return prefix, pathMajor, true -} - -// splitGopkgIn is like SplitPathVersion but only for gopkg.in paths. -func splitGopkgIn(path string) (prefix, pathMajor string, ok bool) { - if !strings.HasPrefix(path, "gopkg.in/") { - return path, "", false - } - i := len(path) - if strings.HasSuffix(path, "-unstable") { - i -= len("-unstable") - } - for i > 0 && ('0' <= path[i-1] && path[i-1] <= '9') { - i-- - } - if i <= 1 || path[i-1] != 'v' || path[i-2] != '.' { - // All gopkg.in paths must end in vN for some N. - return path, "", false - } - prefix, pathMajor = path[:i-2], path[i-2:] - if len(pathMajor) <= 2 || pathMajor[2] == '0' && pathMajor != ".v0" { - return path, "", false - } - return prefix, pathMajor, true -} - -// MatchPathMajor reports whether the semantic version v -// matches the path major version pathMajor. -// -// MatchPathMajor returns true if and only if CheckPathMajor returns nil. -func MatchPathMajor(v, pathMajor string) bool { - return CheckPathMajor(v, pathMajor) == nil -} - -// CheckPathMajor returns a non-nil error if the semantic version v -// does not match the path major version pathMajor. -func CheckPathMajor(v, pathMajor string) error { - // TODO(jayconrod): return errors or panic for invalid inputs. This function - // (and others) was covered by integration tests for cmd/go, and surrounding - // code protected against invalid inputs like non-canonical versions. - if strings.HasPrefix(pathMajor, ".v") && strings.HasSuffix(pathMajor, "-unstable") { - pathMajor = strings.TrimSuffix(pathMajor, "-unstable") - } - if strings.HasPrefix(v, "v0.0.0-") && pathMajor == ".v1" { - // Allow old bug in pseudo-versions that generated v0.0.0- pseudoversion for gopkg .v1. - // For example, gopkg.in/yaml.v2@v2.2.1's go.mod requires gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405. - return nil - } - m := semver.Major(v) - if pathMajor == "" { - if m == "v0" || m == "v1" || semver.Build(v) == "+incompatible" { - return nil - } - pathMajor = "v0 or v1" - } else if pathMajor[0] == '/' || pathMajor[0] == '.' { - if m == pathMajor[1:] { - return nil - } - pathMajor = pathMajor[1:] - } - return &InvalidVersionError{ - Version: v, - Err: fmt.Errorf("should be %s, not %s", pathMajor, semver.Major(v)), - } -} - -// PathMajorPrefix returns the major-version tag prefix implied by pathMajor. -// An empty PathMajorPrefix allows either v0 or v1. -// -// Note that MatchPathMajor may accept some versions that do not actually begin -// with this prefix: namely, it accepts a 'v0.0.0-' prefix for a '.v1' -// pathMajor, even though that pathMajor implies 'v1' tagging. -func PathMajorPrefix(pathMajor string) string { - if pathMajor == "" { - return "" - } - if pathMajor[0] != '/' && pathMajor[0] != '.' { - panic("pathMajor suffix " + pathMajor + " passed to PathMajorPrefix lacks separator") - } - if strings.HasPrefix(pathMajor, ".v") && strings.HasSuffix(pathMajor, "-unstable") { - pathMajor = strings.TrimSuffix(pathMajor, "-unstable") - } - m := pathMajor[1:] - if m != semver.Major(m) { - panic("pathMajor suffix " + pathMajor + "passed to PathMajorPrefix is not a valid major version") - } - return m -} - -// CanonicalVersion returns the canonical form of the version string v. -// It is the same as semver.Canonical(v) except that it preserves the special build suffix "+incompatible". -func CanonicalVersion(v string) string { - cv := semver.Canonical(v) - if semver.Build(v) == "+incompatible" { - cv += "+incompatible" - } - return cv -} - -// Sort sorts the list by Path, breaking ties by comparing Version fields. -// The Version fields are interpreted as semantic versions (using semver.Compare) -// optionally followed by a tie-breaking suffix introduced by a slash character, -// like in "v0.0.1/go.mod". -func Sort(list []Version) { - sort.Slice(list, func(i, j int) bool { - mi := list[i] - mj := list[j] - if mi.Path != mj.Path { - return mi.Path < mj.Path - } - // To help go.sum formatting, allow version/file. - // Compare semver prefix by semver rules, - // file by string order. - vi := mi.Version - vj := mj.Version - var fi, fj string - if k := strings.Index(vi, "/"); k >= 0 { - vi, fi = vi[:k], vi[k:] - } - if k := strings.Index(vj, "/"); k >= 0 { - vj, fj = vj[:k], vj[k:] - } - if vi != vj { - return semver.Compare(vi, vj) < 0 - } - return fi < fj - }) -} - -// EscapePath returns the escaped form of the given module path. -// It fails if the module path is invalid. -func EscapePath(path string) (escaped string, err error) { - if err := CheckPath(path); err != nil { - return "", err - } - - return escapeString(path) -} - -// EscapeVersion returns the escaped form of the given module version. -// Versions are allowed to be in non-semver form but must be valid file names -// and not contain exclamation marks. -func EscapeVersion(v string) (escaped string, err error) { - if err := checkElem(v, filePath); err != nil || strings.Contains(v, "!") { - return "", &InvalidVersionError{ - Version: v, - Err: fmt.Errorf("disallowed version string"), - } - } - return escapeString(v) -} - -func escapeString(s string) (escaped string, err error) { - haveUpper := false - for _, r := range s { - if r == '!' || r >= utf8.RuneSelf { - // This should be disallowed by CheckPath, but diagnose anyway. - // The correctness of the escaping loop below depends on it. - return "", fmt.Errorf("internal error: inconsistency in EscapePath") - } - if 'A' <= r && r <= 'Z' { - haveUpper = true - } - } - - if !haveUpper { - return s, nil - } - - var buf []byte - for _, r := range s { - if 'A' <= r && r <= 'Z' { - buf = append(buf, '!', byte(r+'a'-'A')) - } else { - buf = append(buf, byte(r)) - } - } - return string(buf), nil -} - -// UnescapePath returns the module path for the given escaped path. -// It fails if the escaped path is invalid or describes an invalid path. -func UnescapePath(escaped string) (path string, err error) { - path, ok := unescapeString(escaped) - if !ok { - return "", fmt.Errorf("invalid escaped module path %q", escaped) - } - if err := CheckPath(path); err != nil { - return "", fmt.Errorf("invalid escaped module path %q: %v", escaped, err) - } - return path, nil -} - -// UnescapeVersion returns the version string for the given escaped version. -// It fails if the escaped form is invalid or describes an invalid version. -// Versions are allowed to be in non-semver form but must be valid file names -// and not contain exclamation marks. -func UnescapeVersion(escaped string) (v string, err error) { - v, ok := unescapeString(escaped) - if !ok { - return "", fmt.Errorf("invalid escaped version %q", escaped) - } - if err := checkElem(v, filePath); err != nil { - return "", fmt.Errorf("invalid escaped version %q: %v", v, err) - } - return v, nil -} - -func unescapeString(escaped string) (string, bool) { - var buf []byte - - bang := false - for _, r := range escaped { - if r >= utf8.RuneSelf { - return "", false - } - if bang { - bang = false - if r < 'a' || 'z' < r { - return "", false - } - buf = append(buf, byte(r+'A'-'a')) - continue - } - if r == '!' { - bang = true - continue - } - if 'A' <= r && r <= 'Z' { - return "", false - } - buf = append(buf, byte(r)) - } - if bang { - return "", false - } - return string(buf), true -} - -// MatchPrefixPatterns reports whether any path prefix of target matches one of -// the glob patterns (as defined by path.Match) in the comma-separated globs -// list. This implements the algorithm used when matching a module path to the -// GOPRIVATE environment variable, as described by 'go help module-private'. -// -// It ignores any empty or malformed patterns in the list. -// Trailing slashes on patterns are ignored. -func MatchPrefixPatterns(globs, target string) bool { - for globs != "" { - // Extract next non-empty glob in comma-separated list. - var glob string - if i := strings.Index(globs, ","); i >= 0 { - glob, globs = globs[:i], globs[i+1:] - } else { - glob, globs = globs, "" - } - glob = strings.TrimSuffix(glob, "/") - if glob == "" { - continue - } - - // A glob with N+1 path elements (N slashes) needs to be matched - // against the first N+1 path elements of target, - // which end just before the N+1'th slash. - n := strings.Count(glob, "/") - prefix := target - // Walk target, counting slashes, truncating at the N+1'th slash. - for i := 0; i < len(target); i++ { - if target[i] == '/' { - if n == 0 { - prefix = target[:i] - break - } - n-- - } - } - if n > 0 { - // Not enough prefix elements. - continue - } - matched, _ := path.Match(glob, prefix) - if matched { - return true - } - } - return false -} diff --git a/vendor/golang.org/x/mod/module/pseudo.go b/vendor/golang.org/x/mod/module/pseudo.go deleted file mode 100644 index f04ad378869..00000000000 --- a/vendor/golang.org/x/mod/module/pseudo.go +++ /dev/null @@ -1,250 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Pseudo-versions -// -// Code authors are expected to tag the revisions they want users to use, -// including prereleases. However, not all authors tag versions at all, -// and not all commits a user might want to try will have tags. -// A pseudo-version is a version with a special form that allows us to -// address an untagged commit and order that version with respect to -// other versions we might encounter. -// -// A pseudo-version takes one of the general forms: -// -// (1) vX.0.0-yyyymmddhhmmss-abcdef123456 -// (2) vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdef123456 -// (3) vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdef123456+incompatible -// (4) vX.Y.Z-pre.0.yyyymmddhhmmss-abcdef123456 -// (5) vX.Y.Z-pre.0.yyyymmddhhmmss-abcdef123456+incompatible -// -// If there is no recently tagged version with the right major version vX, -// then form (1) is used, creating a space of pseudo-versions at the bottom -// of the vX version range, less than any tagged version, including the unlikely v0.0.0. -// -// If the most recent tagged version before the target commit is vX.Y.Z or vX.Y.Z+incompatible, -// then the pseudo-version uses form (2) or (3), making it a prerelease for the next -// possible semantic version after vX.Y.Z. The leading 0 segment in the prerelease string -// ensures that the pseudo-version compares less than possible future explicit prereleases -// like vX.Y.(Z+1)-rc1 or vX.Y.(Z+1)-1. -// -// If the most recent tagged version before the target commit is vX.Y.Z-pre or vX.Y.Z-pre+incompatible, -// then the pseudo-version uses form (4) or (5), making it a slightly later prerelease. - -package module - -import ( - "errors" - "fmt" - "strings" - "time" - - "golang.org/x/mod/internal/lazyregexp" - "golang.org/x/mod/semver" -) - -var pseudoVersionRE = lazyregexp.New(`^v[0-9]+\.(0\.0-|\d+\.\d+-([^+]*\.)?0\.)\d{14}-[A-Za-z0-9]+(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$`) - -const PseudoVersionTimestampFormat = "20060102150405" - -// PseudoVersion returns a pseudo-version for the given major version ("v1") -// preexisting older tagged version ("" or "v1.2.3" or "v1.2.3-pre"), revision time, -// and revision identifier (usually a 12-byte commit hash prefix). -func PseudoVersion(major, older string, t time.Time, rev string) string { - if major == "" { - major = "v0" - } - segment := fmt.Sprintf("%s-%s", t.UTC().Format(PseudoVersionTimestampFormat), rev) - build := semver.Build(older) - older = semver.Canonical(older) - if older == "" { - return major + ".0.0-" + segment // form (1) - } - if semver.Prerelease(older) != "" { - return older + ".0." + segment + build // form (4), (5) - } - - // Form (2), (3). - // Extract patch from vMAJOR.MINOR.PATCH - i := strings.LastIndex(older, ".") + 1 - v, patch := older[:i], older[i:] - - // Reassemble. - return v + incDecimal(patch) + "-0." + segment + build -} - -// ZeroPseudoVersion returns a pseudo-version with a zero timestamp and -// revision, which may be used as a placeholder. -func ZeroPseudoVersion(major string) string { - return PseudoVersion(major, "", time.Time{}, "000000000000") -} - -// incDecimal returns the decimal string incremented by 1. -func incDecimal(decimal string) string { - // Scan right to left turning 9s to 0s until you find a digit to increment. - digits := []byte(decimal) - i := len(digits) - 1 - for ; i >= 0 && digits[i] == '9'; i-- { - digits[i] = '0' - } - if i >= 0 { - digits[i]++ - } else { - // digits is all zeros - digits[0] = '1' - digits = append(digits, '0') - } - return string(digits) -} - -// decDecimal returns the decimal string decremented by 1, or the empty string -// if the decimal is all zeroes. -func decDecimal(decimal string) string { - // Scan right to left turning 0s to 9s until you find a digit to decrement. - digits := []byte(decimal) - i := len(digits) - 1 - for ; i >= 0 && digits[i] == '0'; i-- { - digits[i] = '9' - } - if i < 0 { - // decimal is all zeros - return "" - } - if i == 0 && digits[i] == '1' && len(digits) > 1 { - digits = digits[1:] - } else { - digits[i]-- - } - return string(digits) -} - -// IsPseudoVersion reports whether v is a pseudo-version. -func IsPseudoVersion(v string) bool { - return strings.Count(v, "-") >= 2 && semver.IsValid(v) && pseudoVersionRE.MatchString(v) -} - -// IsZeroPseudoVersion returns whether v is a pseudo-version with a zero base, -// timestamp, and revision, as returned by ZeroPseudoVersion. -func IsZeroPseudoVersion(v string) bool { - return v == ZeroPseudoVersion(semver.Major(v)) -} - -// PseudoVersionTime returns the time stamp of the pseudo-version v. -// It returns an error if v is not a pseudo-version or if the time stamp -// embedded in the pseudo-version is not a valid time. -func PseudoVersionTime(v string) (time.Time, error) { - _, timestamp, _, _, err := parsePseudoVersion(v) - if err != nil { - return time.Time{}, err - } - t, err := time.Parse("20060102150405", timestamp) - if err != nil { - return time.Time{}, &InvalidVersionError{ - Version: v, - Pseudo: true, - Err: fmt.Errorf("malformed time %q", timestamp), - } - } - return t, nil -} - -// PseudoVersionRev returns the revision identifier of the pseudo-version v. -// It returns an error if v is not a pseudo-version. -func PseudoVersionRev(v string) (rev string, err error) { - _, _, rev, _, err = parsePseudoVersion(v) - return -} - -// PseudoVersionBase returns the canonical parent version, if any, upon which -// the pseudo-version v is based. -// -// If v has no parent version (that is, if it is "vX.0.0-[…]"), -// PseudoVersionBase returns the empty string and a nil error. -func PseudoVersionBase(v string) (string, error) { - base, _, _, build, err := parsePseudoVersion(v) - if err != nil { - return "", err - } - - switch pre := semver.Prerelease(base); pre { - case "": - // vX.0.0-yyyymmddhhmmss-abcdef123456 → "" - if build != "" { - // Pseudo-versions of the form vX.0.0-yyyymmddhhmmss-abcdef123456+incompatible - // are nonsensical: the "vX.0.0-" prefix implies that there is no parent tag, - // but the "+incompatible" suffix implies that the major version of - // the parent tag is not compatible with the module's import path. - // - // There are a few such entries in the index generated by proxy.golang.org, - // but we believe those entries were generated by the proxy itself. - return "", &InvalidVersionError{ - Version: v, - Pseudo: true, - Err: fmt.Errorf("lacks base version, but has build metadata %q", build), - } - } - return "", nil - - case "-0": - // vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdef123456 → vX.Y.Z - // vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdef123456+incompatible → vX.Y.Z+incompatible - base = strings.TrimSuffix(base, pre) - i := strings.LastIndexByte(base, '.') - if i < 0 { - panic("base from parsePseudoVersion missing patch number: " + base) - } - patch := decDecimal(base[i+1:]) - if patch == "" { - // vX.0.0-0 is invalid, but has been observed in the wild in the index - // generated by requests to proxy.golang.org. - // - // NOTE(bcmills): I cannot find a historical bug that accounts for - // pseudo-versions of this form, nor have I seen such versions in any - // actual go.mod files. If we find actual examples of this form and a - // reasonable theory of how they came into existence, it seems fine to - // treat them as equivalent to vX.0.0 (especially since the invalid - // pseudo-versions have lower precedence than the real ones). For now, we - // reject them. - return "", &InvalidVersionError{ - Version: v, - Pseudo: true, - Err: fmt.Errorf("version before %s would have negative patch number", base), - } - } - return base[:i+1] + patch + build, nil - - default: - // vX.Y.Z-pre.0.yyyymmddhhmmss-abcdef123456 → vX.Y.Z-pre - // vX.Y.Z-pre.0.yyyymmddhhmmss-abcdef123456+incompatible → vX.Y.Z-pre+incompatible - if !strings.HasSuffix(base, ".0") { - panic(`base from parsePseudoVersion missing ".0" before date: ` + base) - } - return strings.TrimSuffix(base, ".0") + build, nil - } -} - -var errPseudoSyntax = errors.New("syntax error") - -func parsePseudoVersion(v string) (base, timestamp, rev, build string, err error) { - if !IsPseudoVersion(v) { - return "", "", "", "", &InvalidVersionError{ - Version: v, - Pseudo: true, - Err: errPseudoSyntax, - } - } - build = semver.Build(v) - v = strings.TrimSuffix(v, build) - j := strings.LastIndex(v, "-") - v, rev = v[:j], v[j+1:] - i := strings.LastIndex(v, "-") - if j := strings.LastIndex(v, "."); j > i { - base = v[:j] // "vX.Y.Z-pre.0" or "vX.Y.(Z+1)-0" - timestamp = v[j+1:] - } else { - base = v[:i] // "vX.0.0" - timestamp = v[i+1:] - } - return base, timestamp, rev, build, nil -} diff --git a/vendor/golang.org/x/mod/semver/semver.go b/vendor/golang.org/x/mod/semver/semver.go deleted file mode 100644 index a30a22bf20f..00000000000 --- a/vendor/golang.org/x/mod/semver/semver.go +++ /dev/null @@ -1,401 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package semver implements comparison of semantic version strings. -// In this package, semantic version strings must begin with a leading "v", -// as in "v1.0.0". -// -// The general form of a semantic version string accepted by this package is -// -// vMAJOR[.MINOR[.PATCH[-PRERELEASE][+BUILD]]] -// -// where square brackets indicate optional parts of the syntax; -// MAJOR, MINOR, and PATCH are decimal integers without extra leading zeros; -// PRERELEASE and BUILD are each a series of non-empty dot-separated identifiers -// using only alphanumeric characters and hyphens; and -// all-numeric PRERELEASE identifiers must not have leading zeros. -// -// This package follows Semantic Versioning 2.0.0 (see semver.org) -// with two exceptions. First, it requires the "v" prefix. Second, it recognizes -// vMAJOR and vMAJOR.MINOR (with no prerelease or build suffixes) -// as shorthands for vMAJOR.0.0 and vMAJOR.MINOR.0. -package semver - -import "sort" - -// parsed returns the parsed form of a semantic version string. -type parsed struct { - major string - minor string - patch string - short string - prerelease string - build string -} - -// IsValid reports whether v is a valid semantic version string. -func IsValid(v string) bool { - _, ok := parse(v) - return ok -} - -// Canonical returns the canonical formatting of the semantic version v. -// It fills in any missing .MINOR or .PATCH and discards build metadata. -// Two semantic versions compare equal only if their canonical formattings -// are identical strings. -// The canonical invalid semantic version is the empty string. -func Canonical(v string) string { - p, ok := parse(v) - if !ok { - return "" - } - if p.build != "" { - return v[:len(v)-len(p.build)] - } - if p.short != "" { - return v + p.short - } - return v -} - -// Major returns the major version prefix of the semantic version v. -// For example, Major("v2.1.0") == "v2". -// If v is an invalid semantic version string, Major returns the empty string. -func Major(v string) string { - pv, ok := parse(v) - if !ok { - return "" - } - return v[:1+len(pv.major)] -} - -// MajorMinor returns the major.minor version prefix of the semantic version v. -// For example, MajorMinor("v2.1.0") == "v2.1". -// If v is an invalid semantic version string, MajorMinor returns the empty string. -func MajorMinor(v string) string { - pv, ok := parse(v) - if !ok { - return "" - } - i := 1 + len(pv.major) - if j := i + 1 + len(pv.minor); j <= len(v) && v[i] == '.' && v[i+1:j] == pv.minor { - return v[:j] - } - return v[:i] + "." + pv.minor -} - -// Prerelease returns the prerelease suffix of the semantic version v. -// For example, Prerelease("v2.1.0-pre+meta") == "-pre". -// If v is an invalid semantic version string, Prerelease returns the empty string. -func Prerelease(v string) string { - pv, ok := parse(v) - if !ok { - return "" - } - return pv.prerelease -} - -// Build returns the build suffix of the semantic version v. -// For example, Build("v2.1.0+meta") == "+meta". -// If v is an invalid semantic version string, Build returns the empty string. -func Build(v string) string { - pv, ok := parse(v) - if !ok { - return "" - } - return pv.build -} - -// Compare returns an integer comparing two versions according to -// semantic version precedence. -// The result will be 0 if v == w, -1 if v < w, or +1 if v > w. -// -// An invalid semantic version string is considered less than a valid one. -// All invalid semantic version strings compare equal to each other. -func Compare(v, w string) int { - pv, ok1 := parse(v) - pw, ok2 := parse(w) - if !ok1 && !ok2 { - return 0 - } - if !ok1 { - return -1 - } - if !ok2 { - return +1 - } - if c := compareInt(pv.major, pw.major); c != 0 { - return c - } - if c := compareInt(pv.minor, pw.minor); c != 0 { - return c - } - if c := compareInt(pv.patch, pw.patch); c != 0 { - return c - } - return comparePrerelease(pv.prerelease, pw.prerelease) -} - -// Max canonicalizes its arguments and then returns the version string -// that compares greater. -// -// Deprecated: use Compare instead. In most cases, returning a canonicalized -// version is not expected or desired. -func Max(v, w string) string { - v = Canonical(v) - w = Canonical(w) - if Compare(v, w) > 0 { - return v - } - return w -} - -// ByVersion implements sort.Interface for sorting semantic version strings. -type ByVersion []string - -func (vs ByVersion) Len() int { return len(vs) } -func (vs ByVersion) Swap(i, j int) { vs[i], vs[j] = vs[j], vs[i] } -func (vs ByVersion) Less(i, j int) bool { - cmp := Compare(vs[i], vs[j]) - if cmp != 0 { - return cmp < 0 - } - return vs[i] < vs[j] -} - -// Sort sorts a list of semantic version strings using ByVersion. -func Sort(list []string) { - sort.Sort(ByVersion(list)) -} - -func parse(v string) (p parsed, ok bool) { - if v == "" || v[0] != 'v' { - return - } - p.major, v, ok = parseInt(v[1:]) - if !ok { - return - } - if v == "" { - p.minor = "0" - p.patch = "0" - p.short = ".0.0" - return - } - if v[0] != '.' { - ok = false - return - } - p.minor, v, ok = parseInt(v[1:]) - if !ok { - return - } - if v == "" { - p.patch = "0" - p.short = ".0" - return - } - if v[0] != '.' { - ok = false - return - } - p.patch, v, ok = parseInt(v[1:]) - if !ok { - return - } - if len(v) > 0 && v[0] == '-' { - p.prerelease, v, ok = parsePrerelease(v) - if !ok { - return - } - } - if len(v) > 0 && v[0] == '+' { - p.build, v, ok = parseBuild(v) - if !ok { - return - } - } - if v != "" { - ok = false - return - } - ok = true - return -} - -func parseInt(v string) (t, rest string, ok bool) { - if v == "" { - return - } - if v[0] < '0' || '9' < v[0] { - return - } - i := 1 - for i < len(v) && '0' <= v[i] && v[i] <= '9' { - i++ - } - if v[0] == '0' && i != 1 { - return - } - return v[:i], v[i:], true -} - -func parsePrerelease(v string) (t, rest string, ok bool) { - // "A pre-release version MAY be denoted by appending a hyphen and - // a series of dot separated identifiers immediately following the patch version. - // Identifiers MUST comprise only ASCII alphanumerics and hyphen [0-9A-Za-z-]. - // Identifiers MUST NOT be empty. Numeric identifiers MUST NOT include leading zeroes." - if v == "" || v[0] != '-' { - return - } - i := 1 - start := 1 - for i < len(v) && v[i] != '+' { - if !isIdentChar(v[i]) && v[i] != '.' { - return - } - if v[i] == '.' { - if start == i || isBadNum(v[start:i]) { - return - } - start = i + 1 - } - i++ - } - if start == i || isBadNum(v[start:i]) { - return - } - return v[:i], v[i:], true -} - -func parseBuild(v string) (t, rest string, ok bool) { - if v == "" || v[0] != '+' { - return - } - i := 1 - start := 1 - for i < len(v) { - if !isIdentChar(v[i]) && v[i] != '.' { - return - } - if v[i] == '.' { - if start == i { - return - } - start = i + 1 - } - i++ - } - if start == i { - return - } - return v[:i], v[i:], true -} - -func isIdentChar(c byte) bool { - return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '-' -} - -func isBadNum(v string) bool { - i := 0 - for i < len(v) && '0' <= v[i] && v[i] <= '9' { - i++ - } - return i == len(v) && i > 1 && v[0] == '0' -} - -func isNum(v string) bool { - i := 0 - for i < len(v) && '0' <= v[i] && v[i] <= '9' { - i++ - } - return i == len(v) -} - -func compareInt(x, y string) int { - if x == y { - return 0 - } - if len(x) < len(y) { - return -1 - } - if len(x) > len(y) { - return +1 - } - if x < y { - return -1 - } else { - return +1 - } -} - -func comparePrerelease(x, y string) int { - // "When major, minor, and patch are equal, a pre-release version has - // lower precedence than a normal version. - // Example: 1.0.0-alpha < 1.0.0. - // Precedence for two pre-release versions with the same major, minor, - // and patch version MUST be determined by comparing each dot separated - // identifier from left to right until a difference is found as follows: - // identifiers consisting of only digits are compared numerically and - // identifiers with letters or hyphens are compared lexically in ASCII - // sort order. Numeric identifiers always have lower precedence than - // non-numeric identifiers. A larger set of pre-release fields has a - // higher precedence than a smaller set, if all of the preceding - // identifiers are equal. - // Example: 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < - // 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0." - if x == y { - return 0 - } - if x == "" { - return +1 - } - if y == "" { - return -1 - } - for x != "" && y != "" { - x = x[1:] // skip - or . - y = y[1:] // skip - or . - var dx, dy string - dx, x = nextIdent(x) - dy, y = nextIdent(y) - if dx != dy { - ix := isNum(dx) - iy := isNum(dy) - if ix != iy { - if ix { - return -1 - } else { - return +1 - } - } - if ix { - if len(dx) < len(dy) { - return -1 - } - if len(dx) > len(dy) { - return +1 - } - } - if dx < dy { - return -1 - } else { - return +1 - } - } - } - if x == "" { - return -1 - } else { - return +1 - } -} - -func nextIdent(x string) (dx, rest string) { - i := 0 - for i < len(x) && x[i] != '.' { - i++ - } - return x[:i], x[i:] -} diff --git a/vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go b/vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go deleted file mode 100644 index 37dc0cfdb5b..00000000000 --- a/vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package ctxhttp provides helper functions for performing context-aware HTTP requests. -package ctxhttp // import "golang.org/x/net/context/ctxhttp" - -import ( - "context" - "io" - "net/http" - "net/url" - "strings" -) - -// Do sends an HTTP request with the provided http.Client and returns -// an HTTP response. -// -// If the client is nil, http.DefaultClient is used. -// -// The provided ctx must be non-nil. If it is canceled or times out, -// ctx.Err() will be returned. -func Do(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) { - if client == nil { - client = http.DefaultClient - } - resp, err := client.Do(req.WithContext(ctx)) - // If we got an error, and the context has been canceled, - // the context's error is probably more useful. - if err != nil { - select { - case <-ctx.Done(): - err = ctx.Err() - default: - } - } - return resp, err -} - -// Get issues a GET request via the Do function. -func Get(ctx context.Context, client *http.Client, url string) (*http.Response, error) { - req, err := http.NewRequest("GET", url, nil) - if err != nil { - return nil, err - } - return Do(ctx, client, req) -} - -// Head issues a HEAD request via the Do function. -func Head(ctx context.Context, client *http.Client, url string) (*http.Response, error) { - req, err := http.NewRequest("HEAD", url, nil) - if err != nil { - return nil, err - } - return Do(ctx, client, req) -} - -// Post issues a POST request via the Do function. -func Post(ctx context.Context, client *http.Client, url string, bodyType string, body io.Reader) (*http.Response, error) { - req, err := http.NewRequest("POST", url, body) - if err != nil { - return nil, err - } - req.Header.Set("Content-Type", bodyType) - return Do(ctx, client, req) -} - -// PostForm issues a POST request via the Do function. -func PostForm(ctx context.Context, client *http.Client, url string, data url.Values) (*http.Response, error) { - return Post(ctx, client, url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode())) -} diff --git a/vendor/golang.org/x/oauth2/AUTHORS b/vendor/golang.org/x/oauth2/AUTHORS deleted file mode 100644 index 15167cd746c..00000000000 --- a/vendor/golang.org/x/oauth2/AUTHORS +++ /dev/null @@ -1,3 +0,0 @@ -# This source code refers to The Go Authors for copyright purposes. -# The master list of authors is in the main Go distribution, -# visible at http://tip.golang.org/AUTHORS. diff --git a/vendor/golang.org/x/oauth2/CONTRIBUTORS b/vendor/golang.org/x/oauth2/CONTRIBUTORS deleted file mode 100644 index 1c4577e9680..00000000000 --- a/vendor/golang.org/x/oauth2/CONTRIBUTORS +++ /dev/null @@ -1,3 +0,0 @@ -# This source code was written by the Go contributors. -# The master list of contributors is in the main Go distribution, -# visible at http://tip.golang.org/CONTRIBUTORS. diff --git a/vendor/golang.org/x/oauth2/README.md b/vendor/golang.org/x/oauth2/README.md index 1473e1296d0..781770c2046 100644 --- a/vendor/golang.org/x/oauth2/README.md +++ b/vendor/golang.org/x/oauth2/README.md @@ -19,7 +19,7 @@ See pkg.go.dev for further documentation and examples. * [pkg.go.dev/golang.org/x/oauth2](https://pkg.go.dev/golang.org/x/oauth2) * [pkg.go.dev/golang.org/x/oauth2/google](https://pkg.go.dev/golang.org/x/oauth2/google) -## Policy for new packages +## Policy for new endpoints We no longer accept new provider-specific packages in this repo if all they do is add a single endpoint variable. If you just want to add a @@ -29,8 +29,12 @@ package. ## Report Issues / Send Patches -This repository uses Gerrit for code changes. To learn how to submit changes to -this repository, see https://golang.org/doc/contribute.html. - The main issue tracker for the oauth2 repository is located at https://github.com/golang/oauth2/issues. + +This repository uses Gerrit for code changes. To learn how to submit changes to +this repository, see https://golang.org/doc/contribute.html. In particular: + +* Excluding trivial changes, all contributions should be connected to an existing issue. +* API changes must go through the [change proposal process](https://go.dev/s/proposal-process) before they can be accepted. +* The code owners are listed at [dev.golang.org/owners](https://dev.golang.org/owners#:~:text=x/oauth2). diff --git a/vendor/golang.org/x/oauth2/authhandler/authhandler.go b/vendor/golang.org/x/oauth2/authhandler/authhandler.go new file mode 100644 index 00000000000..9bc6cd7bc5e --- /dev/null +++ b/vendor/golang.org/x/oauth2/authhandler/authhandler.go @@ -0,0 +1,94 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package authhandler implements a TokenSource to support +// "three-legged OAuth 2.0" via a custom AuthorizationHandler. +package authhandler + +import ( + "context" + "errors" + + "golang.org/x/oauth2" +) + +const ( + // Parameter keys for AuthCodeURL method to support PKCE. + codeChallengeKey = "code_challenge" + codeChallengeMethodKey = "code_challenge_method" + + // Parameter key for Exchange method to support PKCE. + codeVerifierKey = "code_verifier" +) + +// PKCEParams holds parameters to support PKCE. +type PKCEParams struct { + Challenge string // The unpadded, base64-url-encoded string of the encrypted code verifier. + ChallengeMethod string // The encryption method (ex. S256). + Verifier string // The original, non-encrypted secret. +} + +// AuthorizationHandler is a 3-legged-OAuth helper that prompts +// the user for OAuth consent at the specified auth code URL +// and returns an auth code and state upon approval. +type AuthorizationHandler func(authCodeURL string) (code string, state string, err error) + +// TokenSourceWithPKCE is an enhanced version of TokenSource with PKCE support. +// +// The pkce parameter supports PKCE flow, which uses code challenge and code verifier +// to prevent CSRF attacks. A unique code challenge and code verifier should be generated +// by the caller at runtime. See https://www.oauth.com/oauth2-servers/pkce/ for more info. +func TokenSourceWithPKCE(ctx context.Context, config *oauth2.Config, state string, authHandler AuthorizationHandler, pkce *PKCEParams) oauth2.TokenSource { + return oauth2.ReuseTokenSource(nil, authHandlerSource{config: config, ctx: ctx, authHandler: authHandler, state: state, pkce: pkce}) +} + +// TokenSource returns an oauth2.TokenSource that fetches access tokens +// using 3-legged-OAuth flow. +// +// The provided context.Context is used for oauth2 Exchange operation. +// +// The provided oauth2.Config should be a full configuration containing AuthURL, +// TokenURL, and Scope. +// +// An environment-specific AuthorizationHandler is used to obtain user consent. +// +// Per the OAuth protocol, a unique "state" string should be specified here. +// This token source will verify that the "state" is identical in the request +// and response before exchanging the auth code for OAuth token to prevent CSRF +// attacks. +func TokenSource(ctx context.Context, config *oauth2.Config, state string, authHandler AuthorizationHandler) oauth2.TokenSource { + return TokenSourceWithPKCE(ctx, config, state, authHandler, nil) +} + +type authHandlerSource struct { + ctx context.Context + config *oauth2.Config + authHandler AuthorizationHandler + state string + pkce *PKCEParams +} + +func (source authHandlerSource) Token() (*oauth2.Token, error) { + // Step 1: Obtain auth code. + var authCodeUrlOptions []oauth2.AuthCodeOption + if source.pkce != nil && source.pkce.Challenge != "" && source.pkce.ChallengeMethod != "" { + authCodeUrlOptions = []oauth2.AuthCodeOption{oauth2.SetAuthURLParam(codeChallengeKey, source.pkce.Challenge), + oauth2.SetAuthURLParam(codeChallengeMethodKey, source.pkce.ChallengeMethod)} + } + url := source.config.AuthCodeURL(source.state, authCodeUrlOptions...) + code, state, err := source.authHandler(url) + if err != nil { + return nil, err + } + if state != source.state { + return nil, errors.New("state mismatch in 3-legged-OAuth flow") + } + + // Step 2: Exchange auth code for access token. + var exchangeOptions []oauth2.AuthCodeOption + if source.pkce != nil && source.pkce.Verifier != "" { + exchangeOptions = []oauth2.AuthCodeOption{oauth2.SetAuthURLParam(codeVerifierKey, source.pkce.Verifier)} + } + return source.config.Exchange(source.ctx, code, exchangeOptions...) +} diff --git a/vendor/golang.org/x/oauth2/google/appengine_gen1.go b/vendor/golang.org/x/oauth2/google/appengine_gen1.go index 83dacac320a..16c6c6b90ce 100644 --- a/vendor/golang.org/x/oauth2/google/appengine_gen1.go +++ b/vendor/golang.org/x/oauth2/google/appengine_gen1.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build appengine // +build appengine // This file applies to App Engine first generation runtimes (<= Go 1.9). diff --git a/vendor/golang.org/x/oauth2/google/appengine_gen2_flex.go b/vendor/golang.org/x/oauth2/google/appengine_gen2_flex.go index 04c2c2216af..a7e27b3d299 100644 --- a/vendor/golang.org/x/oauth2/google/appengine_gen2_flex.go +++ b/vendor/golang.org/x/oauth2/google/appengine_gen2_flex.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !appengine // +build !appengine // This file applies to App Engine second generation runtimes (>= Go 1.11) and App Engine flexible. diff --git a/vendor/golang.org/x/oauth2/google/default.go b/vendor/golang.org/x/oauth2/google/default.go index ad2c09236c5..b3e8783cc59 100644 --- a/vendor/golang.org/x/oauth2/google/default.go +++ b/vendor/golang.org/x/oauth2/google/default.go @@ -13,14 +13,22 @@ import ( "os" "path/filepath" "runtime" + "time" "cloud.google.com/go/compute/metadata" "golang.org/x/oauth2" + "golang.org/x/oauth2/authhandler" ) +const adcSetupURL = "https://cloud.google.com/docs/authentication/external/set-up-adc" + // Credentials holds Google credentials, including "Application Default Credentials". // For more details, see: // https://developers.google.com/accounts/docs/application-default-credentials +// Credentials from external accounts (workload identity federation) are used to +// identify a particular application from an on-prem or non-Google Cloud platform +// including Amazon Web Services (AWS), Microsoft Azure or any identity provider +// that supports OpenID Connect (OIDC). type Credentials struct { ProjectID string // may be empty TokenSource oauth2.TokenSource @@ -37,6 +45,47 @@ type Credentials struct { // Deprecated: use Credentials instead. type DefaultCredentials = Credentials +// CredentialsParams holds user supplied parameters that are used together +// with a credentials file for building a Credentials object. +type CredentialsParams struct { + // Scopes is the list OAuth scopes. Required. + // Example: https://www.googleapis.com/auth/cloud-platform + Scopes []string + + // Subject is the user email used for domain wide delegation (see + // https://developers.google.com/identity/protocols/oauth2/service-account#delegatingauthority). + // Optional. + Subject string + + // AuthHandler is the AuthorizationHandler used for 3-legged OAuth flow. Required for 3LO flow. + AuthHandler authhandler.AuthorizationHandler + + // State is a unique string used with AuthHandler. Required for 3LO flow. + State string + + // PKCE is used to support PKCE flow. Optional for 3LO flow. + PKCE *authhandler.PKCEParams + + // The OAuth2 TokenURL default override. This value overrides the default TokenURL, + // unless explicitly specified by the credentials config file. Optional. + TokenURL string + + // EarlyTokenRefresh is the amount of time before a token expires that a new + // token will be preemptively fetched. If unset the default value is 10 + // seconds. + // + // Note: This option is currently only respected when using credentials + // fetched from the GCE metadata server. + EarlyTokenRefresh time.Duration +} + +func (params CredentialsParams) deepCopy() CredentialsParams { + paramsCopy := params + paramsCopy.Scopes = make([]string, len(params.Scopes)) + copy(paramsCopy.Scopes, params.Scopes) + return paramsCopy +} + // DefaultClient returns an HTTP Client that uses the // DefaultTokenSource to obtain authentication credentials. func DefaultClient(ctx context.Context, scope ...string) (*http.Client, error) { @@ -58,26 +107,33 @@ func DefaultTokenSource(ctx context.Context, scope ...string) (oauth2.TokenSourc return creds.TokenSource, nil } -// FindDefaultCredentials searches for "Application Default Credentials". +// FindDefaultCredentialsWithParams searches for "Application Default Credentials". // // It looks for credentials in the following places, // preferring the first location found: // -// 1. A JSON file whose path is specified by the -// GOOGLE_APPLICATION_CREDENTIALS environment variable. -// 2. A JSON file in a location known to the gcloud command-line tool. -// On Windows, this is %APPDATA%/gcloud/application_default_credentials.json. -// On other systems, $HOME/.config/gcloud/application_default_credentials.json. -// 3. On Google App Engine standard first generation runtimes (<= Go 1.9) it uses -// the appengine.AccessToken function. -// 4. On Google Compute Engine, Google App Engine standard second generation runtimes -// (>= Go 1.11), and Google App Engine flexible environment, it fetches -// credentials from the metadata server. -func FindDefaultCredentials(ctx context.Context, scopes ...string) (*Credentials, error) { +// 1. A JSON file whose path is specified by the +// GOOGLE_APPLICATION_CREDENTIALS environment variable. +// For workload identity federation, refer to +// https://cloud.google.com/iam/docs/how-to#using-workload-identity-federation on +// how to generate the JSON configuration file for on-prem/non-Google cloud +// platforms. +// 2. A JSON file in a location known to the gcloud command-line tool. +// On Windows, this is %APPDATA%/gcloud/application_default_credentials.json. +// On other systems, $HOME/.config/gcloud/application_default_credentials.json. +// 3. On Google App Engine standard first generation runtimes (<= Go 1.9) it uses +// the appengine.AccessToken function. +// 4. On Google Compute Engine, Google App Engine standard second generation runtimes +// (>= Go 1.11), and Google App Engine flexible environment, it fetches +// credentials from the metadata server. +func FindDefaultCredentialsWithParams(ctx context.Context, params CredentialsParams) (*Credentials, error) { + // Make defensive copy of the slices in params. + params = params.deepCopy() + // First, try the environment variable. const envVar = "GOOGLE_APPLICATION_CREDENTIALS" if filename := os.Getenv(envVar); filename != "" { - creds, err := readCredentialsFile(ctx, filename, scopes) + creds, err := readCredentialsFile(ctx, filename, params) if err != nil { return nil, fmt.Errorf("google: error getting credentials using %v environment variable: %v", envVar, err) } @@ -86,7 +142,7 @@ func FindDefaultCredentials(ctx context.Context, scopes ...string) (*Credentials // Second, try a well-known file. filename := wellKnownFile() - if creds, err := readCredentialsFile(ctx, filename, scopes); err == nil { + if creds, err := readCredentialsFile(ctx, filename, params); err == nil { return creds, nil } else if !os.IsNotExist(err) { return nil, fmt.Errorf("google: error getting credentials using well-known file (%v): %v", filename, err) @@ -96,9 +152,9 @@ func FindDefaultCredentials(ctx context.Context, scopes ...string) (*Credentials // use those credentials. App Engine standard second generation runtimes (>= Go 1.11) // and App Engine flexible use ComputeTokenSource and the metadata server. if appengineTokenFunc != nil { - return &DefaultCredentials{ + return &Credentials{ ProjectID: appengineAppIDFunc(ctx), - TokenSource: AppEngineTokenSource(ctx, scopes...), + TokenSource: AppEngineTokenSource(ctx, params.Scopes...), }, nil } @@ -106,37 +162,66 @@ func FindDefaultCredentials(ctx context.Context, scopes ...string) (*Credentials // or App Engine flexible, use the metadata server. if metadata.OnGCE() { id, _ := metadata.ProjectID() - return &DefaultCredentials{ + return &Credentials{ ProjectID: id, - TokenSource: ComputeTokenSource("", scopes...), + TokenSource: computeTokenSource("", params.EarlyTokenRefresh, params.Scopes...), }, nil } // None are found; return helpful error. - const url = "https://developers.google.com/accounts/docs/application-default-credentials" - return nil, fmt.Errorf("google: could not find default credentials. See %v for more information.", url) + return nil, fmt.Errorf("google: could not find default credentials. See %v for more information", adcSetupURL) } -// CredentialsFromJSON obtains Google credentials from a JSON value. The JSON can -// represent either a Google Developers Console client_credentials.json file (as in -// ConfigFromJSON) or a Google Developers service account key file (as in -// JWTConfigFromJSON). -func CredentialsFromJSON(ctx context.Context, jsonData []byte, scopes ...string) (*Credentials, error) { +// FindDefaultCredentials invokes FindDefaultCredentialsWithParams with the specified scopes. +func FindDefaultCredentials(ctx context.Context, scopes ...string) (*Credentials, error) { + var params CredentialsParams + params.Scopes = scopes + return FindDefaultCredentialsWithParams(ctx, params) +} + +// CredentialsFromJSONWithParams obtains Google credentials from a JSON value. The JSON can +// represent either a Google Developers Console client_credentials.json file (as in ConfigFromJSON), +// a Google Developers service account key file, a gcloud user credentials file (a.k.a. refresh +// token JSON), or the JSON configuration file for workload identity federation in non-Google cloud +// platforms (see https://cloud.google.com/iam/docs/how-to#using-workload-identity-federation). +func CredentialsFromJSONWithParams(ctx context.Context, jsonData []byte, params CredentialsParams) (*Credentials, error) { + // Make defensive copy of the slices in params. + params = params.deepCopy() + + // First, attempt to parse jsonData as a Google Developers Console client_credentials.json. + config, _ := ConfigFromJSON(jsonData, params.Scopes...) + if config != nil { + return &Credentials{ + ProjectID: "", + TokenSource: authhandler.TokenSourceWithPKCE(ctx, config, params.State, params.AuthHandler, params.PKCE), + JSON: jsonData, + }, nil + } + + // Otherwise, parse jsonData as one of the other supported credentials files. var f credentialsFile if err := json.Unmarshal(jsonData, &f); err != nil { return nil, err } - ts, err := f.tokenSource(ctx, append([]string(nil), scopes...)) + ts, err := f.tokenSource(ctx, params) if err != nil { return nil, err } - return &DefaultCredentials{ + ts = newErrWrappingTokenSource(ts) + return &Credentials{ ProjectID: f.ProjectID, TokenSource: ts, JSON: jsonData, }, nil } +// CredentialsFromJSON invokes CredentialsFromJSONWithParams with the specified scopes. +func CredentialsFromJSON(ctx context.Context, jsonData []byte, scopes ...string) (*Credentials, error) { + var params CredentialsParams + params.Scopes = scopes + return CredentialsFromJSONWithParams(ctx, jsonData, params) +} + func wellKnownFile() string { const f = "application_default_credentials.json" if runtime.GOOS == "windows" { @@ -145,10 +230,10 @@ func wellKnownFile() string { return filepath.Join(guessUnixHomeDir(), ".config", "gcloud", f) } -func readCredentialsFile(ctx context.Context, filename string, scopes []string) (*DefaultCredentials, error) { +func readCredentialsFile(ctx context.Context, filename string, params CredentialsParams) (*Credentials, error) { b, err := ioutil.ReadFile(filename) if err != nil { return nil, err } - return CredentialsFromJSON(ctx, b, scopes...) + return CredentialsFromJSONWithParams(ctx, b, params) } diff --git a/vendor/golang.org/x/oauth2/google/doc.go b/vendor/golang.org/x/oauth2/google/doc.go index 73be629033d..ca717634a3f 100644 --- a/vendor/golang.org/x/oauth2/google/doc.go +++ b/vendor/golang.org/x/oauth2/google/doc.go @@ -4,23 +4,109 @@ // Package google provides support for making OAuth2 authorized and authenticated // HTTP requests to Google APIs. It supports the Web server flow, client-side -// credentials, service accounts, Google Compute Engine service accounts, and Google -// App Engine service accounts. +// credentials, service accounts, Google Compute Engine service accounts, +// Google App Engine service accounts and workload identity federation +// from non-Google cloud platforms. // // A brief overview of the package follows. For more information, please read // https://developers.google.com/accounts/docs/OAuth2 // and // https://developers.google.com/accounts/docs/application-default-credentials. +// For more information on using workload identity federation, refer to +// https://cloud.google.com/iam/docs/how-to#using-workload-identity-federation. // -// OAuth2 Configs +// # OAuth2 Configs // // Two functions in this package return golang.org/x/oauth2.Config values from Google credential // data. Google supports two JSON formats for OAuth2 credentials: one is handled by ConfigFromJSON, // the other by JWTConfigFromJSON. The returned Config can be used to obtain a TokenSource or // create an http.Client. // +// # Workload Identity Federation // -// Credentials +// Using workload identity federation, your application can access Google Cloud +// resources from Amazon Web Services (AWS), Microsoft Azure or any identity +// provider that supports OpenID Connect (OIDC) or SAML 2.0. +// Traditionally, applications running outside Google Cloud have used service +// account keys to access Google Cloud resources. Using identity federation, +// you can allow your workload to impersonate a service account. +// This lets you access Google Cloud resources directly, eliminating the +// maintenance and security burden associated with service account keys. +// +// Follow the detailed instructions on how to configure Workload Identity Federation +// in various platforms: +// +// Amazon Web Services (AWS): https://cloud.google.com/iam/docs/workload-identity-federation-with-other-clouds#aws +// Microsoft Azure: https://cloud.google.com/iam/docs/workload-identity-federation-with-other-clouds#azure +// OIDC identity provider: https://cloud.google.com/iam/docs/workload-identity-federation-with-other-providers#oidc +// SAML 2.0 identity provider: https://cloud.google.com/iam/docs/workload-identity-federation-with-other-providers#saml +// +// For OIDC and SAML providers, the library can retrieve tokens in three ways: +// from a local file location (file-sourced credentials), from a server +// (URL-sourced credentials), or from a local executable (executable-sourced +// credentials). +// For file-sourced credentials, a background process needs to be continuously +// refreshing the file location with a new OIDC/SAML token prior to expiration. +// For tokens with one hour lifetimes, the token needs to be updated in the file +// every hour. The token can be stored directly as plain text or in JSON format. +// For URL-sourced credentials, a local server needs to host a GET endpoint to +// return the OIDC/SAML token. The response can be in plain text or JSON. +// Additional required request headers can also be specified. +// For executable-sourced credentials, an application needs to be available to +// output the OIDC/SAML token and other information in a JSON format. +// For more information on how these work (and how to implement +// executable-sourced credentials), please check out: +// https://cloud.google.com/iam/docs/workload-identity-federation-with-other-providers#create_a_credential_configuration +// +// Note that this library does not perform any validation on the token_url, token_info_url, +// or service_account_impersonation_url fields of the credential configuration. +// It is not recommended to use a credential configuration that you did not generate with +// the gcloud CLI unless you verify that the URL fields point to a googleapis.com domain. +// +// # Workforce Identity Federation +// +// Workforce identity federation lets you use an external identity provider (IdP) to +// authenticate and authorize a workforce—a group of users, such as employees, partners, +// and contractors—using IAM, so that the users can access Google Cloud services. +// Workforce identity federation extends Google Cloud's identity capabilities to support +// syncless, attribute-based single sign on. +// +// With workforce identity federation, your workforce can access Google Cloud resources +// using an external identity provider (IdP) that supports OpenID Connect (OIDC) or +// SAML 2.0 such as Azure Active Directory (Azure AD), Active Directory Federation +// Services (AD FS), Okta, and others. +// +// Follow the detailed instructions on how to configure Workload Identity Federation +// in various platforms: +// +// Azure AD: https://cloud.google.com/iam/docs/workforce-sign-in-azure-ad +// Okta: https://cloud.google.com/iam/docs/workforce-sign-in-okta +// OIDC identity provider: https://cloud.google.com/iam/docs/configuring-workforce-identity-federation#oidc +// SAML 2.0 identity provider: https://cloud.google.com/iam/docs/configuring-workforce-identity-federation#saml +// +// For workforce identity federation, the library can retrieve tokens in three ways: +// from a local file location (file-sourced credentials), from a server +// (URL-sourced credentials), or from a local executable (executable-sourced +// credentials). +// For file-sourced credentials, a background process needs to be continuously +// refreshing the file location with a new OIDC/SAML token prior to expiration. +// For tokens with one hour lifetimes, the token needs to be updated in the file +// every hour. The token can be stored directly as plain text or in JSON format. +// For URL-sourced credentials, a local server needs to host a GET endpoint to +// return the OIDC/SAML token. The response can be in plain text or JSON. +// Additional required request headers can also be specified. +// For executable-sourced credentials, an application needs to be available to +// output the OIDC/SAML token and other information in a JSON format. +// For more information on how these work (and how to implement +// executable-sourced credentials), please check out: +// https://cloud.google.com/iam/docs/workforce-obtaining-short-lived-credentials#generate_a_configuration_file_for_non-interactive_sign-in +// +// Note that this library does not perform any validation on the token_url, token_info_url, +// or service_account_impersonation_url fields of the credential configuration. +// It is not recommended to use a credential configuration that you did not generate with +// the gcloud CLI unless you verify that the URL fields point to a googleapis.com domain. +// +// # Credentials // // The Credentials type represents Google credentials, including Application Default // Credentials. @@ -29,6 +115,13 @@ // FindDefaultCredentials looks in some well-known places for a credentials file, and // will call AppEngineTokenSource or ComputeTokenSource as needed. // +// Application Default Credentials also support workload identity federation to +// access Google Cloud resources from non-Google Cloud platforms including Amazon +// Web Services (AWS), Microsoft Azure or any identity provider that supports +// OpenID Connect (OIDC). Workload identity federation is recommended for +// non-Google Cloud environments as it avoids the need to download, manage and +// store service account private keys locally. +// // DefaultClient and DefaultTokenSource are convenience methods. They first call FindDefaultCredentials, // then use the credentials to construct an http.Client or an oauth2.TokenSource. // diff --git a/vendor/golang.org/x/oauth2/google/error.go b/vendor/golang.org/x/oauth2/google/error.go new file mode 100644 index 00000000000..d84dd004731 --- /dev/null +++ b/vendor/golang.org/x/oauth2/google/error.go @@ -0,0 +1,64 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package google + +import ( + "errors" + + "golang.org/x/oauth2" +) + +// AuthenticationError indicates there was an error in the authentication flow. +// +// Use (*AuthenticationError).Temporary to check if the error can be retried. +type AuthenticationError struct { + err *oauth2.RetrieveError +} + +func newAuthenticationError(err error) error { + re := &oauth2.RetrieveError{} + if !errors.As(err, &re) { + return err + } + return &AuthenticationError{ + err: re, + } +} + +// Temporary indicates that the network error has one of the following status codes and may be retried: 500, 503, 408, or 429. +func (e *AuthenticationError) Temporary() bool { + if e.err.Response == nil { + return false + } + sc := e.err.Response.StatusCode + return sc == 500 || sc == 503 || sc == 408 || sc == 429 +} + +func (e *AuthenticationError) Error() string { + return e.err.Error() +} + +func (e *AuthenticationError) Unwrap() error { + return e.err +} + +type errWrappingTokenSource struct { + src oauth2.TokenSource +} + +func newErrWrappingTokenSource(ts oauth2.TokenSource) oauth2.TokenSource { + return &errWrappingTokenSource{src: ts} +} + +// Token returns the current token if it's still valid, else will +// refresh the current token (using r.Context for HTTP client +// information) and return the new one. +func (s *errWrappingTokenSource) Token() (*oauth2.Token, error) { + t, err := s.src.Token() + if err != nil { + return nil, newAuthenticationError(err) + } + return t, nil +} diff --git a/vendor/golang.org/x/oauth2/google/google.go b/vendor/golang.org/x/oauth2/google/google.go index 81de32b360b..cc1223889e2 100644 --- a/vendor/golang.org/x/oauth2/google/google.go +++ b/vendor/golang.org/x/oauth2/google/google.go @@ -15,16 +15,20 @@ import ( "cloud.google.com/go/compute/metadata" "golang.org/x/oauth2" + "golang.org/x/oauth2/google/internal/externalaccount" "golang.org/x/oauth2/jwt" ) -// Endpoint is Google's OAuth 2.0 endpoint. +// Endpoint is Google's OAuth 2.0 default endpoint. var Endpoint = oauth2.Endpoint{ AuthURL: "https://accounts.google.com/o/oauth2/auth", TokenURL: "https://oauth2.googleapis.com/token", AuthStyle: oauth2.AuthStyleInParams, } +// MTLSTokenURL is Google's OAuth 2.0 default mTLS endpoint. +const MTLSTokenURL = "https://oauth2.mtls.googleapis.com/token" + // JWTTokenURL is Google's OAuth 2.0 token URL to use with the JWT flow. const JWTTokenURL = "https://oauth2.googleapis.com/token" @@ -86,23 +90,26 @@ func JWTConfigFromJSON(jsonKey []byte, scope ...string) (*jwt.Config, error) { return nil, fmt.Errorf("google: read JWT from JSON credentials: 'type' field is %q (expected %q)", f.Type, serviceAccountKey) } scope = append([]string(nil), scope...) // copy - return f.jwtConfig(scope), nil + return f.jwtConfig(scope, ""), nil } // JSON key file types. const ( - serviceAccountKey = "service_account" - userCredentialsKey = "authorized_user" + serviceAccountKey = "service_account" + userCredentialsKey = "authorized_user" + externalAccountKey = "external_account" + impersonatedServiceAccount = "impersonated_service_account" ) // credentialsFile is the unmarshalled representation of a credentials file. type credentialsFile struct { - Type string `json:"type"` // serviceAccountKey or userCredentialsKey + Type string `json:"type"` // Service Account fields ClientEmail string `json:"client_email"` PrivateKeyID string `json:"private_key_id"` PrivateKey string `json:"private_key"` + AuthURL string `json:"auth_uri"` TokenURL string `json:"token_uri"` ProjectID string `json:"project_id"` @@ -111,15 +118,36 @@ type credentialsFile struct { ClientSecret string `json:"client_secret"` ClientID string `json:"client_id"` RefreshToken string `json:"refresh_token"` + + // External Account fields + Audience string `json:"audience"` + SubjectTokenType string `json:"subject_token_type"` + TokenURLExternal string `json:"token_url"` + TokenInfoURL string `json:"token_info_url"` + ServiceAccountImpersonationURL string `json:"service_account_impersonation_url"` + ServiceAccountImpersonation serviceAccountImpersonationInfo `json:"service_account_impersonation"` + Delegates []string `json:"delegates"` + CredentialSource externalaccount.CredentialSource `json:"credential_source"` + QuotaProjectID string `json:"quota_project_id"` + WorkforcePoolUserProject string `json:"workforce_pool_user_project"` + + // Service account impersonation + SourceCredentials *credentialsFile `json:"source_credentials"` } -func (f *credentialsFile) jwtConfig(scopes []string) *jwt.Config { +type serviceAccountImpersonationInfo struct { + TokenLifetimeSeconds int `json:"token_lifetime_seconds"` +} + +func (f *credentialsFile) jwtConfig(scopes []string, subject string) *jwt.Config { cfg := &jwt.Config{ Email: f.ClientEmail, PrivateKey: []byte(f.PrivateKey), PrivateKeyID: f.PrivateKeyID, Scopes: scopes, TokenURL: f.TokenURL, + Subject: subject, // This is the user email to impersonate + Audience: f.Audience, } if cfg.TokenURL == "" { cfg.TokenURL = JWTTokenURL @@ -127,20 +155,67 @@ func (f *credentialsFile) jwtConfig(scopes []string) *jwt.Config { return cfg } -func (f *credentialsFile) tokenSource(ctx context.Context, scopes []string) (oauth2.TokenSource, error) { +func (f *credentialsFile) tokenSource(ctx context.Context, params CredentialsParams) (oauth2.TokenSource, error) { switch f.Type { case serviceAccountKey: - cfg := f.jwtConfig(scopes) + cfg := f.jwtConfig(params.Scopes, params.Subject) return cfg.TokenSource(ctx), nil case userCredentialsKey: cfg := &oauth2.Config{ ClientID: f.ClientID, ClientSecret: f.ClientSecret, - Scopes: scopes, - Endpoint: Endpoint, + Scopes: params.Scopes, + Endpoint: oauth2.Endpoint{ + AuthURL: f.AuthURL, + TokenURL: f.TokenURL, + AuthStyle: oauth2.AuthStyleInParams, + }, + } + if cfg.Endpoint.AuthURL == "" { + cfg.Endpoint.AuthURL = Endpoint.AuthURL + } + if cfg.Endpoint.TokenURL == "" { + if params.TokenURL != "" { + cfg.Endpoint.TokenURL = params.TokenURL + } else { + cfg.Endpoint.TokenURL = Endpoint.TokenURL + } } tok := &oauth2.Token{RefreshToken: f.RefreshToken} return cfg.TokenSource(ctx, tok), nil + case externalAccountKey: + cfg := &externalaccount.Config{ + Audience: f.Audience, + SubjectTokenType: f.SubjectTokenType, + TokenURL: f.TokenURLExternal, + TokenInfoURL: f.TokenInfoURL, + ServiceAccountImpersonationURL: f.ServiceAccountImpersonationURL, + ServiceAccountImpersonationLifetimeSeconds: f.ServiceAccountImpersonation.TokenLifetimeSeconds, + ClientSecret: f.ClientSecret, + ClientID: f.ClientID, + CredentialSource: f.CredentialSource, + QuotaProjectID: f.QuotaProjectID, + Scopes: params.Scopes, + WorkforcePoolUserProject: f.WorkforcePoolUserProject, + } + return cfg.TokenSource(ctx) + case impersonatedServiceAccount: + if f.ServiceAccountImpersonationURL == "" || f.SourceCredentials == nil { + return nil, errors.New("missing 'source_credentials' field or 'service_account_impersonation_url' in credentials") + } + + ts, err := f.SourceCredentials.tokenSource(ctx, params) + if err != nil { + return nil, err + } + imp := externalaccount.ImpersonateTokenSource{ + Ctx: ctx, + URL: f.ServiceAccountImpersonationURL, + Scopes: params.Scopes, + Ts: ts, + Delegates: f.Delegates, + } + return oauth2.ReuseTokenSource(nil, imp), nil case "": return nil, errors.New("missing 'type' field in credentials") default: @@ -156,7 +231,11 @@ func (f *credentialsFile) tokenSource(ctx context.Context, scopes []string) (oau // Further information about retrieving access tokens from the GCE metadata // server can be found at https://cloud.google.com/compute/docs/authentication. func ComputeTokenSource(account string, scope ...string) oauth2.TokenSource { - return oauth2.ReuseTokenSource(nil, computeSource{account: account, scopes: scope}) + return computeTokenSource(account, 0, scope...) +} + +func computeTokenSource(account string, earlyExpiry time.Duration, scope ...string) oauth2.TokenSource { + return oauth2.ReuseTokenSourceWithExpiry(nil, computeSource{account: account, scopes: scope}, earlyExpiry) } type computeSource struct { diff --git a/vendor/golang.org/x/oauth2/google/internal/externalaccount/aws.go b/vendor/golang.org/x/oauth2/google/internal/externalaccount/aws.go new file mode 100644 index 00000000000..2bf3202b290 --- /dev/null +++ b/vendor/golang.org/x/oauth2/google/internal/externalaccount/aws.go @@ -0,0 +1,595 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package externalaccount + +import ( + "bytes" + "context" + "crypto/hmac" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "io" + "io/ioutil" + "net/http" + "net/url" + "os" + "path" + "sort" + "strings" + "time" + + "golang.org/x/oauth2" +) + +type awsSecurityCredentials struct { + AccessKeyID string `json:"AccessKeyID"` + SecretAccessKey string `json:"SecretAccessKey"` + SecurityToken string `json:"Token"` +} + +// awsRequestSigner is a utility class to sign http requests using a AWS V4 signature. +type awsRequestSigner struct { + RegionName string + AwsSecurityCredentials awsSecurityCredentials +} + +// getenv aliases os.Getenv for testing +var getenv = os.Getenv + +const ( + // AWS Signature Version 4 signing algorithm identifier. + awsAlgorithm = "AWS4-HMAC-SHA256" + + // The termination string for the AWS credential scope value as defined in + // https://docs.aws.amazon.com/general/latest/gr/sigv4-create-string-to-sign.html + awsRequestType = "aws4_request" + + // The AWS authorization header name for the security session token if available. + awsSecurityTokenHeader = "x-amz-security-token" + + // The name of the header containing the session token for metadata endpoint calls + awsIMDSv2SessionTokenHeader = "X-aws-ec2-metadata-token" + + awsIMDSv2SessionTtlHeader = "X-aws-ec2-metadata-token-ttl-seconds" + + awsIMDSv2SessionTtl = "300" + + // The AWS authorization header name for the auto-generated date. + awsDateHeader = "x-amz-date" + + // Supported AWS configuration environment variables. + awsAccessKeyId = "AWS_ACCESS_KEY_ID" + awsDefaultRegion = "AWS_DEFAULT_REGION" + awsRegion = "AWS_REGION" + awsSecretAccessKey = "AWS_SECRET_ACCESS_KEY" + awsSessionToken = "AWS_SESSION_TOKEN" + + awsTimeFormatLong = "20060102T150405Z" + awsTimeFormatShort = "20060102" +) + +func getSha256(input []byte) (string, error) { + hash := sha256.New() + if _, err := hash.Write(input); err != nil { + return "", err + } + return hex.EncodeToString(hash.Sum(nil)), nil +} + +func getHmacSha256(key, input []byte) ([]byte, error) { + hash := hmac.New(sha256.New, key) + if _, err := hash.Write(input); err != nil { + return nil, err + } + return hash.Sum(nil), nil +} + +func cloneRequest(r *http.Request) *http.Request { + r2 := new(http.Request) + *r2 = *r + if r.Header != nil { + r2.Header = make(http.Header, len(r.Header)) + + // Find total number of values. + headerCount := 0 + for _, headerValues := range r.Header { + headerCount += len(headerValues) + } + copiedHeaders := make([]string, headerCount) // shared backing array for headers' values + + for headerKey, headerValues := range r.Header { + headerCount = copy(copiedHeaders, headerValues) + r2.Header[headerKey] = copiedHeaders[:headerCount:headerCount] + copiedHeaders = copiedHeaders[headerCount:] + } + } + return r2 +} + +func canonicalPath(req *http.Request) string { + result := req.URL.EscapedPath() + if result == "" { + return "/" + } + return path.Clean(result) +} + +func canonicalQuery(req *http.Request) string { + queryValues := req.URL.Query() + for queryKey := range queryValues { + sort.Strings(queryValues[queryKey]) + } + return queryValues.Encode() +} + +func canonicalHeaders(req *http.Request) (string, string) { + // Header keys need to be sorted alphabetically. + var headers []string + lowerCaseHeaders := make(http.Header) + for k, v := range req.Header { + k := strings.ToLower(k) + if _, ok := lowerCaseHeaders[k]; ok { + // include additional values + lowerCaseHeaders[k] = append(lowerCaseHeaders[k], v...) + } else { + headers = append(headers, k) + lowerCaseHeaders[k] = v + } + } + sort.Strings(headers) + + var fullHeaders bytes.Buffer + for _, header := range headers { + headerValue := strings.Join(lowerCaseHeaders[header], ",") + fullHeaders.WriteString(header) + fullHeaders.WriteRune(':') + fullHeaders.WriteString(headerValue) + fullHeaders.WriteRune('\n') + } + + return strings.Join(headers, ";"), fullHeaders.String() +} + +func requestDataHash(req *http.Request) (string, error) { + var requestData []byte + if req.Body != nil { + requestBody, err := req.GetBody() + if err != nil { + return "", err + } + defer requestBody.Close() + + requestData, err = ioutil.ReadAll(io.LimitReader(requestBody, 1<<20)) + if err != nil { + return "", err + } + } + + return getSha256(requestData) +} + +func requestHost(req *http.Request) string { + if req.Host != "" { + return req.Host + } + return req.URL.Host +} + +func canonicalRequest(req *http.Request, canonicalHeaderColumns, canonicalHeaderData string) (string, error) { + dataHash, err := requestDataHash(req) + if err != nil { + return "", err + } + + return fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s", req.Method, canonicalPath(req), canonicalQuery(req), canonicalHeaderData, canonicalHeaderColumns, dataHash), nil +} + +// SignRequest adds the appropriate headers to an http.Request +// or returns an error if something prevented this. +func (rs *awsRequestSigner) SignRequest(req *http.Request) error { + signedRequest := cloneRequest(req) + timestamp := now() + + signedRequest.Header.Add("host", requestHost(req)) + + if rs.AwsSecurityCredentials.SecurityToken != "" { + signedRequest.Header.Add(awsSecurityTokenHeader, rs.AwsSecurityCredentials.SecurityToken) + } + + if signedRequest.Header.Get("date") == "" { + signedRequest.Header.Add(awsDateHeader, timestamp.Format(awsTimeFormatLong)) + } + + authorizationCode, err := rs.generateAuthentication(signedRequest, timestamp) + if err != nil { + return err + } + signedRequest.Header.Set("Authorization", authorizationCode) + + req.Header = signedRequest.Header + return nil +} + +func (rs *awsRequestSigner) generateAuthentication(req *http.Request, timestamp time.Time) (string, error) { + canonicalHeaderColumns, canonicalHeaderData := canonicalHeaders(req) + + dateStamp := timestamp.Format(awsTimeFormatShort) + serviceName := "" + if splitHost := strings.Split(requestHost(req), "."); len(splitHost) > 0 { + serviceName = splitHost[0] + } + + credentialScope := fmt.Sprintf("%s/%s/%s/%s", dateStamp, rs.RegionName, serviceName, awsRequestType) + + requestString, err := canonicalRequest(req, canonicalHeaderColumns, canonicalHeaderData) + if err != nil { + return "", err + } + requestHash, err := getSha256([]byte(requestString)) + if err != nil { + return "", err + } + + stringToSign := fmt.Sprintf("%s\n%s\n%s\n%s", awsAlgorithm, timestamp.Format(awsTimeFormatLong), credentialScope, requestHash) + + signingKey := []byte("AWS4" + rs.AwsSecurityCredentials.SecretAccessKey) + for _, signingInput := range []string{ + dateStamp, rs.RegionName, serviceName, awsRequestType, stringToSign, + } { + signingKey, err = getHmacSha256(signingKey, []byte(signingInput)) + if err != nil { + return "", err + } + } + + return fmt.Sprintf("%s Credential=%s/%s, SignedHeaders=%s, Signature=%s", awsAlgorithm, rs.AwsSecurityCredentials.AccessKeyID, credentialScope, canonicalHeaderColumns, hex.EncodeToString(signingKey)), nil +} + +type awsCredentialSource struct { + EnvironmentID string + RegionURL string + RegionalCredVerificationURL string + CredVerificationURL string + IMDSv2SessionTokenURL string + TargetResource string + requestSigner *awsRequestSigner + region string + ctx context.Context + client *http.Client +} + +type awsRequestHeader struct { + Key string `json:"key"` + Value string `json:"value"` +} + +type awsRequest struct { + URL string `json:"url"` + Method string `json:"method"` + Headers []awsRequestHeader `json:"headers"` +} + +func (cs awsCredentialSource) validateMetadataServers() error { + if err := cs.validateMetadataServer(cs.RegionURL, "region_url"); err != nil { + return err + } + if err := cs.validateMetadataServer(cs.CredVerificationURL, "url"); err != nil { + return err + } + return cs.validateMetadataServer(cs.IMDSv2SessionTokenURL, "imdsv2_session_token_url") +} + +var validHostnames []string = []string{"169.254.169.254", "fd00:ec2::254"} + +func (cs awsCredentialSource) isValidMetadataServer(metadataUrl string) bool { + if metadataUrl == "" { + // Zero value means use default, which is valid. + return true + } + + u, err := url.Parse(metadataUrl) + if err != nil { + // Unparseable URL means invalid + return false + } + + for _, validHostname := range validHostnames { + if u.Hostname() == validHostname { + // If it's one of the valid hostnames, everything is good + return true + } + } + + // hostname not found in our allowlist, so not valid + return false +} + +func (cs awsCredentialSource) validateMetadataServer(metadataUrl, urlName string) error { + if !cs.isValidMetadataServer(metadataUrl) { + return fmt.Errorf("oauth2/google: invalid hostname %s for %s", metadataUrl, urlName) + } + + return nil +} + +func (cs awsCredentialSource) doRequest(req *http.Request) (*http.Response, error) { + if cs.client == nil { + cs.client = oauth2.NewClient(cs.ctx, nil) + } + return cs.client.Do(req.WithContext(cs.ctx)) +} + +func canRetrieveRegionFromEnvironment() bool { + // The AWS region can be provided through AWS_REGION or AWS_DEFAULT_REGION. Only one is + // required. + return getenv(awsRegion) != "" || getenv(awsDefaultRegion) != "" +} + +func canRetrieveSecurityCredentialFromEnvironment() bool { + // Check if both AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are available. + return getenv(awsAccessKeyId) != "" && getenv(awsSecretAccessKey) != "" +} + +func shouldUseMetadataServer() bool { + return !canRetrieveRegionFromEnvironment() || !canRetrieveSecurityCredentialFromEnvironment() +} + +func (cs awsCredentialSource) subjectToken() (string, error) { + if cs.requestSigner == nil { + headers := make(map[string]string) + if shouldUseMetadataServer() { + awsSessionToken, err := cs.getAWSSessionToken() + if err != nil { + return "", err + } + + if awsSessionToken != "" { + headers[awsIMDSv2SessionTokenHeader] = awsSessionToken + } + } + + awsSecurityCredentials, err := cs.getSecurityCredentials(headers) + if err != nil { + return "", err + } + + if cs.region, err = cs.getRegion(headers); err != nil { + return "", err + } + + cs.requestSigner = &awsRequestSigner{ + RegionName: cs.region, + AwsSecurityCredentials: awsSecurityCredentials, + } + } + + // Generate the signed request to AWS STS GetCallerIdentity API. + // Use the required regional endpoint. Otherwise, the request will fail. + req, err := http.NewRequest("POST", strings.Replace(cs.RegionalCredVerificationURL, "{region}", cs.region, 1), nil) + if err != nil { + return "", err + } + // The full, canonical resource name of the workload identity pool + // provider, with or without the HTTPS prefix. + // Including this header as part of the signature is recommended to + // ensure data integrity. + if cs.TargetResource != "" { + req.Header.Add("x-goog-cloud-target-resource", cs.TargetResource) + } + cs.requestSigner.SignRequest(req) + + /* + The GCP STS endpoint expects the headers to be formatted as: + # [ + # {key: 'x-amz-date', value: '...'}, + # {key: 'Authorization', value: '...'}, + # ... + # ] + # And then serialized as: + # quote(json.dumps({ + # url: '...', + # method: 'POST', + # headers: [{key: 'x-amz-date', value: '...'}, ...] + # })) + */ + + awsSignedReq := awsRequest{ + URL: req.URL.String(), + Method: "POST", + } + for headerKey, headerList := range req.Header { + for _, headerValue := range headerList { + awsSignedReq.Headers = append(awsSignedReq.Headers, awsRequestHeader{ + Key: headerKey, + Value: headerValue, + }) + } + } + sort.Slice(awsSignedReq.Headers, func(i, j int) bool { + headerCompare := strings.Compare(awsSignedReq.Headers[i].Key, awsSignedReq.Headers[j].Key) + if headerCompare == 0 { + return strings.Compare(awsSignedReq.Headers[i].Value, awsSignedReq.Headers[j].Value) < 0 + } + return headerCompare < 0 + }) + + result, err := json.Marshal(awsSignedReq) + if err != nil { + return "", err + } + return url.QueryEscape(string(result)), nil +} + +func (cs *awsCredentialSource) getAWSSessionToken() (string, error) { + if cs.IMDSv2SessionTokenURL == "" { + return "", nil + } + + req, err := http.NewRequest("PUT", cs.IMDSv2SessionTokenURL, nil) + if err != nil { + return "", err + } + + req.Header.Add(awsIMDSv2SessionTtlHeader, awsIMDSv2SessionTtl) + + resp, err := cs.doRequest(req) + if err != nil { + return "", err + } + defer resp.Body.Close() + + respBody, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20)) + if err != nil { + return "", err + } + + if resp.StatusCode != 200 { + return "", fmt.Errorf("oauth2/google: unable to retrieve AWS session token - %s", string(respBody)) + } + + return string(respBody), nil +} + +func (cs *awsCredentialSource) getRegion(headers map[string]string) (string, error) { + if canRetrieveRegionFromEnvironment() { + if envAwsRegion := getenv(awsRegion); envAwsRegion != "" { + return envAwsRegion, nil + } + return getenv("AWS_DEFAULT_REGION"), nil + } + + if cs.RegionURL == "" { + return "", errors.New("oauth2/google: unable to determine AWS region") + } + + req, err := http.NewRequest("GET", cs.RegionURL, nil) + if err != nil { + return "", err + } + + for name, value := range headers { + req.Header.Add(name, value) + } + + resp, err := cs.doRequest(req) + if err != nil { + return "", err + } + defer resp.Body.Close() + + respBody, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20)) + if err != nil { + return "", err + } + + if resp.StatusCode != 200 { + return "", fmt.Errorf("oauth2/google: unable to retrieve AWS region - %s", string(respBody)) + } + + // This endpoint will return the region in format: us-east-2b. + // Only the us-east-2 part should be used. + respBodyEnd := 0 + if len(respBody) > 1 { + respBodyEnd = len(respBody) - 1 + } + return string(respBody[:respBodyEnd]), nil +} + +func (cs *awsCredentialSource) getSecurityCredentials(headers map[string]string) (result awsSecurityCredentials, err error) { + if canRetrieveSecurityCredentialFromEnvironment() { + return awsSecurityCredentials{ + AccessKeyID: getenv(awsAccessKeyId), + SecretAccessKey: getenv(awsSecretAccessKey), + SecurityToken: getenv(awsSessionToken), + }, nil + } + + roleName, err := cs.getMetadataRoleName(headers) + if err != nil { + return + } + + credentials, err := cs.getMetadataSecurityCredentials(roleName, headers) + if err != nil { + return + } + + if credentials.AccessKeyID == "" { + return result, errors.New("oauth2/google: missing AccessKeyId credential") + } + + if credentials.SecretAccessKey == "" { + return result, errors.New("oauth2/google: missing SecretAccessKey credential") + } + + return credentials, nil +} + +func (cs *awsCredentialSource) getMetadataSecurityCredentials(roleName string, headers map[string]string) (awsSecurityCredentials, error) { + var result awsSecurityCredentials + + req, err := http.NewRequest("GET", fmt.Sprintf("%s/%s", cs.CredVerificationURL, roleName), nil) + if err != nil { + return result, err + } + req.Header.Add("Content-Type", "application/json") + + for name, value := range headers { + req.Header.Add(name, value) + } + + resp, err := cs.doRequest(req) + if err != nil { + return result, err + } + defer resp.Body.Close() + + respBody, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20)) + if err != nil { + return result, err + } + + if resp.StatusCode != 200 { + return result, fmt.Errorf("oauth2/google: unable to retrieve AWS security credentials - %s", string(respBody)) + } + + err = json.Unmarshal(respBody, &result) + return result, err +} + +func (cs *awsCredentialSource) getMetadataRoleName(headers map[string]string) (string, error) { + if cs.CredVerificationURL == "" { + return "", errors.New("oauth2/google: unable to determine the AWS metadata server security credentials endpoint") + } + + req, err := http.NewRequest("GET", cs.CredVerificationURL, nil) + if err != nil { + return "", err + } + + for name, value := range headers { + req.Header.Add(name, value) + } + + resp, err := cs.doRequest(req) + if err != nil { + return "", err + } + defer resp.Body.Close() + + respBody, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20)) + if err != nil { + return "", err + } + + if resp.StatusCode != 200 { + return "", fmt.Errorf("oauth2/google: unable to retrieve AWS role name - %s", string(respBody)) + } + + return string(respBody), nil +} diff --git a/vendor/golang.org/x/oauth2/google/internal/externalaccount/basecredentials.go b/vendor/golang.org/x/oauth2/google/internal/externalaccount/basecredentials.go new file mode 100644 index 00000000000..dcd252a61cc --- /dev/null +++ b/vendor/golang.org/x/oauth2/google/internal/externalaccount/basecredentials.go @@ -0,0 +1,269 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package externalaccount + +import ( + "context" + "fmt" + "net/http" + "net/url" + "regexp" + "strconv" + "strings" + "time" + + "golang.org/x/oauth2" +) + +// now aliases time.Now for testing +var now = func() time.Time { + return time.Now().UTC() +} + +// Config stores the configuration for fetching tokens with external credentials. +type Config struct { + // Audience is the Secure Token Service (STS) audience which contains the resource name for the workload + // identity pool or the workforce pool and the provider identifier in that pool. + Audience string + // SubjectTokenType is the STS token type based on the Oauth2.0 token exchange spec + // e.g. `urn:ietf:params:oauth:token-type:jwt`. + SubjectTokenType string + // TokenURL is the STS token exchange endpoint. + TokenURL string + // TokenInfoURL is the token_info endpoint used to retrieve the account related information ( + // user attributes like account identifier, eg. email, username, uid, etc). This is + // needed for gCloud session account identification. + TokenInfoURL string + // ServiceAccountImpersonationURL is the URL for the service account impersonation request. This is only + // required for workload identity pools when APIs to be accessed have not integrated with UberMint. + ServiceAccountImpersonationURL string + // ServiceAccountImpersonationLifetimeSeconds is the number of seconds the service account impersonation + // token will be valid for. + ServiceAccountImpersonationLifetimeSeconds int + // ClientSecret is currently only required if token_info endpoint also + // needs to be called with the generated GCP access token. When provided, STS will be + // called with additional basic authentication using client_id as username and client_secret as password. + ClientSecret string + // ClientID is only required in conjunction with ClientSecret, as described above. + ClientID string + // CredentialSource contains the necessary information to retrieve the token itself, as well + // as some environmental information. + CredentialSource CredentialSource + // QuotaProjectID is injected by gCloud. If the value is non-empty, the Auth libraries + // will set the x-goog-user-project which overrides the project associated with the credentials. + QuotaProjectID string + // Scopes contains the desired scopes for the returned access token. + Scopes []string + // The optional workforce pool user project number when the credential + // corresponds to a workforce pool and not a workload identity pool. + // The underlying principal must still have serviceusage.services.use IAM + // permission to use the project for billing/quota. + WorkforcePoolUserProject string +} + +// Each element consists of a list of patterns. validateURLs checks for matches +// that include all elements in a given list, in that order. + +var ( + validWorkforceAudiencePattern *regexp.Regexp = regexp.MustCompile(`//iam\.googleapis\.com/locations/[^/]+/workforcePools/`) +) + +func validateURL(input string, patterns []*regexp.Regexp, scheme string) bool { + parsed, err := url.Parse(input) + if err != nil { + return false + } + if !strings.EqualFold(parsed.Scheme, scheme) { + return false + } + toTest := parsed.Host + + for _, pattern := range patterns { + if pattern.MatchString(toTest) { + return true + } + } + return false +} + +func validateWorkforceAudience(input string) bool { + return validWorkforceAudiencePattern.MatchString(input) +} + +// TokenSource Returns an external account TokenSource struct. This is to be called by package google to construct a google.Credentials. +func (c *Config) TokenSource(ctx context.Context) (oauth2.TokenSource, error) { + return c.tokenSource(ctx, "https") +} + +// tokenSource is a private function that's directly called by some of the tests, +// because the unit test URLs are mocked, and would otherwise fail the +// validity check. +func (c *Config) tokenSource(ctx context.Context, scheme string) (oauth2.TokenSource, error) { + if c.WorkforcePoolUserProject != "" { + valid := validateWorkforceAudience(c.Audience) + if !valid { + return nil, fmt.Errorf("oauth2/google: workforce_pool_user_project should not be set for non-workforce pool credentials") + } + } + + ts := tokenSource{ + ctx: ctx, + conf: c, + } + if c.ServiceAccountImpersonationURL == "" { + return oauth2.ReuseTokenSource(nil, ts), nil + } + scopes := c.Scopes + ts.conf.Scopes = []string{"https://www.googleapis.com/auth/cloud-platform"} + imp := ImpersonateTokenSource{ + Ctx: ctx, + URL: c.ServiceAccountImpersonationURL, + Scopes: scopes, + Ts: oauth2.ReuseTokenSource(nil, ts), + TokenLifetimeSeconds: c.ServiceAccountImpersonationLifetimeSeconds, + } + return oauth2.ReuseTokenSource(nil, imp), nil +} + +// Subject token file types. +const ( + fileTypeText = "text" + fileTypeJSON = "json" +) + +type format struct { + // Type is either "text" or "json". When not provided "text" type is assumed. + Type string `json:"type"` + // SubjectTokenFieldName is only required for JSON format. This would be "access_token" for azure. + SubjectTokenFieldName string `json:"subject_token_field_name"` +} + +// CredentialSource stores the information necessary to retrieve the credentials for the STS exchange. +// One field amongst File, URL, and Executable should be filled, depending on the kind of credential in question. +// The EnvironmentID should start with AWS if being used for an AWS credential. +type CredentialSource struct { + File string `json:"file"` + + URL string `json:"url"` + Headers map[string]string `json:"headers"` + + Executable *ExecutableConfig `json:"executable"` + + EnvironmentID string `json:"environment_id"` + RegionURL string `json:"region_url"` + RegionalCredVerificationURL string `json:"regional_cred_verification_url"` + CredVerificationURL string `json:"cred_verification_url"` + IMDSv2SessionTokenURL string `json:"imdsv2_session_token_url"` + Format format `json:"format"` +} + +type ExecutableConfig struct { + Command string `json:"command"` + TimeoutMillis *int `json:"timeout_millis"` + OutputFile string `json:"output_file"` +} + +// parse determines the type of CredentialSource needed. +func (c *Config) parse(ctx context.Context) (baseCredentialSource, error) { + if len(c.CredentialSource.EnvironmentID) > 3 && c.CredentialSource.EnvironmentID[:3] == "aws" { + if awsVersion, err := strconv.Atoi(c.CredentialSource.EnvironmentID[3:]); err == nil { + if awsVersion != 1 { + return nil, fmt.Errorf("oauth2/google: aws version '%d' is not supported in the current build", awsVersion) + } + + awsCredSource := awsCredentialSource{ + EnvironmentID: c.CredentialSource.EnvironmentID, + RegionURL: c.CredentialSource.RegionURL, + RegionalCredVerificationURL: c.CredentialSource.RegionalCredVerificationURL, + CredVerificationURL: c.CredentialSource.URL, + TargetResource: c.Audience, + ctx: ctx, + } + if c.CredentialSource.IMDSv2SessionTokenURL != "" { + awsCredSource.IMDSv2SessionTokenURL = c.CredentialSource.IMDSv2SessionTokenURL + } + + if err := awsCredSource.validateMetadataServers(); err != nil { + return nil, err + } + + return awsCredSource, nil + } + } else if c.CredentialSource.File != "" { + return fileCredentialSource{File: c.CredentialSource.File, Format: c.CredentialSource.Format}, nil + } else if c.CredentialSource.URL != "" { + return urlCredentialSource{URL: c.CredentialSource.URL, Headers: c.CredentialSource.Headers, Format: c.CredentialSource.Format, ctx: ctx}, nil + } else if c.CredentialSource.Executable != nil { + return CreateExecutableCredential(ctx, c.CredentialSource.Executable, c) + } + return nil, fmt.Errorf("oauth2/google: unable to parse credential source") +} + +type baseCredentialSource interface { + subjectToken() (string, error) +} + +// tokenSource is the source that handles external credentials. It is used to retrieve Tokens. +type tokenSource struct { + ctx context.Context + conf *Config +} + +// Token allows tokenSource to conform to the oauth2.TokenSource interface. +func (ts tokenSource) Token() (*oauth2.Token, error) { + conf := ts.conf + + credSource, err := conf.parse(ts.ctx) + if err != nil { + return nil, err + } + subjectToken, err := credSource.subjectToken() + + if err != nil { + return nil, err + } + stsRequest := stsTokenExchangeRequest{ + GrantType: "urn:ietf:params:oauth:grant-type:token-exchange", + Audience: conf.Audience, + Scope: conf.Scopes, + RequestedTokenType: "urn:ietf:params:oauth:token-type:access_token", + SubjectToken: subjectToken, + SubjectTokenType: conf.SubjectTokenType, + } + header := make(http.Header) + header.Add("Content-Type", "application/x-www-form-urlencoded") + clientAuth := clientAuthentication{ + AuthStyle: oauth2.AuthStyleInHeader, + ClientID: conf.ClientID, + ClientSecret: conf.ClientSecret, + } + var options map[string]interface{} + // Do not pass workforce_pool_user_project when client authentication is used. + // The client ID is sufficient for determining the user project. + if conf.WorkforcePoolUserProject != "" && conf.ClientID == "" { + options = map[string]interface{}{ + "userProject": conf.WorkforcePoolUserProject, + } + } + stsResp, err := exchangeToken(ts.ctx, conf.TokenURL, &stsRequest, clientAuth, header, options) + if err != nil { + return nil, err + } + + accessToken := &oauth2.Token{ + AccessToken: stsResp.AccessToken, + TokenType: stsResp.TokenType, + } + if stsResp.ExpiresIn < 0 { + return nil, fmt.Errorf("oauth2/google: got invalid expiry from security token service") + } else if stsResp.ExpiresIn >= 0 { + accessToken.Expiry = now().Add(time.Duration(stsResp.ExpiresIn) * time.Second) + } + + if stsResp.RefreshToken != "" { + accessToken.RefreshToken = stsResp.RefreshToken + } + return accessToken, nil +} diff --git a/vendor/golang.org/x/oauth2/google/internal/externalaccount/clientauth.go b/vendor/golang.org/x/oauth2/google/internal/externalaccount/clientauth.go new file mode 100644 index 00000000000..99987ce2945 --- /dev/null +++ b/vendor/golang.org/x/oauth2/google/internal/externalaccount/clientauth.go @@ -0,0 +1,45 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package externalaccount + +import ( + "encoding/base64" + "net/http" + "net/url" + + "golang.org/x/oauth2" +) + +// clientAuthentication represents an OAuth client ID and secret and the mechanism for passing these credentials as stated in rfc6749#2.3.1. +type clientAuthentication struct { + // AuthStyle can be either basic or request-body + AuthStyle oauth2.AuthStyle + ClientID string + ClientSecret string +} + +// InjectAuthentication is used to add authentication to a Secure Token Service exchange +// request. It modifies either the passed url.Values or http.Header depending on the desired +// authentication format. +func (c *clientAuthentication) InjectAuthentication(values url.Values, headers http.Header) { + if c.ClientID == "" || c.ClientSecret == "" || values == nil || headers == nil { + return + } + + switch c.AuthStyle { + case oauth2.AuthStyleInHeader: // AuthStyleInHeader corresponds to basic authentication as defined in rfc7617#2 + plainHeader := c.ClientID + ":" + c.ClientSecret + headers.Add("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(plainHeader))) + case oauth2.AuthStyleInParams: // AuthStyleInParams corresponds to request-body authentication with ClientID and ClientSecret in the message body. + values.Set("client_id", c.ClientID) + values.Set("client_secret", c.ClientSecret) + case oauth2.AuthStyleAutoDetect: + values.Set("client_id", c.ClientID) + values.Set("client_secret", c.ClientSecret) + default: + values.Set("client_id", c.ClientID) + values.Set("client_secret", c.ClientSecret) + } +} diff --git a/vendor/golang.org/x/oauth2/google/internal/externalaccount/err.go b/vendor/golang.org/x/oauth2/google/internal/externalaccount/err.go new file mode 100644 index 00000000000..233a78cef2a --- /dev/null +++ b/vendor/golang.org/x/oauth2/google/internal/externalaccount/err.go @@ -0,0 +1,18 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package externalaccount + +import "fmt" + +// Error for handling OAuth related error responses as stated in rfc6749#5.2. +type Error struct { + Code string + URI string + Description string +} + +func (err *Error) Error() string { + return fmt.Sprintf("got error code %s from %s: %s", err.Code, err.URI, err.Description) +} diff --git a/vendor/golang.org/x/oauth2/google/internal/externalaccount/executablecredsource.go b/vendor/golang.org/x/oauth2/google/internal/externalaccount/executablecredsource.go new file mode 100644 index 00000000000..579bcce5f28 --- /dev/null +++ b/vendor/golang.org/x/oauth2/google/internal/externalaccount/executablecredsource.go @@ -0,0 +1,309 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package externalaccount + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "io" + "io/ioutil" + "os" + "os/exec" + "regexp" + "strings" + "time" +) + +var serviceAccountImpersonationRE = regexp.MustCompile("https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/(.*@.*):generateAccessToken") + +const ( + executableSupportedMaxVersion = 1 + defaultTimeout = 30 * time.Second + timeoutMinimum = 5 * time.Second + timeoutMaximum = 120 * time.Second + executableSource = "response" + outputFileSource = "output file" +) + +type nonCacheableError struct { + message string +} + +func (nce nonCacheableError) Error() string { + return nce.message +} + +func missingFieldError(source, field string) error { + return fmt.Errorf("oauth2/google: %v missing `%q` field", source, field) +} + +func jsonParsingError(source, data string) error { + return fmt.Errorf("oauth2/google: unable to parse %v\nResponse: %v", source, data) +} + +func malformedFailureError() error { + return nonCacheableError{"oauth2/google: response must include `error` and `message` fields when unsuccessful"} +} + +func userDefinedError(code, message string) error { + return nonCacheableError{fmt.Sprintf("oauth2/google: response contains unsuccessful response: (%v) %v", code, message)} +} + +func unsupportedVersionError(source string, version int) error { + return fmt.Errorf("oauth2/google: %v contains unsupported version: %v", source, version) +} + +func tokenExpiredError() error { + return nonCacheableError{"oauth2/google: the token returned by the executable is expired"} +} + +func tokenTypeError(source string) error { + return fmt.Errorf("oauth2/google: %v contains unsupported token type", source) +} + +func exitCodeError(exitCode int) error { + return fmt.Errorf("oauth2/google: executable command failed with exit code %v", exitCode) +} + +func executableError(err error) error { + return fmt.Errorf("oauth2/google: executable command failed: %v", err) +} + +func executablesDisallowedError() error { + return errors.New("oauth2/google: executables need to be explicitly allowed (set GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES to '1') to run") +} + +func timeoutRangeError() error { + return errors.New("oauth2/google: invalid `timeout_millis` field — executable timeout must be between 5 and 120 seconds") +} + +func commandMissingError() error { + return errors.New("oauth2/google: missing `command` field — executable command must be provided") +} + +type environment interface { + existingEnv() []string + getenv(string) string + run(ctx context.Context, command string, env []string) ([]byte, error) + now() time.Time +} + +type runtimeEnvironment struct{} + +func (r runtimeEnvironment) existingEnv() []string { + return os.Environ() +} + +func (r runtimeEnvironment) getenv(key string) string { + return os.Getenv(key) +} + +func (r runtimeEnvironment) now() time.Time { + return time.Now().UTC() +} + +func (r runtimeEnvironment) run(ctx context.Context, command string, env []string) ([]byte, error) { + splitCommand := strings.Fields(command) + cmd := exec.CommandContext(ctx, splitCommand[0], splitCommand[1:]...) + cmd.Env = env + + var stdout, stderr bytes.Buffer + cmd.Stdout = &stdout + cmd.Stderr = &stderr + + if err := cmd.Run(); err != nil { + if ctx.Err() == context.DeadlineExceeded { + return nil, context.DeadlineExceeded + } + + if exitError, ok := err.(*exec.ExitError); ok { + return nil, exitCodeError(exitError.ExitCode()) + } + + return nil, executableError(err) + } + + bytesStdout := bytes.TrimSpace(stdout.Bytes()) + if len(bytesStdout) > 0 { + return bytesStdout, nil + } + return bytes.TrimSpace(stderr.Bytes()), nil +} + +type executableCredentialSource struct { + Command string + Timeout time.Duration + OutputFile string + ctx context.Context + config *Config + env environment +} + +// CreateExecutableCredential creates an executableCredentialSource given an ExecutableConfig. +// It also performs defaulting and type conversions. +func CreateExecutableCredential(ctx context.Context, ec *ExecutableConfig, config *Config) (executableCredentialSource, error) { + if ec.Command == "" { + return executableCredentialSource{}, commandMissingError() + } + + result := executableCredentialSource{} + result.Command = ec.Command + if ec.TimeoutMillis == nil { + result.Timeout = defaultTimeout + } else { + result.Timeout = time.Duration(*ec.TimeoutMillis) * time.Millisecond + if result.Timeout < timeoutMinimum || result.Timeout > timeoutMaximum { + return executableCredentialSource{}, timeoutRangeError() + } + } + result.OutputFile = ec.OutputFile + result.ctx = ctx + result.config = config + result.env = runtimeEnvironment{} + return result, nil +} + +type executableResponse struct { + Version int `json:"version,omitempty"` + Success *bool `json:"success,omitempty"` + TokenType string `json:"token_type,omitempty"` + ExpirationTime int64 `json:"expiration_time,omitempty"` + IdToken string `json:"id_token,omitempty"` + SamlResponse string `json:"saml_response,omitempty"` + Code string `json:"code,omitempty"` + Message string `json:"message,omitempty"` +} + +func (cs executableCredentialSource) parseSubjectTokenFromSource(response []byte, source string, now int64) (string, error) { + var result executableResponse + if err := json.Unmarshal(response, &result); err != nil { + return "", jsonParsingError(source, string(response)) + } + + if result.Version == 0 { + return "", missingFieldError(source, "version") + } + + if result.Success == nil { + return "", missingFieldError(source, "success") + } + + if !*result.Success { + if result.Code == "" || result.Message == "" { + return "", malformedFailureError() + } + return "", userDefinedError(result.Code, result.Message) + } + + if result.Version > executableSupportedMaxVersion || result.Version < 0 { + return "", unsupportedVersionError(source, result.Version) + } + + if result.ExpirationTime == 0 && cs.OutputFile != "" { + return "", missingFieldError(source, "expiration_time") + } + + if result.TokenType == "" { + return "", missingFieldError(source, "token_type") + } + + if result.ExpirationTime != 0 && result.ExpirationTime < now { + return "", tokenExpiredError() + } + + if result.TokenType == "urn:ietf:params:oauth:token-type:jwt" || result.TokenType == "urn:ietf:params:oauth:token-type:id_token" { + if result.IdToken == "" { + return "", missingFieldError(source, "id_token") + } + return result.IdToken, nil + } + + if result.TokenType == "urn:ietf:params:oauth:token-type:saml2" { + if result.SamlResponse == "" { + return "", missingFieldError(source, "saml_response") + } + return result.SamlResponse, nil + } + + return "", tokenTypeError(source) +} + +func (cs executableCredentialSource) subjectToken() (string, error) { + if token, err := cs.getTokenFromOutputFile(); token != "" || err != nil { + return token, err + } + + return cs.getTokenFromExecutableCommand() +} + +func (cs executableCredentialSource) getTokenFromOutputFile() (token string, err error) { + if cs.OutputFile == "" { + // This ExecutableCredentialSource doesn't use an OutputFile. + return "", nil + } + + file, err := os.Open(cs.OutputFile) + if err != nil { + // No OutputFile found. Hasn't been created yet, so skip it. + return "", nil + } + defer file.Close() + + data, err := ioutil.ReadAll(io.LimitReader(file, 1<<20)) + if err != nil || len(data) == 0 { + // Cachefile exists, but no data found. Get new credential. + return "", nil + } + + token, err = cs.parseSubjectTokenFromSource(data, outputFileSource, cs.env.now().Unix()) + if err != nil { + if _, ok := err.(nonCacheableError); ok { + // If the cached token is expired we need a new token, + // and if the cache contains a failure, we need to try again. + return "", nil + } + + // There was an error in the cached token, and the developer should be aware of it. + return "", err + } + // Token parsing succeeded. Use found token. + return token, nil +} + +func (cs executableCredentialSource) executableEnvironment() []string { + result := cs.env.existingEnv() + result = append(result, fmt.Sprintf("GOOGLE_EXTERNAL_ACCOUNT_AUDIENCE=%v", cs.config.Audience)) + result = append(result, fmt.Sprintf("GOOGLE_EXTERNAL_ACCOUNT_TOKEN_TYPE=%v", cs.config.SubjectTokenType)) + result = append(result, "GOOGLE_EXTERNAL_ACCOUNT_INTERACTIVE=0") + if cs.config.ServiceAccountImpersonationURL != "" { + matches := serviceAccountImpersonationRE.FindStringSubmatch(cs.config.ServiceAccountImpersonationURL) + if matches != nil { + result = append(result, fmt.Sprintf("GOOGLE_EXTERNAL_ACCOUNT_IMPERSONATED_EMAIL=%v", matches[1])) + } + } + if cs.OutputFile != "" { + result = append(result, fmt.Sprintf("GOOGLE_EXTERNAL_ACCOUNT_OUTPUT_FILE=%v", cs.OutputFile)) + } + return result +} + +func (cs executableCredentialSource) getTokenFromExecutableCommand() (string, error) { + // For security reasons, we need our consumers to set this environment variable to allow executables to be run. + if cs.env.getenv("GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES") != "1" { + return "", executablesDisallowedError() + } + + ctx, cancel := context.WithDeadline(cs.ctx, cs.env.now().Add(cs.Timeout)) + defer cancel() + + output, err := cs.env.run(ctx, cs.Command, cs.executableEnvironment()) + if err != nil { + return "", err + } + return cs.parseSubjectTokenFromSource(output, executableSource, cs.env.now().Unix()) +} diff --git a/vendor/golang.org/x/oauth2/google/internal/externalaccount/filecredsource.go b/vendor/golang.org/x/oauth2/google/internal/externalaccount/filecredsource.go new file mode 100644 index 00000000000..e953ddb473a --- /dev/null +++ b/vendor/golang.org/x/oauth2/google/internal/externalaccount/filecredsource.go @@ -0,0 +1,57 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package externalaccount + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io" + "io/ioutil" + "os" +) + +type fileCredentialSource struct { + File string + Format format +} + +func (cs fileCredentialSource) subjectToken() (string, error) { + tokenFile, err := os.Open(cs.File) + if err != nil { + return "", fmt.Errorf("oauth2/google: failed to open credential file %q", cs.File) + } + defer tokenFile.Close() + tokenBytes, err := ioutil.ReadAll(io.LimitReader(tokenFile, 1<<20)) + if err != nil { + return "", fmt.Errorf("oauth2/google: failed to read credential file: %v", err) + } + tokenBytes = bytes.TrimSpace(tokenBytes) + switch cs.Format.Type { + case "json": + jsonData := make(map[string]interface{}) + err = json.Unmarshal(tokenBytes, &jsonData) + if err != nil { + return "", fmt.Errorf("oauth2/google: failed to unmarshal subject token file: %v", err) + } + val, ok := jsonData[cs.Format.SubjectTokenFieldName] + if !ok { + return "", errors.New("oauth2/google: provided subject_token_field_name not found in credentials") + } + token, ok := val.(string) + if !ok { + return "", errors.New("oauth2/google: improperly formatted subject token") + } + return token, nil + case "text": + return string(tokenBytes), nil + case "": + return string(tokenBytes), nil + default: + return "", errors.New("oauth2/google: invalid credential_source file format type") + } + +} diff --git a/vendor/golang.org/x/oauth2/google/internal/externalaccount/impersonate.go b/vendor/golang.org/x/oauth2/google/internal/externalaccount/impersonate.go new file mode 100644 index 00000000000..54c8f209f3b --- /dev/null +++ b/vendor/golang.org/x/oauth2/google/internal/externalaccount/impersonate.go @@ -0,0 +1,105 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package externalaccount + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "net/http" + "time" + + "golang.org/x/oauth2" +) + +// generateAccesstokenReq is used for service account impersonation +type generateAccessTokenReq struct { + Delegates []string `json:"delegates,omitempty"` + Lifetime string `json:"lifetime,omitempty"` + Scope []string `json:"scope,omitempty"` +} + +type impersonateTokenResponse struct { + AccessToken string `json:"accessToken"` + ExpireTime string `json:"expireTime"` +} + +// ImpersonateTokenSource uses a source credential, stored in Ts, to request an access token to the provided URL. +// Scopes can be defined when the access token is requested. +type ImpersonateTokenSource struct { + // Ctx is the execution context of the impersonation process + // used to perform http call to the URL. Required + Ctx context.Context + // Ts is the source credential used to generate a token on the + // impersonated service account. Required. + Ts oauth2.TokenSource + + // URL is the endpoint to call to generate a token + // on behalf the service account. Required. + URL string + // Scopes that the impersonated credential should have. Required. + Scopes []string + // Delegates are the service account email addresses in a delegation chain. + // Each service account must be granted roles/iam.serviceAccountTokenCreator + // on the next service account in the chain. Optional. + Delegates []string + // TokenLifetimeSeconds is the number of seconds the impersonation token will + // be valid for. + TokenLifetimeSeconds int +} + +// Token performs the exchange to get a temporary service account token to allow access to GCP. +func (its ImpersonateTokenSource) Token() (*oauth2.Token, error) { + lifetimeString := "3600s" + if its.TokenLifetimeSeconds != 0 { + lifetimeString = fmt.Sprintf("%ds", its.TokenLifetimeSeconds) + } + reqBody := generateAccessTokenReq{ + Lifetime: lifetimeString, + Scope: its.Scopes, + Delegates: its.Delegates, + } + b, err := json.Marshal(reqBody) + if err != nil { + return nil, fmt.Errorf("oauth2/google: unable to marshal request: %v", err) + } + client := oauth2.NewClient(its.Ctx, its.Ts) + req, err := http.NewRequest("POST", its.URL, bytes.NewReader(b)) + if err != nil { + return nil, fmt.Errorf("oauth2/google: unable to create impersonation request: %v", err) + } + req = req.WithContext(its.Ctx) + req.Header.Set("Content-Type", "application/json") + + resp, err := client.Do(req) + if err != nil { + return nil, fmt.Errorf("oauth2/google: unable to generate access token: %v", err) + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20)) + if err != nil { + return nil, fmt.Errorf("oauth2/google: unable to read body: %v", err) + } + if c := resp.StatusCode; c < 200 || c > 299 { + return nil, fmt.Errorf("oauth2/google: status code %d: %s", c, body) + } + + var accessTokenResp impersonateTokenResponse + if err := json.Unmarshal(body, &accessTokenResp); err != nil { + return nil, fmt.Errorf("oauth2/google: unable to parse response: %v", err) + } + expiry, err := time.Parse(time.RFC3339, accessTokenResp.ExpireTime) + if err != nil { + return nil, fmt.Errorf("oauth2/google: unable to parse expiry: %v", err) + } + return &oauth2.Token{ + AccessToken: accessTokenResp.AccessToken, + Expiry: expiry, + TokenType: "Bearer", + }, nil +} diff --git a/vendor/golang.org/x/oauth2/google/internal/externalaccount/sts_exchange.go b/vendor/golang.org/x/oauth2/google/internal/externalaccount/sts_exchange.go new file mode 100644 index 00000000000..e6fcae5fcbf --- /dev/null +++ b/vendor/golang.org/x/oauth2/google/internal/externalaccount/sts_exchange.go @@ -0,0 +1,107 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package externalaccount + +import ( + "context" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "net/http" + "net/url" + "strconv" + "strings" + + "golang.org/x/oauth2" +) + +// exchangeToken performs an oauth2 token exchange with the provided endpoint. +// The first 4 fields are all mandatory. headers can be used to pass additional +// headers beyond the bare minimum required by the token exchange. options can +// be used to pass additional JSON-structured options to the remote server. +func exchangeToken(ctx context.Context, endpoint string, request *stsTokenExchangeRequest, authentication clientAuthentication, headers http.Header, options map[string]interface{}) (*stsTokenExchangeResponse, error) { + + client := oauth2.NewClient(ctx, nil) + + data := url.Values{} + data.Set("audience", request.Audience) + data.Set("grant_type", "urn:ietf:params:oauth:grant-type:token-exchange") + data.Set("requested_token_type", "urn:ietf:params:oauth:token-type:access_token") + data.Set("subject_token_type", request.SubjectTokenType) + data.Set("subject_token", request.SubjectToken) + data.Set("scope", strings.Join(request.Scope, " ")) + if options != nil { + opts, err := json.Marshal(options) + if err != nil { + return nil, fmt.Errorf("oauth2/google: failed to marshal additional options: %v", err) + } + data.Set("options", string(opts)) + } + + authentication.InjectAuthentication(data, headers) + encodedData := data.Encode() + + req, err := http.NewRequest("POST", endpoint, strings.NewReader(encodedData)) + if err != nil { + return nil, fmt.Errorf("oauth2/google: failed to properly build http request: %v", err) + + } + req = req.WithContext(ctx) + for key, list := range headers { + for _, val := range list { + req.Header.Add(key, val) + } + } + req.Header.Add("Content-Length", strconv.Itoa(len(encodedData))) + + resp, err := client.Do(req) + + if err != nil { + return nil, fmt.Errorf("oauth2/google: invalid response from Secure Token Server: %v", err) + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20)) + if err != nil { + return nil, err + } + if c := resp.StatusCode; c < 200 || c > 299 { + return nil, fmt.Errorf("oauth2/google: status code %d: %s", c, body) + } + var stsResp stsTokenExchangeResponse + err = json.Unmarshal(body, &stsResp) + if err != nil { + return nil, fmt.Errorf("oauth2/google: failed to unmarshal response body from Secure Token Server: %v", err) + + } + + return &stsResp, nil +} + +// stsTokenExchangeRequest contains fields necessary to make an oauth2 token exchange. +type stsTokenExchangeRequest struct { + ActingParty struct { + ActorToken string + ActorTokenType string + } + GrantType string + Resource string + Audience string + Scope []string + RequestedTokenType string + SubjectToken string + SubjectTokenType string +} + +// stsTokenExchangeResponse is used to decode the remote server response during an oauth2 token exchange. +type stsTokenExchangeResponse struct { + AccessToken string `json:"access_token"` + IssuedTokenType string `json:"issued_token_type"` + TokenType string `json:"token_type"` + ExpiresIn int `json:"expires_in"` + Scope string `json:"scope"` + RefreshToken string `json:"refresh_token"` +} diff --git a/vendor/golang.org/x/oauth2/google/internal/externalaccount/urlcredsource.go b/vendor/golang.org/x/oauth2/google/internal/externalaccount/urlcredsource.go new file mode 100644 index 00000000000..16dca6541d9 --- /dev/null +++ b/vendor/golang.org/x/oauth2/google/internal/externalaccount/urlcredsource.go @@ -0,0 +1,75 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package externalaccount + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "io" + "io/ioutil" + "net/http" + + "golang.org/x/oauth2" +) + +type urlCredentialSource struct { + URL string + Headers map[string]string + Format format + ctx context.Context +} + +func (cs urlCredentialSource) subjectToken() (string, error) { + client := oauth2.NewClient(cs.ctx, nil) + req, err := http.NewRequest("GET", cs.URL, nil) + if err != nil { + return "", fmt.Errorf("oauth2/google: HTTP request for URL-sourced credential failed: %v", err) + } + req = req.WithContext(cs.ctx) + + for key, val := range cs.Headers { + req.Header.Add(key, val) + } + resp, err := client.Do(req) + if err != nil { + return "", fmt.Errorf("oauth2/google: invalid response when retrieving subject token: %v", err) + } + defer resp.Body.Close() + + respBody, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20)) + if err != nil { + return "", fmt.Errorf("oauth2/google: invalid body in subject token URL query: %v", err) + } + if c := resp.StatusCode; c < 200 || c > 299 { + return "", fmt.Errorf("oauth2/google: status code %d: %s", c, respBody) + } + + switch cs.Format.Type { + case "json": + jsonData := make(map[string]interface{}) + err = json.Unmarshal(respBody, &jsonData) + if err != nil { + return "", fmt.Errorf("oauth2/google: failed to unmarshal subject token file: %v", err) + } + val, ok := jsonData[cs.Format.SubjectTokenFieldName] + if !ok { + return "", errors.New("oauth2/google: provided subject_token_field_name not found in credentials") + } + token, ok := val.(string) + if !ok { + return "", errors.New("oauth2/google: improperly formatted subject token") + } + return token, nil + case "text": + return string(respBody), nil + case "": + return string(respBody), nil + default: + return "", errors.New("oauth2/google: invalid credential_source file format type") + } + +} diff --git a/vendor/golang.org/x/oauth2/google/jwt.go b/vendor/golang.org/x/oauth2/google/jwt.go index b0fdb3a888a..e89e6ae17bc 100644 --- a/vendor/golang.org/x/oauth2/google/jwt.go +++ b/vendor/golang.org/x/oauth2/google/jwt.go @@ -7,6 +7,7 @@ package google import ( "crypto/rsa" "fmt" + "strings" "time" "golang.org/x/oauth2" @@ -24,6 +25,28 @@ import ( // optimization supported by a few Google services. // Unless you know otherwise, you should use JWTConfigFromJSON instead. func JWTAccessTokenSourceFromJSON(jsonKey []byte, audience string) (oauth2.TokenSource, error) { + return newJWTSource(jsonKey, audience, nil) +} + +// JWTAccessTokenSourceWithScope uses a Google Developers service account JSON +// key file to read the credentials that authorize and authenticate the +// requests, and returns a TokenSource that does not use any OAuth2 flow but +// instead creates a JWT and sends that as the access token. +// The scope is typically a list of URLs that specifies the scope of the +// credentials. +// +// Note that this is not a standard OAuth flow, but rather an +// optimization supported by a few Google services. +// Unless you know otherwise, you should use JWTConfigFromJSON instead. +func JWTAccessTokenSourceWithScope(jsonKey []byte, scope ...string) (oauth2.TokenSource, error) { + return newJWTSource(jsonKey, "", scope) +} + +func newJWTSource(jsonKey []byte, audience string, scopes []string) (oauth2.TokenSource, error) { + if len(scopes) == 0 && audience == "" { + return nil, fmt.Errorf("google: missing scope/audience for JWT access token") + } + cfg, err := JWTConfigFromJSON(jsonKey) if err != nil { return nil, fmt.Errorf("google: could not parse JSON key: %v", err) @@ -35,6 +58,7 @@ func JWTAccessTokenSourceFromJSON(jsonKey []byte, audience string) (oauth2.Token ts := &jwtAccessTokenSource{ email: cfg.Email, audience: audience, + scopes: scopes, pk: pk, pkID: cfg.PrivateKeyID, } @@ -42,11 +66,13 @@ func JWTAccessTokenSourceFromJSON(jsonKey []byte, audience string) (oauth2.Token if err != nil { return nil, err } - return oauth2.ReuseTokenSource(tok, ts), nil + rts := newErrWrappingTokenSource(oauth2.ReuseTokenSource(tok, ts)) + return rts, nil } type jwtAccessTokenSource struct { email, audience string + scopes []string pk *rsa.PrivateKey pkID string } @@ -54,12 +80,14 @@ type jwtAccessTokenSource struct { func (ts *jwtAccessTokenSource) Token() (*oauth2.Token, error) { iat := time.Now() exp := iat.Add(time.Hour) + scope := strings.Join(ts.scopes, " ") cs := &jws.ClaimSet{ - Iss: ts.email, - Sub: ts.email, - Aud: ts.audience, - Iat: iat.Unix(), - Exp: exp.Unix(), + Iss: ts.email, + Sub: ts.email, + Aud: ts.audience, + Scope: scope, + Iat: iat.Unix(), + Exp: exp.Unix(), } hdr := &jws.Header{ Algorithm: "RS256", diff --git a/vendor/golang.org/x/oauth2/internal/client_appengine.go b/vendor/golang.org/x/oauth2/internal/client_appengine.go index 7434871880a..e1755d1d9ac 100644 --- a/vendor/golang.org/x/oauth2/internal/client_appengine.go +++ b/vendor/golang.org/x/oauth2/internal/client_appengine.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build appengine // +build appengine package internal diff --git a/vendor/golang.org/x/oauth2/internal/token.go b/vendor/golang.org/x/oauth2/internal/token.go index 355c386961d..b4723fcacea 100644 --- a/vendor/golang.org/x/oauth2/internal/token.go +++ b/vendor/golang.org/x/oauth2/internal/token.go @@ -19,8 +19,6 @@ import ( "strings" "sync" "time" - - "golang.org/x/net/context/ctxhttp" ) // Token represents the credentials used to authorize @@ -229,7 +227,7 @@ func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string, } func doTokenRoundTrip(ctx context.Context, req *http.Request) (*Token, error) { - r, err := ctxhttp.Do(ctx, ContextClient(ctx), req) + r, err := ContextClient(ctx).Do(req.WithContext(ctx)) if err != nil { return nil, err } diff --git a/vendor/golang.org/x/oauth2/jws/jws.go b/vendor/golang.org/x/oauth2/jws/jws.go index 683d2d271a3..95015648b43 100644 --- a/vendor/golang.org/x/oauth2/jws/jws.go +++ b/vendor/golang.org/x/oauth2/jws/jws.go @@ -178,5 +178,5 @@ func Verify(token string, key *rsa.PublicKey) error { h := sha256.New() h.Write([]byte(signedContent)) - return rsa.VerifyPKCS1v15(key, crypto.SHA256, h.Sum(nil), []byte(signatureString)) + return rsa.VerifyPKCS1v15(key, crypto.SHA256, h.Sum(nil), signatureString) } diff --git a/vendor/golang.org/x/oauth2/oauth2.go b/vendor/golang.org/x/oauth2/oauth2.go index 291df5c833f..9085fabe34e 100644 --- a/vendor/golang.org/x/oauth2/oauth2.go +++ b/vendor/golang.org/x/oauth2/oauth2.go @@ -16,6 +16,7 @@ import ( "net/url" "strings" "sync" + "time" "golang.org/x/oauth2/internal" ) @@ -140,7 +141,7 @@ func SetAuthURLParam(key, value string) AuthCodeOption { // // State is a token to protect the user from CSRF attacks. You must // always provide a non-empty string and validate that it matches the -// the state query parameter on your redirect callback. +// state query parameter on your redirect callback. // See http://tools.ietf.org/html/rfc6749#section-10.12 for more info. // // Opts may include AccessTypeOnline or AccessTypeOffline, as well @@ -290,6 +291,8 @@ type reuseTokenSource struct { mu sync.Mutex // guards t t *Token + + expiryDelta time.Duration } // Token returns the current token if it's still valid, else will @@ -305,6 +308,7 @@ func (s *reuseTokenSource) Token() (*Token, error) { if err != nil { return nil, err } + t.expiryDelta = s.expiryDelta s.t = t return t, nil } @@ -379,3 +383,30 @@ func ReuseTokenSource(t *Token, src TokenSource) TokenSource { new: src, } } + +// ReuseTokenSource returns a TokenSource that acts in the same manner as the +// TokenSource returned by ReuseTokenSource, except the expiry buffer is +// configurable. The expiration time of a token is calculated as +// t.Expiry.Add(-earlyExpiry). +func ReuseTokenSourceWithExpiry(t *Token, src TokenSource, earlyExpiry time.Duration) TokenSource { + // Don't wrap a reuseTokenSource in itself. That would work, + // but cause an unnecessary number of mutex operations. + // Just build the equivalent one. + if rt, ok := src.(*reuseTokenSource); ok { + if t == nil { + // Just use it directly, but set the expiryDelta to earlyExpiry, + // so the behavior matches what the user expects. + rt.expiryDelta = earlyExpiry + return rt + } + src = rt.new + } + if t != nil { + t.expiryDelta = earlyExpiry + } + return &reuseTokenSource{ + t: t, + new: src, + expiryDelta: earlyExpiry, + } +} diff --git a/vendor/golang.org/x/oauth2/token.go b/vendor/golang.org/x/oauth2/token.go index 822720341af..7c64006de69 100644 --- a/vendor/golang.org/x/oauth2/token.go +++ b/vendor/golang.org/x/oauth2/token.go @@ -16,10 +16,10 @@ import ( "golang.org/x/oauth2/internal" ) -// expiryDelta determines how earlier a token should be considered +// defaultExpiryDelta determines how earlier a token should be considered // expired than its actual expiration time. It is used to avoid late // expirations due to client-server time mismatches. -const expiryDelta = 10 * time.Second +const defaultExpiryDelta = 10 * time.Second // Token represents the credentials used to authorize // the requests to access protected resources on the OAuth 2.0 @@ -52,6 +52,11 @@ type Token struct { // raw optionally contains extra metadata from the server // when updating a token. raw interface{} + + // expiryDelta is used to calculate when a token is considered + // expired, by subtracting from Expiry. If zero, defaultExpiryDelta + // is used. + expiryDelta time.Duration } // Type returns t.TokenType if non-empty, else "Bearer". @@ -127,6 +132,11 @@ func (t *Token) expired() bool { if t.Expiry.IsZero() { return false } + + expiryDelta := defaultExpiryDelta + if t.expiryDelta != 0 { + expiryDelta = t.expiryDelta + } return t.Expiry.Round(0).Add(-expiryDelta).Before(timeNow()) } diff --git a/vendor/golang.org/x/sys/execabs/execabs.go b/vendor/golang.org/x/sys/execabs/execabs.go deleted file mode 100644 index 3bf40fdfecd..00000000000 --- a/vendor/golang.org/x/sys/execabs/execabs.go +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2020 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package execabs is a drop-in replacement for os/exec -// that requires PATH lookups to find absolute paths. -// That is, execabs.Command("cmd") runs the same PATH lookup -// as exec.Command("cmd"), but if the result is a path -// which is relative, the Run and Start methods will report -// an error instead of running the executable. -// -// See https://blog.golang.org/path-security for more information -// about when it may be necessary or appropriate to use this package. -package execabs - -import ( - "context" - "fmt" - "os/exec" - "path/filepath" - "reflect" - "unsafe" -) - -// ErrNotFound is the error resulting if a path search failed to find an executable file. -// It is an alias for exec.ErrNotFound. -var ErrNotFound = exec.ErrNotFound - -// Cmd represents an external command being prepared or run. -// It is an alias for exec.Cmd. -type Cmd = exec.Cmd - -// Error is returned by LookPath when it fails to classify a file as an executable. -// It is an alias for exec.Error. -type Error = exec.Error - -// An ExitError reports an unsuccessful exit by a command. -// It is an alias for exec.ExitError. -type ExitError = exec.ExitError - -func relError(file, path string) error { - return fmt.Errorf("%s resolves to executable in current directory (.%c%s)", file, filepath.Separator, path) -} - -// LookPath searches for an executable named file in the directories -// named by the PATH environment variable. If file contains a slash, -// it is tried directly and the PATH is not consulted. The result will be -// an absolute path. -// -// LookPath differs from exec.LookPath in its handling of PATH lookups, -// which are used for file names without slashes. If exec.LookPath's -// PATH lookup would have returned an executable from the current directory, -// LookPath instead returns an error. -func LookPath(file string) (string, error) { - path, err := exec.LookPath(file) - if err != nil && !isGo119ErrDot(err) { - return "", err - } - if filepath.Base(file) == file && !filepath.IsAbs(path) { - return "", relError(file, path) - } - return path, nil -} - -func fixCmd(name string, cmd *exec.Cmd) { - if filepath.Base(name) == name && !filepath.IsAbs(cmd.Path) && !isGo119ErrFieldSet(cmd) { - // exec.Command was called with a bare binary name and - // exec.LookPath returned a path which is not absolute. - // Set cmd.lookPathErr and clear cmd.Path so that it - // cannot be run. - lookPathErr := (*error)(unsafe.Pointer(reflect.ValueOf(cmd).Elem().FieldByName("lookPathErr").Addr().Pointer())) - if *lookPathErr == nil { - *lookPathErr = relError(name, cmd.Path) - } - cmd.Path = "" - } -} - -// CommandContext is like Command but includes a context. -// -// The provided context is used to kill the process (by calling os.Process.Kill) -// if the context becomes done before the command completes on its own. -func CommandContext(ctx context.Context, name string, arg ...string) *exec.Cmd { - cmd := exec.CommandContext(ctx, name, arg...) - fixCmd(name, cmd) - return cmd - -} - -// Command returns the Cmd struct to execute the named program with the given arguments. -// See exec.Command for most details. -// -// Command differs from exec.Command in its handling of PATH lookups, -// which are used when the program name contains no slashes. -// If exec.Command would have returned an exec.Cmd configured to run an -// executable from the current directory, Command instead -// returns an exec.Cmd that will return an error from Start or Run. -func Command(name string, arg ...string) *exec.Cmd { - cmd := exec.Command(name, arg...) - fixCmd(name, cmd) - return cmd -} diff --git a/vendor/golang.org/x/sys/execabs/execabs_go118.go b/vendor/golang.org/x/sys/execabs/execabs_go118.go deleted file mode 100644 index 5627d70e398..00000000000 --- a/vendor/golang.org/x/sys/execabs/execabs_go118.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !go1.19 - -package execabs - -import "os/exec" - -func isGo119ErrDot(err error) bool { - return false -} - -func isGo119ErrFieldSet(cmd *exec.Cmd) bool { - return false -} diff --git a/vendor/golang.org/x/sys/execabs/execabs_go119.go b/vendor/golang.org/x/sys/execabs/execabs_go119.go deleted file mode 100644 index d60ab1b4195..00000000000 --- a/vendor/golang.org/x/sys/execabs/execabs_go119.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build go1.19 - -package execabs - -import ( - "errors" - "os/exec" -) - -func isGo119ErrDot(err error) bool { - return errors.Is(err, exec.ErrDot) -} - -func isGo119ErrFieldSet(cmd *exec.Cmd) bool { - return cmd.Err != nil -} diff --git a/vendor/golang.org/x/tools/LICENSE b/vendor/golang.org/x/tools/LICENSE deleted file mode 100644 index 6a66aea5eaf..00000000000 --- a/vendor/golang.org/x/tools/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2009 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/golang.org/x/tools/PATENTS b/vendor/golang.org/x/tools/PATENTS deleted file mode 100644 index 733099041f8..00000000000 --- a/vendor/golang.org/x/tools/PATENTS +++ /dev/null @@ -1,22 +0,0 @@ -Additional IP Rights Grant (Patents) - -"This implementation" means the copyrightable works distributed by -Google as part of the Go project. - -Google hereby grants to You a perpetual, worldwide, non-exclusive, -no-charge, royalty-free, irrevocable (except as stated in this section) -patent license to make, have made, use, offer to sell, sell, import, -transfer and otherwise run, modify and propagate the contents of this -implementation of Go, where such license applies only to those patent -claims, both currently owned or controlled by Google and acquired in -the future, licensable by Google that are necessarily infringed by this -implementation of Go. This grant does not include claims that would be -infringed only as a consequence of further modification of this -implementation. If you or your agent or exclusive licensee institute or -order or agree to the institution of patent litigation against any -entity (including a cross-claim or counterclaim in a lawsuit) alleging -that this implementation of Go or any code incorporated within this -implementation of Go constitutes direct or contributory patent -infringement, or inducement of patent infringement, then any patent -rights granted to you under this License for this implementation of Go -shall terminate as of the date such litigation is filed. diff --git a/vendor/golang.org/x/tools/cmd/goimports/doc.go b/vendor/golang.org/x/tools/cmd/goimports/doc.go deleted file mode 100644 index 18a3ad448ea..00000000000 --- a/vendor/golang.org/x/tools/cmd/goimports/doc.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* -Command goimports updates your Go import lines, -adding missing ones and removing unreferenced ones. - - $ go install golang.org/x/tools/cmd/goimports@latest - -In addition to fixing imports, goimports also formats -your code in the same style as gofmt so it can be used -as a replacement for your editor's gofmt-on-save hook. - -For emacs, make sure you have the latest go-mode.el: - - https://github.com/dominikh/go-mode.el - -Then in your .emacs file: - - (setq gofmt-command "goimports") - (add-hook 'before-save-hook 'gofmt-before-save) - -For vim, set "gofmt_command" to "goimports": - - https://golang.org/change/39c724dd7f252 - https://golang.org/wiki/IDEsAndTextEditorPlugins - etc - -For GoSublime, follow the steps described here: - - http://michaelwhatcott.com/gosublime-goimports/ - -For other editors, you probably know what to do. - -To exclude directories in your $GOPATH from being scanned for Go -files, goimports respects a configuration file at -$GOPATH/src/.goimportsignore which may contain blank lines, comment -lines (beginning with '#'), or lines naming a directory relative to -the configuration file to ignore when scanning. No globbing or regex -patterns are allowed. Use the "-v" verbose flag to verify it's -working and see what goimports is doing. - -File bugs or feature requests at: - - https://golang.org/issues/new?title=x/tools/cmd/goimports:+ - -Happy hacking! -*/ -package main // import "golang.org/x/tools/cmd/goimports" diff --git a/vendor/golang.org/x/tools/cmd/goimports/goimports.go b/vendor/golang.org/x/tools/cmd/goimports/goimports.go deleted file mode 100644 index b354c9e8241..00000000000 --- a/vendor/golang.org/x/tools/cmd/goimports/goimports.go +++ /dev/null @@ -1,380 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "bufio" - "bytes" - "errors" - "flag" - "fmt" - "go/scanner" - exec "golang.org/x/sys/execabs" - "io" - "io/ioutil" - "log" - "os" - "path/filepath" - "runtime" - "runtime/pprof" - "strings" - - "golang.org/x/tools/internal/gocommand" - "golang.org/x/tools/internal/imports" -) - -var ( - // main operation modes - list = flag.Bool("l", false, "list files whose formatting differs from goimport's") - write = flag.Bool("w", false, "write result to (source) file instead of stdout") - doDiff = flag.Bool("d", false, "display diffs instead of rewriting files") - srcdir = flag.String("srcdir", "", "choose imports as if source code is from `dir`. When operating on a single file, dir may instead be the complete file name.") - - verbose bool // verbose logging - - cpuProfile = flag.String("cpuprofile", "", "CPU profile output") - memProfile = flag.String("memprofile", "", "memory profile output") - memProfileRate = flag.Int("memrate", 0, "if > 0, sets runtime.MemProfileRate") - - options = &imports.Options{ - TabWidth: 8, - TabIndent: true, - Comments: true, - Fragment: true, - Env: &imports.ProcessEnv{ - GocmdRunner: &gocommand.Runner{}, - }, - } - exitCode = 0 -) - -func init() { - flag.BoolVar(&options.AllErrors, "e", false, "report all errors (not just the first 10 on different lines)") - flag.StringVar(&options.LocalPrefix, "local", "", "put imports beginning with this string after 3rd-party packages; comma-separated list") - flag.BoolVar(&options.FormatOnly, "format-only", false, "if true, don't fix imports and only format. In this mode, goimports is effectively gofmt, with the addition that imports are grouped into sections.") -} - -func report(err error) { - scanner.PrintError(os.Stderr, err) - exitCode = 2 -} - -func usage() { - fmt.Fprintf(os.Stderr, "usage: goimports [flags] [path ...]\n") - flag.PrintDefaults() - os.Exit(2) -} - -func isGoFile(f os.FileInfo) bool { - // ignore non-Go files - name := f.Name() - return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") -} - -// argumentType is which mode goimports was invoked as. -type argumentType int - -const ( - // fromStdin means the user is piping their source into goimports. - fromStdin argumentType = iota - - // singleArg is the common case from editors, when goimports is run on - // a single file. - singleArg - - // multipleArg is when the user ran "goimports file1.go file2.go" - // or ran goimports on a directory tree. - multipleArg -) - -func processFile(filename string, in io.Reader, out io.Writer, argType argumentType) error { - opt := options - if argType == fromStdin { - nopt := *options - nopt.Fragment = true - opt = &nopt - } - - if in == nil { - f, err := os.Open(filename) - if err != nil { - return err - } - defer f.Close() - in = f - } - - src, err := ioutil.ReadAll(in) - if err != nil { - return err - } - - target := filename - if *srcdir != "" { - // Determine whether the provided -srcdirc is a directory or file - // and then use it to override the target. - // - // See https://github.com/dominikh/go-mode.el/issues/146 - if isFile(*srcdir) { - if argType == multipleArg { - return errors.New("-srcdir value can't be a file when passing multiple arguments or when walking directories") - } - target = *srcdir - } else if argType == singleArg && strings.HasSuffix(*srcdir, ".go") && !isDir(*srcdir) { - // For a file which doesn't exist on disk yet, but might shortly. - // e.g. user in editor opens $DIR/newfile.go and newfile.go doesn't yet exist on disk. - // The goimports on-save hook writes the buffer to a temp file - // first and runs goimports before the actual save to newfile.go. - // The editor's buffer is named "newfile.go" so that is passed to goimports as: - // goimports -srcdir=/gopath/src/pkg/newfile.go /tmp/gofmtXXXXXXXX.go - // and then the editor reloads the result from the tmp file and writes - // it to newfile.go. - target = *srcdir - } else { - // Pretend that file is from *srcdir in order to decide - // visible imports correctly. - target = filepath.Join(*srcdir, filepath.Base(filename)) - } - } - - res, err := imports.Process(target, src, opt) - if err != nil { - return err - } - - if !bytes.Equal(src, res) { - // formatting has changed - if *list { - fmt.Fprintln(out, filename) - } - if *write { - if argType == fromStdin { - // filename is "" - return errors.New("can't use -w on stdin") - } - // On Windows, we need to re-set the permissions from the file. See golang/go#38225. - var perms os.FileMode - if fi, err := os.Stat(filename); err == nil { - perms = fi.Mode() & os.ModePerm - } - err = ioutil.WriteFile(filename, res, perms) - if err != nil { - return err - } - } - if *doDiff { - if argType == fromStdin { - filename = "stdin.go" // because .orig looks silly - } - data, err := diff(src, res, filename) - if err != nil { - return fmt.Errorf("computing diff: %s", err) - } - fmt.Printf("diff -u %s %s\n", filepath.ToSlash(filename+".orig"), filepath.ToSlash(filename)) - out.Write(data) - } - } - - if !*list && !*write && !*doDiff { - _, err = out.Write(res) - } - - return err -} - -func visitFile(path string, f os.FileInfo, err error) error { - if err == nil && isGoFile(f) { - err = processFile(path, nil, os.Stdout, multipleArg) - } - if err != nil { - report(err) - } - return nil -} - -func walkDir(path string) { - filepath.Walk(path, visitFile) -} - -func main() { - runtime.GOMAXPROCS(runtime.NumCPU()) - - // call gofmtMain in a separate function - // so that it can use defer and have them - // run before the exit. - gofmtMain() - os.Exit(exitCode) -} - -// parseFlags parses command line flags and returns the paths to process. -// It's a var so that custom implementations can replace it in other files. -var parseFlags = func() []string { - flag.BoolVar(&verbose, "v", false, "verbose logging") - - flag.Parse() - return flag.Args() -} - -func bufferedFileWriter(dest string) (w io.Writer, close func()) { - f, err := os.Create(dest) - if err != nil { - log.Fatal(err) - } - bw := bufio.NewWriter(f) - return bw, func() { - if err := bw.Flush(); err != nil { - log.Fatalf("error flushing %v: %v", dest, err) - } - if err := f.Close(); err != nil { - log.Fatal(err) - } - } -} - -func gofmtMain() { - flag.Usage = usage - paths := parseFlags() - - if *cpuProfile != "" { - bw, flush := bufferedFileWriter(*cpuProfile) - pprof.StartCPUProfile(bw) - defer flush() - defer pprof.StopCPUProfile() - } - // doTrace is a conditionally compiled wrapper around runtime/trace. It is - // used to allow goimports to compile under gccgo, which does not support - // runtime/trace. See https://golang.org/issue/15544. - defer doTrace()() - if *memProfileRate > 0 { - runtime.MemProfileRate = *memProfileRate - bw, flush := bufferedFileWriter(*memProfile) - defer func() { - runtime.GC() // materialize all statistics - if err := pprof.WriteHeapProfile(bw); err != nil { - log.Fatal(err) - } - flush() - }() - } - - if verbose { - log.SetFlags(log.LstdFlags | log.Lmicroseconds) - options.Env.Logf = log.Printf - } - if options.TabWidth < 0 { - fmt.Fprintf(os.Stderr, "negative tabwidth %d\n", options.TabWidth) - exitCode = 2 - return - } - - if len(paths) == 0 { - if err := processFile("", os.Stdin, os.Stdout, fromStdin); err != nil { - report(err) - } - return - } - - argType := singleArg - if len(paths) > 1 { - argType = multipleArg - } - - for _, path := range paths { - switch dir, err := os.Stat(path); { - case err != nil: - report(err) - case dir.IsDir(): - walkDir(path) - default: - if err := processFile(path, nil, os.Stdout, argType); err != nil { - report(err) - } - } - } -} - -func writeTempFile(dir, prefix string, data []byte) (string, error) { - file, err := ioutil.TempFile(dir, prefix) - if err != nil { - return "", err - } - _, err = file.Write(data) - if err1 := file.Close(); err == nil { - err = err1 - } - if err != nil { - os.Remove(file.Name()) - return "", err - } - return file.Name(), nil -} - -func diff(b1, b2 []byte, filename string) (data []byte, err error) { - f1, err := writeTempFile("", "gofmt", b1) - if err != nil { - return - } - defer os.Remove(f1) - - f2, err := writeTempFile("", "gofmt", b2) - if err != nil { - return - } - defer os.Remove(f2) - - cmd := "diff" - if runtime.GOOS == "plan9" { - cmd = "/bin/ape/diff" - } - - data, err = exec.Command(cmd, "-u", f1, f2).CombinedOutput() - if len(data) > 0 { - // diff exits with a non-zero status when the files don't match. - // Ignore that failure as long as we get output. - return replaceTempFilename(data, filename) - } - return -} - -// replaceTempFilename replaces temporary filenames in diff with actual one. -// -// --- /tmp/gofmt316145376 2017-02-03 19:13:00.280468375 -0500 -// +++ /tmp/gofmt617882815 2017-02-03 19:13:00.280468375 -0500 -// ... -// -> -// --- path/to/file.go.orig 2017-02-03 19:13:00.280468375 -0500 -// +++ path/to/file.go 2017-02-03 19:13:00.280468375 -0500 -// ... -func replaceTempFilename(diff []byte, filename string) ([]byte, error) { - bs := bytes.SplitN(diff, []byte{'\n'}, 3) - if len(bs) < 3 { - return nil, fmt.Errorf("got unexpected diff for %s", filename) - } - // Preserve timestamps. - var t0, t1 []byte - if i := bytes.LastIndexByte(bs[0], '\t'); i != -1 { - t0 = bs[0][i:] - } - if i := bytes.LastIndexByte(bs[1], '\t'); i != -1 { - t1 = bs[1][i:] - } - // Always print filepath with slash separator. - f := filepath.ToSlash(filename) - bs[0] = []byte(fmt.Sprintf("--- %s%s", f+".orig", t0)) - bs[1] = []byte(fmt.Sprintf("+++ %s%s", f, t1)) - return bytes.Join(bs, []byte{'\n'}), nil -} - -// isFile reports whether name is a file. -func isFile(name string) bool { - fi, err := os.Stat(name) - return err == nil && fi.Mode().IsRegular() -} - -// isDir reports whether name is a directory. -func isDir(name string) bool { - fi, err := os.Stat(name) - return err == nil && fi.IsDir() -} diff --git a/vendor/golang.org/x/tools/cmd/goimports/goimports_gc.go b/vendor/golang.org/x/tools/cmd/goimports/goimports_gc.go deleted file mode 100644 index 190a56535ca..00000000000 --- a/vendor/golang.org/x/tools/cmd/goimports/goimports_gc.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build gc -// +build gc - -package main - -import ( - "flag" - "runtime/trace" -) - -var traceProfile = flag.String("trace", "", "trace profile output") - -func doTrace() func() { - if *traceProfile != "" { - bw, flush := bufferedFileWriter(*traceProfile) - trace.Start(bw) - return func() { - flush() - trace.Stop() - } - } - return func() {} -} diff --git a/vendor/golang.org/x/tools/cmd/goimports/goimports_not_gc.go b/vendor/golang.org/x/tools/cmd/goimports/goimports_not_gc.go deleted file mode 100644 index 344fe7576b0..00000000000 --- a/vendor/golang.org/x/tools/cmd/goimports/goimports_not_gc.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !gc -// +build !gc - -package main - -func doTrace() func() { - return func() {} -} diff --git a/vendor/golang.org/x/tools/go/ast/astutil/enclosing.go b/vendor/golang.org/x/tools/go/ast/astutil/enclosing.go deleted file mode 100644 index 9fa5aa192c2..00000000000 --- a/vendor/golang.org/x/tools/go/ast/astutil/enclosing.go +++ /dev/null @@ -1,636 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package astutil - -// This file defines utilities for working with source positions. - -import ( - "fmt" - "go/ast" - "go/token" - "sort" - - "golang.org/x/tools/internal/typeparams" -) - -// PathEnclosingInterval returns the node that encloses the source -// interval [start, end), and all its ancestors up to the AST root. -// -// The definition of "enclosing" used by this function considers -// additional whitespace abutting a node to be enclosed by it. -// In this example: -// -// z := x + y // add them -// <-A-> -// <----B-----> -// -// the ast.BinaryExpr(+) node is considered to enclose interval B -// even though its [Pos()..End()) is actually only interval A. -// This behaviour makes user interfaces more tolerant of imperfect -// input. -// -// This function treats tokens as nodes, though they are not included -// in the result. e.g. PathEnclosingInterval("+") returns the -// enclosing ast.BinaryExpr("x + y"). -// -// If start==end, the 1-char interval following start is used instead. -// -// The 'exact' result is true if the interval contains only path[0] -// and perhaps some adjacent whitespace. It is false if the interval -// overlaps multiple children of path[0], or if it contains only -// interior whitespace of path[0]. -// In this example: -// -// z := x + y // add them -// <--C--> <---E--> -// ^ -// D -// -// intervals C, D and E are inexact. C is contained by the -// z-assignment statement, because it spans three of its children (:=, -// x, +). So too is the 1-char interval D, because it contains only -// interior whitespace of the assignment. E is considered interior -// whitespace of the BlockStmt containing the assignment. -// -// The resulting path is never empty; it always contains at least the -// 'root' *ast.File. Ideally PathEnclosingInterval would reject -// intervals that lie wholly or partially outside the range of the -// file, but unfortunately ast.File records only the token.Pos of -// the 'package' keyword, but not of the start of the file itself. -func PathEnclosingInterval(root *ast.File, start, end token.Pos) (path []ast.Node, exact bool) { - // fmt.Printf("EnclosingInterval %d %d\n", start, end) // debugging - - // Precondition: node.[Pos..End) and adjoining whitespace contain [start, end). - var visit func(node ast.Node) bool - visit = func(node ast.Node) bool { - path = append(path, node) - - nodePos := node.Pos() - nodeEnd := node.End() - - // fmt.Printf("visit(%T, %d, %d)\n", node, nodePos, nodeEnd) // debugging - - // Intersect [start, end) with interval of node. - if start < nodePos { - start = nodePos - } - if end > nodeEnd { - end = nodeEnd - } - - // Find sole child that contains [start, end). - children := childrenOf(node) - l := len(children) - for i, child := range children { - // [childPos, childEnd) is unaugmented interval of child. - childPos := child.Pos() - childEnd := child.End() - - // [augPos, augEnd) is whitespace-augmented interval of child. - augPos := childPos - augEnd := childEnd - if i > 0 { - augPos = children[i-1].End() // start of preceding whitespace - } - if i < l-1 { - nextChildPos := children[i+1].Pos() - // Does [start, end) lie between child and next child? - if start >= augEnd && end <= nextChildPos { - return false // inexact match - } - augEnd = nextChildPos // end of following whitespace - } - - // fmt.Printf("\tchild %d: [%d..%d)\tcontains interval [%d..%d)?\n", - // i, augPos, augEnd, start, end) // debugging - - // Does augmented child strictly contain [start, end)? - if augPos <= start && end <= augEnd { - _, isToken := child.(tokenNode) - return isToken || visit(child) - } - - // Does [start, end) overlap multiple children? - // i.e. left-augmented child contains start - // but LR-augmented child does not contain end. - if start < childEnd && end > augEnd { - break - } - } - - // No single child contained [start, end), - // so node is the result. Is it exact? - - // (It's tempting to put this condition before the - // child loop, but it gives the wrong result in the - // case where a node (e.g. ExprStmt) and its sole - // child have equal intervals.) - if start == nodePos && end == nodeEnd { - return true // exact match - } - - return false // inexact: overlaps multiple children - } - - // Ensure [start,end) is nondecreasing. - if start > end { - start, end = end, start - } - - if start < root.End() && end > root.Pos() { - if start == end { - end = start + 1 // empty interval => interval of size 1 - } - exact = visit(root) - - // Reverse the path: - for i, l := 0, len(path); i < l/2; i++ { - path[i], path[l-1-i] = path[l-1-i], path[i] - } - } else { - // Selection lies within whitespace preceding the - // first (or following the last) declaration in the file. - // The result nonetheless always includes the ast.File. - path = append(path, root) - } - - return -} - -// tokenNode is a dummy implementation of ast.Node for a single token. -// They are used transiently by PathEnclosingInterval but never escape -// this package. -type tokenNode struct { - pos token.Pos - end token.Pos -} - -func (n tokenNode) Pos() token.Pos { - return n.pos -} - -func (n tokenNode) End() token.Pos { - return n.end -} - -func tok(pos token.Pos, len int) ast.Node { - return tokenNode{pos, pos + token.Pos(len)} -} - -// childrenOf returns the direct non-nil children of ast.Node n. -// It may include fake ast.Node implementations for bare tokens. -// it is not safe to call (e.g.) ast.Walk on such nodes. -func childrenOf(n ast.Node) []ast.Node { - var children []ast.Node - - // First add nodes for all true subtrees. - ast.Inspect(n, func(node ast.Node) bool { - if node == n { // push n - return true // recur - } - if node != nil { // push child - children = append(children, node) - } - return false // no recursion - }) - - // Then add fake Nodes for bare tokens. - switch n := n.(type) { - case *ast.ArrayType: - children = append(children, - tok(n.Lbrack, len("[")), - tok(n.Elt.End(), len("]"))) - - case *ast.AssignStmt: - children = append(children, - tok(n.TokPos, len(n.Tok.String()))) - - case *ast.BasicLit: - children = append(children, - tok(n.ValuePos, len(n.Value))) - - case *ast.BinaryExpr: - children = append(children, tok(n.OpPos, len(n.Op.String()))) - - case *ast.BlockStmt: - children = append(children, - tok(n.Lbrace, len("{")), - tok(n.Rbrace, len("}"))) - - case *ast.BranchStmt: - children = append(children, - tok(n.TokPos, len(n.Tok.String()))) - - case *ast.CallExpr: - children = append(children, - tok(n.Lparen, len("(")), - tok(n.Rparen, len(")"))) - if n.Ellipsis != 0 { - children = append(children, tok(n.Ellipsis, len("..."))) - } - - case *ast.CaseClause: - if n.List == nil { - children = append(children, - tok(n.Case, len("default"))) - } else { - children = append(children, - tok(n.Case, len("case"))) - } - children = append(children, tok(n.Colon, len(":"))) - - case *ast.ChanType: - switch n.Dir { - case ast.RECV: - children = append(children, tok(n.Begin, len("<-chan"))) - case ast.SEND: - children = append(children, tok(n.Begin, len("chan<-"))) - case ast.RECV | ast.SEND: - children = append(children, tok(n.Begin, len("chan"))) - } - - case *ast.CommClause: - if n.Comm == nil { - children = append(children, - tok(n.Case, len("default"))) - } else { - children = append(children, - tok(n.Case, len("case"))) - } - children = append(children, tok(n.Colon, len(":"))) - - case *ast.Comment: - // nop - - case *ast.CommentGroup: - // nop - - case *ast.CompositeLit: - children = append(children, - tok(n.Lbrace, len("{")), - tok(n.Rbrace, len("{"))) - - case *ast.DeclStmt: - // nop - - case *ast.DeferStmt: - children = append(children, - tok(n.Defer, len("defer"))) - - case *ast.Ellipsis: - children = append(children, - tok(n.Ellipsis, len("..."))) - - case *ast.EmptyStmt: - // nop - - case *ast.ExprStmt: - // nop - - case *ast.Field: - // TODO(adonovan): Field.{Doc,Comment,Tag}? - - case *ast.FieldList: - children = append(children, - tok(n.Opening, len("(")), // or len("[") - tok(n.Closing, len(")"))) // or len("]") - - case *ast.File: - // TODO test: Doc - children = append(children, - tok(n.Package, len("package"))) - - case *ast.ForStmt: - children = append(children, - tok(n.For, len("for"))) - - case *ast.FuncDecl: - // TODO(adonovan): FuncDecl.Comment? - - // Uniquely, FuncDecl breaks the invariant that - // preorder traversal yields tokens in lexical order: - // in fact, FuncDecl.Recv precedes FuncDecl.Type.Func. - // - // As a workaround, we inline the case for FuncType - // here and order things correctly. - // - children = nil // discard ast.Walk(FuncDecl) info subtrees - children = append(children, tok(n.Type.Func, len("func"))) - if n.Recv != nil { - children = append(children, n.Recv) - } - children = append(children, n.Name) - if tparams := typeparams.ForFuncType(n.Type); tparams != nil { - children = append(children, tparams) - } - if n.Type.Params != nil { - children = append(children, n.Type.Params) - } - if n.Type.Results != nil { - children = append(children, n.Type.Results) - } - if n.Body != nil { - children = append(children, n.Body) - } - - case *ast.FuncLit: - // nop - - case *ast.FuncType: - if n.Func != 0 { - children = append(children, - tok(n.Func, len("func"))) - } - - case *ast.GenDecl: - children = append(children, - tok(n.TokPos, len(n.Tok.String()))) - if n.Lparen != 0 { - children = append(children, - tok(n.Lparen, len("(")), - tok(n.Rparen, len(")"))) - } - - case *ast.GoStmt: - children = append(children, - tok(n.Go, len("go"))) - - case *ast.Ident: - children = append(children, - tok(n.NamePos, len(n.Name))) - - case *ast.IfStmt: - children = append(children, - tok(n.If, len("if"))) - - case *ast.ImportSpec: - // TODO(adonovan): ImportSpec.{Doc,EndPos}? - - case *ast.IncDecStmt: - children = append(children, - tok(n.TokPos, len(n.Tok.String()))) - - case *ast.IndexExpr: - children = append(children, - tok(n.Lbrack, len("[")), - tok(n.Rbrack, len("]"))) - - case *typeparams.IndexListExpr: - children = append(children, - tok(n.Lbrack, len("[")), - tok(n.Rbrack, len("]"))) - - case *ast.InterfaceType: - children = append(children, - tok(n.Interface, len("interface"))) - - case *ast.KeyValueExpr: - children = append(children, - tok(n.Colon, len(":"))) - - case *ast.LabeledStmt: - children = append(children, - tok(n.Colon, len(":"))) - - case *ast.MapType: - children = append(children, - tok(n.Map, len("map"))) - - case *ast.ParenExpr: - children = append(children, - tok(n.Lparen, len("(")), - tok(n.Rparen, len(")"))) - - case *ast.RangeStmt: - children = append(children, - tok(n.For, len("for")), - tok(n.TokPos, len(n.Tok.String()))) - - case *ast.ReturnStmt: - children = append(children, - tok(n.Return, len("return"))) - - case *ast.SelectStmt: - children = append(children, - tok(n.Select, len("select"))) - - case *ast.SelectorExpr: - // nop - - case *ast.SendStmt: - children = append(children, - tok(n.Arrow, len("<-"))) - - case *ast.SliceExpr: - children = append(children, - tok(n.Lbrack, len("[")), - tok(n.Rbrack, len("]"))) - - case *ast.StarExpr: - children = append(children, tok(n.Star, len("*"))) - - case *ast.StructType: - children = append(children, tok(n.Struct, len("struct"))) - - case *ast.SwitchStmt: - children = append(children, tok(n.Switch, len("switch"))) - - case *ast.TypeAssertExpr: - children = append(children, - tok(n.Lparen-1, len(".")), - tok(n.Lparen, len("(")), - tok(n.Rparen, len(")"))) - - case *ast.TypeSpec: - // TODO(adonovan): TypeSpec.{Doc,Comment}? - - case *ast.TypeSwitchStmt: - children = append(children, tok(n.Switch, len("switch"))) - - case *ast.UnaryExpr: - children = append(children, tok(n.OpPos, len(n.Op.String()))) - - case *ast.ValueSpec: - // TODO(adonovan): ValueSpec.{Doc,Comment}? - - case *ast.BadDecl, *ast.BadExpr, *ast.BadStmt: - // nop - } - - // TODO(adonovan): opt: merge the logic of ast.Inspect() into - // the switch above so we can make interleaved callbacks for - // both Nodes and Tokens in the right order and avoid the need - // to sort. - sort.Sort(byPos(children)) - - return children -} - -type byPos []ast.Node - -func (sl byPos) Len() int { - return len(sl) -} -func (sl byPos) Less(i, j int) bool { - return sl[i].Pos() < sl[j].Pos() -} -func (sl byPos) Swap(i, j int) { - sl[i], sl[j] = sl[j], sl[i] -} - -// NodeDescription returns a description of the concrete type of n suitable -// for a user interface. -// -// TODO(adonovan): in some cases (e.g. Field, FieldList, Ident, -// StarExpr) we could be much more specific given the path to the AST -// root. Perhaps we should do that. -func NodeDescription(n ast.Node) string { - switch n := n.(type) { - case *ast.ArrayType: - return "array type" - case *ast.AssignStmt: - return "assignment" - case *ast.BadDecl: - return "bad declaration" - case *ast.BadExpr: - return "bad expression" - case *ast.BadStmt: - return "bad statement" - case *ast.BasicLit: - return "basic literal" - case *ast.BinaryExpr: - return fmt.Sprintf("binary %s operation", n.Op) - case *ast.BlockStmt: - return "block" - case *ast.BranchStmt: - switch n.Tok { - case token.BREAK: - return "break statement" - case token.CONTINUE: - return "continue statement" - case token.GOTO: - return "goto statement" - case token.FALLTHROUGH: - return "fall-through statement" - } - case *ast.CallExpr: - if len(n.Args) == 1 && !n.Ellipsis.IsValid() { - return "function call (or conversion)" - } - return "function call" - case *ast.CaseClause: - return "case clause" - case *ast.ChanType: - return "channel type" - case *ast.CommClause: - return "communication clause" - case *ast.Comment: - return "comment" - case *ast.CommentGroup: - return "comment group" - case *ast.CompositeLit: - return "composite literal" - case *ast.DeclStmt: - return NodeDescription(n.Decl) + " statement" - case *ast.DeferStmt: - return "defer statement" - case *ast.Ellipsis: - return "ellipsis" - case *ast.EmptyStmt: - return "empty statement" - case *ast.ExprStmt: - return "expression statement" - case *ast.Field: - // Can be any of these: - // struct {x, y int} -- struct field(s) - // struct {T} -- anon struct field - // interface {I} -- interface embedding - // interface {f()} -- interface method - // func (A) func(B) C -- receiver, param(s), result(s) - return "field/method/parameter" - case *ast.FieldList: - return "field/method/parameter list" - case *ast.File: - return "source file" - case *ast.ForStmt: - return "for loop" - case *ast.FuncDecl: - return "function declaration" - case *ast.FuncLit: - return "function literal" - case *ast.FuncType: - return "function type" - case *ast.GenDecl: - switch n.Tok { - case token.IMPORT: - return "import declaration" - case token.CONST: - return "constant declaration" - case token.TYPE: - return "type declaration" - case token.VAR: - return "variable declaration" - } - case *ast.GoStmt: - return "go statement" - case *ast.Ident: - return "identifier" - case *ast.IfStmt: - return "if statement" - case *ast.ImportSpec: - return "import specification" - case *ast.IncDecStmt: - if n.Tok == token.INC { - return "increment statement" - } - return "decrement statement" - case *ast.IndexExpr: - return "index expression" - case *typeparams.IndexListExpr: - return "index list expression" - case *ast.InterfaceType: - return "interface type" - case *ast.KeyValueExpr: - return "key/value association" - case *ast.LabeledStmt: - return "statement label" - case *ast.MapType: - return "map type" - case *ast.Package: - return "package" - case *ast.ParenExpr: - return "parenthesized " + NodeDescription(n.X) - case *ast.RangeStmt: - return "range loop" - case *ast.ReturnStmt: - return "return statement" - case *ast.SelectStmt: - return "select statement" - case *ast.SelectorExpr: - return "selector" - case *ast.SendStmt: - return "channel send" - case *ast.SliceExpr: - return "slice expression" - case *ast.StarExpr: - return "*-operation" // load/store expr or pointer type - case *ast.StructType: - return "struct type" - case *ast.SwitchStmt: - return "switch statement" - case *ast.TypeAssertExpr: - return "type assertion" - case *ast.TypeSpec: - return "type specification" - case *ast.TypeSwitchStmt: - return "type switch" - case *ast.UnaryExpr: - return fmt.Sprintf("unary %s operation", n.Op) - case *ast.ValueSpec: - return "value specification" - - } - panic(fmt.Sprintf("unexpected node type: %T", n)) -} diff --git a/vendor/golang.org/x/tools/go/ast/astutil/imports.go b/vendor/golang.org/x/tools/go/ast/astutil/imports.go deleted file mode 100644 index 18d1adb05dd..00000000000 --- a/vendor/golang.org/x/tools/go/ast/astutil/imports.go +++ /dev/null @@ -1,485 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package astutil contains common utilities for working with the Go AST. -package astutil // import "golang.org/x/tools/go/ast/astutil" - -import ( - "fmt" - "go/ast" - "go/token" - "strconv" - "strings" -) - -// AddImport adds the import path to the file f, if absent. -func AddImport(fset *token.FileSet, f *ast.File, path string) (added bool) { - return AddNamedImport(fset, f, "", path) -} - -// AddNamedImport adds the import with the given name and path to the file f, if absent. -// If name is not empty, it is used to rename the import. -// -// For example, calling -// -// AddNamedImport(fset, f, "pathpkg", "path") -// -// adds -// -// import pathpkg "path" -func AddNamedImport(fset *token.FileSet, f *ast.File, name, path string) (added bool) { - if imports(f, name, path) { - return false - } - - newImport := &ast.ImportSpec{ - Path: &ast.BasicLit{ - Kind: token.STRING, - Value: strconv.Quote(path), - }, - } - if name != "" { - newImport.Name = &ast.Ident{Name: name} - } - - // Find an import decl to add to. - // The goal is to find an existing import - // whose import path has the longest shared - // prefix with path. - var ( - bestMatch = -1 // length of longest shared prefix - lastImport = -1 // index in f.Decls of the file's final import decl - impDecl *ast.GenDecl // import decl containing the best match - impIndex = -1 // spec index in impDecl containing the best match - - isThirdPartyPath = isThirdParty(path) - ) - for i, decl := range f.Decls { - gen, ok := decl.(*ast.GenDecl) - if ok && gen.Tok == token.IMPORT { - lastImport = i - // Do not add to import "C", to avoid disrupting the - // association with its doc comment, breaking cgo. - if declImports(gen, "C") { - continue - } - - // Match an empty import decl if that's all that is available. - if len(gen.Specs) == 0 && bestMatch == -1 { - impDecl = gen - } - - // Compute longest shared prefix with imports in this group and find best - // matched import spec. - // 1. Always prefer import spec with longest shared prefix. - // 2. While match length is 0, - // - for stdlib package: prefer first import spec. - // - for third party package: prefer first third party import spec. - // We cannot use last import spec as best match for third party package - // because grouped imports are usually placed last by goimports -local - // flag. - // See issue #19190. - seenAnyThirdParty := false - for j, spec := range gen.Specs { - impspec := spec.(*ast.ImportSpec) - p := importPath(impspec) - n := matchLen(p, path) - if n > bestMatch || (bestMatch == 0 && !seenAnyThirdParty && isThirdPartyPath) { - bestMatch = n - impDecl = gen - impIndex = j - } - seenAnyThirdParty = seenAnyThirdParty || isThirdParty(p) - } - } - } - - // If no import decl found, add one after the last import. - if impDecl == nil { - impDecl = &ast.GenDecl{ - Tok: token.IMPORT, - } - if lastImport >= 0 { - impDecl.TokPos = f.Decls[lastImport].End() - } else { - // There are no existing imports. - // Our new import, preceded by a blank line, goes after the package declaration - // and after the comment, if any, that starts on the same line as the - // package declaration. - impDecl.TokPos = f.Package - - file := fset.File(f.Package) - pkgLine := file.Line(f.Package) - for _, c := range f.Comments { - if file.Line(c.Pos()) > pkgLine { - break - } - // +2 for a blank line - impDecl.TokPos = c.End() + 2 - } - } - f.Decls = append(f.Decls, nil) - copy(f.Decls[lastImport+2:], f.Decls[lastImport+1:]) - f.Decls[lastImport+1] = impDecl - } - - // Insert new import at insertAt. - insertAt := 0 - if impIndex >= 0 { - // insert after the found import - insertAt = impIndex + 1 - } - impDecl.Specs = append(impDecl.Specs, nil) - copy(impDecl.Specs[insertAt+1:], impDecl.Specs[insertAt:]) - impDecl.Specs[insertAt] = newImport - pos := impDecl.Pos() - if insertAt > 0 { - // If there is a comment after an existing import, preserve the comment - // position by adding the new import after the comment. - if spec, ok := impDecl.Specs[insertAt-1].(*ast.ImportSpec); ok && spec.Comment != nil { - pos = spec.Comment.End() - } else { - // Assign same position as the previous import, - // so that the sorter sees it as being in the same block. - pos = impDecl.Specs[insertAt-1].Pos() - } - } - if newImport.Name != nil { - newImport.Name.NamePos = pos - } - newImport.Path.ValuePos = pos - newImport.EndPos = pos - - // Clean up parens. impDecl contains at least one spec. - if len(impDecl.Specs) == 1 { - // Remove unneeded parens. - impDecl.Lparen = token.NoPos - } else if !impDecl.Lparen.IsValid() { - // impDecl needs parens added. - impDecl.Lparen = impDecl.Specs[0].Pos() - } - - f.Imports = append(f.Imports, newImport) - - if len(f.Decls) <= 1 { - return true - } - - // Merge all the import declarations into the first one. - var first *ast.GenDecl - for i := 0; i < len(f.Decls); i++ { - decl := f.Decls[i] - gen, ok := decl.(*ast.GenDecl) - if !ok || gen.Tok != token.IMPORT || declImports(gen, "C") { - continue - } - if first == nil { - first = gen - continue // Don't touch the first one. - } - // We now know there is more than one package in this import - // declaration. Ensure that it ends up parenthesized. - first.Lparen = first.Pos() - // Move the imports of the other import declaration to the first one. - for _, spec := range gen.Specs { - spec.(*ast.ImportSpec).Path.ValuePos = first.Pos() - first.Specs = append(first.Specs, spec) - } - f.Decls = append(f.Decls[:i], f.Decls[i+1:]...) - i-- - } - - return true -} - -func isThirdParty(importPath string) bool { - // Third party package import path usually contains "." (".com", ".org", ...) - // This logic is taken from golang.org/x/tools/imports package. - return strings.Contains(importPath, ".") -} - -// DeleteImport deletes the import path from the file f, if present. -// If there are duplicate import declarations, all matching ones are deleted. -func DeleteImport(fset *token.FileSet, f *ast.File, path string) (deleted bool) { - return DeleteNamedImport(fset, f, "", path) -} - -// DeleteNamedImport deletes the import with the given name and path from the file f, if present. -// If there are duplicate import declarations, all matching ones are deleted. -func DeleteNamedImport(fset *token.FileSet, f *ast.File, name, path string) (deleted bool) { - var delspecs []*ast.ImportSpec - var delcomments []*ast.CommentGroup - - // Find the import nodes that import path, if any. - for i := 0; i < len(f.Decls); i++ { - decl := f.Decls[i] - gen, ok := decl.(*ast.GenDecl) - if !ok || gen.Tok != token.IMPORT { - continue - } - for j := 0; j < len(gen.Specs); j++ { - spec := gen.Specs[j] - impspec := spec.(*ast.ImportSpec) - if importName(impspec) != name || importPath(impspec) != path { - continue - } - - // We found an import spec that imports path. - // Delete it. - delspecs = append(delspecs, impspec) - deleted = true - copy(gen.Specs[j:], gen.Specs[j+1:]) - gen.Specs = gen.Specs[:len(gen.Specs)-1] - - // If this was the last import spec in this decl, - // delete the decl, too. - if len(gen.Specs) == 0 { - copy(f.Decls[i:], f.Decls[i+1:]) - f.Decls = f.Decls[:len(f.Decls)-1] - i-- - break - } else if len(gen.Specs) == 1 { - if impspec.Doc != nil { - delcomments = append(delcomments, impspec.Doc) - } - if impspec.Comment != nil { - delcomments = append(delcomments, impspec.Comment) - } - for _, cg := range f.Comments { - // Found comment on the same line as the import spec. - if cg.End() < impspec.Pos() && fset.Position(cg.End()).Line == fset.Position(impspec.Pos()).Line { - delcomments = append(delcomments, cg) - break - } - } - - spec := gen.Specs[0].(*ast.ImportSpec) - - // Move the documentation right after the import decl. - if spec.Doc != nil { - for fset.Position(gen.TokPos).Line+1 < fset.Position(spec.Doc.Pos()).Line { - fset.File(gen.TokPos).MergeLine(fset.Position(gen.TokPos).Line) - } - } - for _, cg := range f.Comments { - if cg.End() < spec.Pos() && fset.Position(cg.End()).Line == fset.Position(spec.Pos()).Line { - for fset.Position(gen.TokPos).Line+1 < fset.Position(spec.Pos()).Line { - fset.File(gen.TokPos).MergeLine(fset.Position(gen.TokPos).Line) - } - break - } - } - } - if j > 0 { - lastImpspec := gen.Specs[j-1].(*ast.ImportSpec) - lastLine := fset.PositionFor(lastImpspec.Path.ValuePos, false).Line - line := fset.PositionFor(impspec.Path.ValuePos, false).Line - - // We deleted an entry but now there may be - // a blank line-sized hole where the import was. - if line-lastLine > 1 || !gen.Rparen.IsValid() { - // There was a blank line immediately preceding the deleted import, - // so there's no need to close the hole. The right parenthesis is - // invalid after AddImport to an import statement without parenthesis. - // Do nothing. - } else if line != fset.File(gen.Rparen).LineCount() { - // There was no blank line. Close the hole. - fset.File(gen.Rparen).MergeLine(line) - } - } - j-- - } - } - - // Delete imports from f.Imports. - for i := 0; i < len(f.Imports); i++ { - imp := f.Imports[i] - for j, del := range delspecs { - if imp == del { - copy(f.Imports[i:], f.Imports[i+1:]) - f.Imports = f.Imports[:len(f.Imports)-1] - copy(delspecs[j:], delspecs[j+1:]) - delspecs = delspecs[:len(delspecs)-1] - i-- - break - } - } - } - - // Delete comments from f.Comments. - for i := 0; i < len(f.Comments); i++ { - cg := f.Comments[i] - for j, del := range delcomments { - if cg == del { - copy(f.Comments[i:], f.Comments[i+1:]) - f.Comments = f.Comments[:len(f.Comments)-1] - copy(delcomments[j:], delcomments[j+1:]) - delcomments = delcomments[:len(delcomments)-1] - i-- - break - } - } - } - - if len(delspecs) > 0 { - panic(fmt.Sprintf("deleted specs from Decls but not Imports: %v", delspecs)) - } - - return -} - -// RewriteImport rewrites any import of path oldPath to path newPath. -func RewriteImport(fset *token.FileSet, f *ast.File, oldPath, newPath string) (rewrote bool) { - for _, imp := range f.Imports { - if importPath(imp) == oldPath { - rewrote = true - // record old End, because the default is to compute - // it using the length of imp.Path.Value. - imp.EndPos = imp.End() - imp.Path.Value = strconv.Quote(newPath) - } - } - return -} - -// UsesImport reports whether a given import is used. -func UsesImport(f *ast.File, path string) (used bool) { - spec := importSpec(f, path) - if spec == nil { - return - } - - name := spec.Name.String() - switch name { - case "": - // If the package name is not explicitly specified, - // make an educated guess. This is not guaranteed to be correct. - lastSlash := strings.LastIndex(path, "/") - if lastSlash == -1 { - name = path - } else { - name = path[lastSlash+1:] - } - case "_", ".": - // Not sure if this import is used - err on the side of caution. - return true - } - - ast.Walk(visitFn(func(n ast.Node) { - sel, ok := n.(*ast.SelectorExpr) - if ok && isTopName(sel.X, name) { - used = true - } - }), f) - - return -} - -type visitFn func(node ast.Node) - -func (fn visitFn) Visit(node ast.Node) ast.Visitor { - fn(node) - return fn -} - -// imports reports whether f has an import with the specified name and path. -func imports(f *ast.File, name, path string) bool { - for _, s := range f.Imports { - if importName(s) == name && importPath(s) == path { - return true - } - } - return false -} - -// importSpec returns the import spec if f imports path, -// or nil otherwise. -func importSpec(f *ast.File, path string) *ast.ImportSpec { - for _, s := range f.Imports { - if importPath(s) == path { - return s - } - } - return nil -} - -// importName returns the name of s, -// or "" if the import is not named. -func importName(s *ast.ImportSpec) string { - if s.Name == nil { - return "" - } - return s.Name.Name -} - -// importPath returns the unquoted import path of s, -// or "" if the path is not properly quoted. -func importPath(s *ast.ImportSpec) string { - t, err := strconv.Unquote(s.Path.Value) - if err != nil { - return "" - } - return t -} - -// declImports reports whether gen contains an import of path. -func declImports(gen *ast.GenDecl, path string) bool { - if gen.Tok != token.IMPORT { - return false - } - for _, spec := range gen.Specs { - impspec := spec.(*ast.ImportSpec) - if importPath(impspec) == path { - return true - } - } - return false -} - -// matchLen returns the length of the longest path segment prefix shared by x and y. -func matchLen(x, y string) int { - n := 0 - for i := 0; i < len(x) && i < len(y) && x[i] == y[i]; i++ { - if x[i] == '/' { - n++ - } - } - return n -} - -// isTopName returns true if n is a top-level unresolved identifier with the given name. -func isTopName(n ast.Expr, name string) bool { - id, ok := n.(*ast.Ident) - return ok && id.Name == name && id.Obj == nil -} - -// Imports returns the file imports grouped by paragraph. -func Imports(fset *token.FileSet, f *ast.File) [][]*ast.ImportSpec { - var groups [][]*ast.ImportSpec - - for _, decl := range f.Decls { - genDecl, ok := decl.(*ast.GenDecl) - if !ok || genDecl.Tok != token.IMPORT { - break - } - - group := []*ast.ImportSpec{} - - var lastLine int - for _, spec := range genDecl.Specs { - importSpec := spec.(*ast.ImportSpec) - pos := importSpec.Path.ValuePos - line := fset.Position(pos).Line - if lastLine > 0 && pos > 0 && line-lastLine > 1 { - groups = append(groups, group) - group = []*ast.ImportSpec{} - } - group = append(group, importSpec) - lastLine = line - } - groups = append(groups, group) - } - - return groups -} diff --git a/vendor/golang.org/x/tools/go/ast/astutil/rewrite.go b/vendor/golang.org/x/tools/go/ast/astutil/rewrite.go deleted file mode 100644 index f430b21b9b9..00000000000 --- a/vendor/golang.org/x/tools/go/ast/astutil/rewrite.go +++ /dev/null @@ -1,488 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package astutil - -import ( - "fmt" - "go/ast" - "reflect" - "sort" - - "golang.org/x/tools/internal/typeparams" -) - -// An ApplyFunc is invoked by Apply for each node n, even if n is nil, -// before and/or after the node's children, using a Cursor describing -// the current node and providing operations on it. -// -// The return value of ApplyFunc controls the syntax tree traversal. -// See Apply for details. -type ApplyFunc func(*Cursor) bool - -// Apply traverses a syntax tree recursively, starting with root, -// and calling pre and post for each node as described below. -// Apply returns the syntax tree, possibly modified. -// -// If pre is not nil, it is called for each node before the node's -// children are traversed (pre-order). If pre returns false, no -// children are traversed, and post is not called for that node. -// -// If post is not nil, and a prior call of pre didn't return false, -// post is called for each node after its children are traversed -// (post-order). If post returns false, traversal is terminated and -// Apply returns immediately. -// -// Only fields that refer to AST nodes are considered children; -// i.e., token.Pos, Scopes, Objects, and fields of basic types -// (strings, etc.) are ignored. -// -// Children are traversed in the order in which they appear in the -// respective node's struct definition. A package's files are -// traversed in the filenames' alphabetical order. -func Apply(root ast.Node, pre, post ApplyFunc) (result ast.Node) { - parent := &struct{ ast.Node }{root} - defer func() { - if r := recover(); r != nil && r != abort { - panic(r) - } - result = parent.Node - }() - a := &application{pre: pre, post: post} - a.apply(parent, "Node", nil, root) - return -} - -var abort = new(int) // singleton, to signal termination of Apply - -// A Cursor describes a node encountered during Apply. -// Information about the node and its parent is available -// from the Node, Parent, Name, and Index methods. -// -// If p is a variable of type and value of the current parent node -// c.Parent(), and f is the field identifier with name c.Name(), -// the following invariants hold: -// -// p.f == c.Node() if c.Index() < 0 -// p.f[c.Index()] == c.Node() if c.Index() >= 0 -// -// The methods Replace, Delete, InsertBefore, and InsertAfter -// can be used to change the AST without disrupting Apply. -type Cursor struct { - parent ast.Node - name string - iter *iterator // valid if non-nil - node ast.Node -} - -// Node returns the current Node. -func (c *Cursor) Node() ast.Node { return c.node } - -// Parent returns the parent of the current Node. -func (c *Cursor) Parent() ast.Node { return c.parent } - -// Name returns the name of the parent Node field that contains the current Node. -// If the parent is a *ast.Package and the current Node is a *ast.File, Name returns -// the filename for the current Node. -func (c *Cursor) Name() string { return c.name } - -// Index reports the index >= 0 of the current Node in the slice of Nodes that -// contains it, or a value < 0 if the current Node is not part of a slice. -// The index of the current node changes if InsertBefore is called while -// processing the current node. -func (c *Cursor) Index() int { - if c.iter != nil { - return c.iter.index - } - return -1 -} - -// field returns the current node's parent field value. -func (c *Cursor) field() reflect.Value { - return reflect.Indirect(reflect.ValueOf(c.parent)).FieldByName(c.name) -} - -// Replace replaces the current Node with n. -// The replacement node is not walked by Apply. -func (c *Cursor) Replace(n ast.Node) { - if _, ok := c.node.(*ast.File); ok { - file, ok := n.(*ast.File) - if !ok { - panic("attempt to replace *ast.File with non-*ast.File") - } - c.parent.(*ast.Package).Files[c.name] = file - return - } - - v := c.field() - if i := c.Index(); i >= 0 { - v = v.Index(i) - } - v.Set(reflect.ValueOf(n)) -} - -// Delete deletes the current Node from its containing slice. -// If the current Node is not part of a slice, Delete panics. -// As a special case, if the current node is a package file, -// Delete removes it from the package's Files map. -func (c *Cursor) Delete() { - if _, ok := c.node.(*ast.File); ok { - delete(c.parent.(*ast.Package).Files, c.name) - return - } - - i := c.Index() - if i < 0 { - panic("Delete node not contained in slice") - } - v := c.field() - l := v.Len() - reflect.Copy(v.Slice(i, l), v.Slice(i+1, l)) - v.Index(l - 1).Set(reflect.Zero(v.Type().Elem())) - v.SetLen(l - 1) - c.iter.step-- -} - -// InsertAfter inserts n after the current Node in its containing slice. -// If the current Node is not part of a slice, InsertAfter panics. -// Apply does not walk n. -func (c *Cursor) InsertAfter(n ast.Node) { - i := c.Index() - if i < 0 { - panic("InsertAfter node not contained in slice") - } - v := c.field() - v.Set(reflect.Append(v, reflect.Zero(v.Type().Elem()))) - l := v.Len() - reflect.Copy(v.Slice(i+2, l), v.Slice(i+1, l)) - v.Index(i + 1).Set(reflect.ValueOf(n)) - c.iter.step++ -} - -// InsertBefore inserts n before the current Node in its containing slice. -// If the current Node is not part of a slice, InsertBefore panics. -// Apply will not walk n. -func (c *Cursor) InsertBefore(n ast.Node) { - i := c.Index() - if i < 0 { - panic("InsertBefore node not contained in slice") - } - v := c.field() - v.Set(reflect.Append(v, reflect.Zero(v.Type().Elem()))) - l := v.Len() - reflect.Copy(v.Slice(i+1, l), v.Slice(i, l)) - v.Index(i).Set(reflect.ValueOf(n)) - c.iter.index++ -} - -// application carries all the shared data so we can pass it around cheaply. -type application struct { - pre, post ApplyFunc - cursor Cursor - iter iterator -} - -func (a *application) apply(parent ast.Node, name string, iter *iterator, n ast.Node) { - // convert typed nil into untyped nil - if v := reflect.ValueOf(n); v.Kind() == reflect.Ptr && v.IsNil() { - n = nil - } - - // avoid heap-allocating a new cursor for each apply call; reuse a.cursor instead - saved := a.cursor - a.cursor.parent = parent - a.cursor.name = name - a.cursor.iter = iter - a.cursor.node = n - - if a.pre != nil && !a.pre(&a.cursor) { - a.cursor = saved - return - } - - // walk children - // (the order of the cases matches the order of the corresponding node types in go/ast) - switch n := n.(type) { - case nil: - // nothing to do - - // Comments and fields - case *ast.Comment: - // nothing to do - - case *ast.CommentGroup: - if n != nil { - a.applyList(n, "List") - } - - case *ast.Field: - a.apply(n, "Doc", nil, n.Doc) - a.applyList(n, "Names") - a.apply(n, "Type", nil, n.Type) - a.apply(n, "Tag", nil, n.Tag) - a.apply(n, "Comment", nil, n.Comment) - - case *ast.FieldList: - a.applyList(n, "List") - - // Expressions - case *ast.BadExpr, *ast.Ident, *ast.BasicLit: - // nothing to do - - case *ast.Ellipsis: - a.apply(n, "Elt", nil, n.Elt) - - case *ast.FuncLit: - a.apply(n, "Type", nil, n.Type) - a.apply(n, "Body", nil, n.Body) - - case *ast.CompositeLit: - a.apply(n, "Type", nil, n.Type) - a.applyList(n, "Elts") - - case *ast.ParenExpr: - a.apply(n, "X", nil, n.X) - - case *ast.SelectorExpr: - a.apply(n, "X", nil, n.X) - a.apply(n, "Sel", nil, n.Sel) - - case *ast.IndexExpr: - a.apply(n, "X", nil, n.X) - a.apply(n, "Index", nil, n.Index) - - case *typeparams.IndexListExpr: - a.apply(n, "X", nil, n.X) - a.applyList(n, "Indices") - - case *ast.SliceExpr: - a.apply(n, "X", nil, n.X) - a.apply(n, "Low", nil, n.Low) - a.apply(n, "High", nil, n.High) - a.apply(n, "Max", nil, n.Max) - - case *ast.TypeAssertExpr: - a.apply(n, "X", nil, n.X) - a.apply(n, "Type", nil, n.Type) - - case *ast.CallExpr: - a.apply(n, "Fun", nil, n.Fun) - a.applyList(n, "Args") - - case *ast.StarExpr: - a.apply(n, "X", nil, n.X) - - case *ast.UnaryExpr: - a.apply(n, "X", nil, n.X) - - case *ast.BinaryExpr: - a.apply(n, "X", nil, n.X) - a.apply(n, "Y", nil, n.Y) - - case *ast.KeyValueExpr: - a.apply(n, "Key", nil, n.Key) - a.apply(n, "Value", nil, n.Value) - - // Types - case *ast.ArrayType: - a.apply(n, "Len", nil, n.Len) - a.apply(n, "Elt", nil, n.Elt) - - case *ast.StructType: - a.apply(n, "Fields", nil, n.Fields) - - case *ast.FuncType: - if tparams := typeparams.ForFuncType(n); tparams != nil { - a.apply(n, "TypeParams", nil, tparams) - } - a.apply(n, "Params", nil, n.Params) - a.apply(n, "Results", nil, n.Results) - - case *ast.InterfaceType: - a.apply(n, "Methods", nil, n.Methods) - - case *ast.MapType: - a.apply(n, "Key", nil, n.Key) - a.apply(n, "Value", nil, n.Value) - - case *ast.ChanType: - a.apply(n, "Value", nil, n.Value) - - // Statements - case *ast.BadStmt: - // nothing to do - - case *ast.DeclStmt: - a.apply(n, "Decl", nil, n.Decl) - - case *ast.EmptyStmt: - // nothing to do - - case *ast.LabeledStmt: - a.apply(n, "Label", nil, n.Label) - a.apply(n, "Stmt", nil, n.Stmt) - - case *ast.ExprStmt: - a.apply(n, "X", nil, n.X) - - case *ast.SendStmt: - a.apply(n, "Chan", nil, n.Chan) - a.apply(n, "Value", nil, n.Value) - - case *ast.IncDecStmt: - a.apply(n, "X", nil, n.X) - - case *ast.AssignStmt: - a.applyList(n, "Lhs") - a.applyList(n, "Rhs") - - case *ast.GoStmt: - a.apply(n, "Call", nil, n.Call) - - case *ast.DeferStmt: - a.apply(n, "Call", nil, n.Call) - - case *ast.ReturnStmt: - a.applyList(n, "Results") - - case *ast.BranchStmt: - a.apply(n, "Label", nil, n.Label) - - case *ast.BlockStmt: - a.applyList(n, "List") - - case *ast.IfStmt: - a.apply(n, "Init", nil, n.Init) - a.apply(n, "Cond", nil, n.Cond) - a.apply(n, "Body", nil, n.Body) - a.apply(n, "Else", nil, n.Else) - - case *ast.CaseClause: - a.applyList(n, "List") - a.applyList(n, "Body") - - case *ast.SwitchStmt: - a.apply(n, "Init", nil, n.Init) - a.apply(n, "Tag", nil, n.Tag) - a.apply(n, "Body", nil, n.Body) - - case *ast.TypeSwitchStmt: - a.apply(n, "Init", nil, n.Init) - a.apply(n, "Assign", nil, n.Assign) - a.apply(n, "Body", nil, n.Body) - - case *ast.CommClause: - a.apply(n, "Comm", nil, n.Comm) - a.applyList(n, "Body") - - case *ast.SelectStmt: - a.apply(n, "Body", nil, n.Body) - - case *ast.ForStmt: - a.apply(n, "Init", nil, n.Init) - a.apply(n, "Cond", nil, n.Cond) - a.apply(n, "Post", nil, n.Post) - a.apply(n, "Body", nil, n.Body) - - case *ast.RangeStmt: - a.apply(n, "Key", nil, n.Key) - a.apply(n, "Value", nil, n.Value) - a.apply(n, "X", nil, n.X) - a.apply(n, "Body", nil, n.Body) - - // Declarations - case *ast.ImportSpec: - a.apply(n, "Doc", nil, n.Doc) - a.apply(n, "Name", nil, n.Name) - a.apply(n, "Path", nil, n.Path) - a.apply(n, "Comment", nil, n.Comment) - - case *ast.ValueSpec: - a.apply(n, "Doc", nil, n.Doc) - a.applyList(n, "Names") - a.apply(n, "Type", nil, n.Type) - a.applyList(n, "Values") - a.apply(n, "Comment", nil, n.Comment) - - case *ast.TypeSpec: - a.apply(n, "Doc", nil, n.Doc) - a.apply(n, "Name", nil, n.Name) - if tparams := typeparams.ForTypeSpec(n); tparams != nil { - a.apply(n, "TypeParams", nil, tparams) - } - a.apply(n, "Type", nil, n.Type) - a.apply(n, "Comment", nil, n.Comment) - - case *ast.BadDecl: - // nothing to do - - case *ast.GenDecl: - a.apply(n, "Doc", nil, n.Doc) - a.applyList(n, "Specs") - - case *ast.FuncDecl: - a.apply(n, "Doc", nil, n.Doc) - a.apply(n, "Recv", nil, n.Recv) - a.apply(n, "Name", nil, n.Name) - a.apply(n, "Type", nil, n.Type) - a.apply(n, "Body", nil, n.Body) - - // Files and packages - case *ast.File: - a.apply(n, "Doc", nil, n.Doc) - a.apply(n, "Name", nil, n.Name) - a.applyList(n, "Decls") - // Don't walk n.Comments; they have either been walked already if - // they are Doc comments, or they can be easily walked explicitly. - - case *ast.Package: - // collect and sort names for reproducible behavior - var names []string - for name := range n.Files { - names = append(names, name) - } - sort.Strings(names) - for _, name := range names { - a.apply(n, name, nil, n.Files[name]) - } - - default: - panic(fmt.Sprintf("Apply: unexpected node type %T", n)) - } - - if a.post != nil && !a.post(&a.cursor) { - panic(abort) - } - - a.cursor = saved -} - -// An iterator controls iteration over a slice of nodes. -type iterator struct { - index, step int -} - -func (a *application) applyList(parent ast.Node, name string) { - // avoid heap-allocating a new iterator for each applyList call; reuse a.iter instead - saved := a.iter - a.iter.index = 0 - for { - // must reload parent.name each time, since cursor modifications might change it - v := reflect.Indirect(reflect.ValueOf(parent)).FieldByName(name) - if a.iter.index >= v.Len() { - break - } - - // element x may be nil in a bad AST - be cautious - var x ast.Node - if e := v.Index(a.iter.index); e.IsValid() { - x = e.Interface().(ast.Node) - } - - a.iter.step = 1 - a.apply(parent, name, &a.iter, x) - a.iter.index += a.iter.step - } - a.iter = saved -} diff --git a/vendor/golang.org/x/tools/go/ast/astutil/util.go b/vendor/golang.org/x/tools/go/ast/astutil/util.go deleted file mode 100644 index 919d5305ab4..00000000000 --- a/vendor/golang.org/x/tools/go/ast/astutil/util.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package astutil - -import "go/ast" - -// Unparen returns e with any enclosing parentheses stripped. -func Unparen(e ast.Expr) ast.Expr { - for { - p, ok := e.(*ast.ParenExpr) - if !ok { - return e - } - e = p.X - } -} diff --git a/vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go b/vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go deleted file mode 100644 index 165ede0f8f3..00000000000 --- a/vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package gcexportdata provides functions for locating, reading, and -// writing export data files containing type information produced by the -// gc compiler. This package supports go1.7 export data format and all -// later versions. -// -// Although it might seem convenient for this package to live alongside -// go/types in the standard library, this would cause version skew -// problems for developer tools that use it, since they must be able to -// consume the outputs of the gc compiler both before and after a Go -// update such as from Go 1.7 to Go 1.8. Because this package lives in -// golang.org/x/tools, sites can update their version of this repo some -// time before the Go 1.8 release and rebuild and redeploy their -// developer tools, which will then be able to consume both Go 1.7 and -// Go 1.8 export data files, so they will work before and after the -// Go update. (See discussion at https://golang.org/issue/15651.) -package gcexportdata // import "golang.org/x/tools/go/gcexportdata" - -import ( - "bufio" - "bytes" - "encoding/json" - "fmt" - "go/token" - "go/types" - "io" - "os/exec" - - "golang.org/x/tools/internal/gcimporter" -) - -// Find returns the name of an object (.o) or archive (.a) file -// containing type information for the specified import path, -// using the go command. -// If no file was found, an empty filename is returned. -// -// A relative srcDir is interpreted relative to the current working directory. -// -// Find also returns the package's resolved (canonical) import path, -// reflecting the effects of srcDir and vendoring on importPath. -// -// Deprecated: Use the higher-level API in golang.org/x/tools/go/packages, -// which is more efficient. -func Find(importPath, srcDir string) (filename, path string) { - cmd := exec.Command("go", "list", "-json", "-export", "--", importPath) - cmd.Dir = srcDir - out, err := cmd.CombinedOutput() - if err != nil { - return "", "" - } - var data struct { - ImportPath string - Export string - } - json.Unmarshal(out, &data) - return data.Export, data.ImportPath -} - -// NewReader returns a reader for the export data section of an object -// (.o) or archive (.a) file read from r. The new reader may provide -// additional trailing data beyond the end of the export data. -func NewReader(r io.Reader) (io.Reader, error) { - buf := bufio.NewReader(r) - _, size, err := gcimporter.FindExportData(buf) - if err != nil { - return nil, err - } - - if size >= 0 { - // We were given an archive and found the __.PKGDEF in it. - // This tells us the size of the export data, and we don't - // need to return the entire file. - return &io.LimitedReader{ - R: buf, - N: size, - }, nil - } else { - // We were given an object file. As such, we don't know how large - // the export data is and must return the entire file. - return buf, nil - } -} - -// readAll works the same way as io.ReadAll, but avoids allocations and copies -// by preallocating a byte slice of the necessary size if the size is known up -// front. This is always possible when the input is an archive. In that case, -// NewReader will return the known size using an io.LimitedReader. -func readAll(r io.Reader) ([]byte, error) { - if lr, ok := r.(*io.LimitedReader); ok { - data := make([]byte, lr.N) - _, err := io.ReadFull(lr, data) - return data, err - } - return io.ReadAll(r) -} - -// Read reads export data from in, decodes it, and returns type -// information for the package. -// -// The package path (effectively its linker symbol prefix) is -// specified by path, since unlike the package name, this information -// may not be recorded in the export data. -// -// File position information is added to fset. -// -// Read may inspect and add to the imports map to ensure that references -// within the export data to other packages are consistent. The caller -// must ensure that imports[path] does not exist, or exists but is -// incomplete (see types.Package.Complete), and Read inserts the -// resulting package into this map entry. -// -// On return, the state of the reader is undefined. -func Read(in io.Reader, fset *token.FileSet, imports map[string]*types.Package, path string) (*types.Package, error) { - data, err := readAll(in) - if err != nil { - return nil, fmt.Errorf("reading export data for %q: %v", path, err) - } - - if bytes.HasPrefix(data, []byte("!")) { - return nil, fmt.Errorf("can't read export data for %q directly from an archive file (call gcexportdata.NewReader first to extract export data)", path) - } - - // The indexed export format starts with an 'i'; the older - // binary export format starts with a 'c', 'd', or 'v' - // (from "version"). Select appropriate importer. - if len(data) > 0 { - switch data[0] { - case 'i': - _, pkg, err := gcimporter.IImportData(fset, imports, data[1:], path) - return pkg, err - - case 'v', 'c', 'd': - _, pkg, err := gcimporter.BImportData(fset, imports, data, path) - return pkg, err - - case 'u': - _, pkg, err := gcimporter.UImportData(fset, imports, data[1:], path) - return pkg, err - - default: - l := len(data) - if l > 10 { - l = 10 - } - return nil, fmt.Errorf("unexpected export data with prefix %q for path %s", string(data[:l]), path) - } - } - return nil, fmt.Errorf("empty export data for %s", path) -} - -// Write writes encoded type information for the specified package to out. -// The FileSet provides file position information for named objects. -func Write(out io.Writer, fset *token.FileSet, pkg *types.Package) error { - if _, err := io.WriteString(out, "i"); err != nil { - return err - } - return gcimporter.IExportData(out, fset, pkg) -} - -// ReadBundle reads an export bundle from in, decodes it, and returns type -// information for the packages. -// File position information is added to fset. -// -// ReadBundle may inspect and add to the imports map to ensure that references -// within the export bundle to other packages are consistent. -// -// On return, the state of the reader is undefined. -// -// Experimental: This API is experimental and may change in the future. -func ReadBundle(in io.Reader, fset *token.FileSet, imports map[string]*types.Package) ([]*types.Package, error) { - data, err := readAll(in) - if err != nil { - return nil, fmt.Errorf("reading export bundle: %v", err) - } - return gcimporter.IImportBundle(fset, imports, data) -} - -// WriteBundle writes encoded type information for the specified packages to out. -// The FileSet provides file position information for named objects. -// -// Experimental: This API is experimental and may change in the future. -func WriteBundle(out io.Writer, fset *token.FileSet, pkgs []*types.Package) error { - return gcimporter.IExportBundle(out, fset, pkgs) -} diff --git a/vendor/golang.org/x/tools/go/gcexportdata/importer.go b/vendor/golang.org/x/tools/go/gcexportdata/importer.go deleted file mode 100644 index 37a7247e268..00000000000 --- a/vendor/golang.org/x/tools/go/gcexportdata/importer.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package gcexportdata - -import ( - "fmt" - "go/token" - "go/types" - "os" -) - -// NewImporter returns a new instance of the types.Importer interface -// that reads type information from export data files written by gc. -// The Importer also satisfies types.ImporterFrom. -// -// Export data files are located using "go build" workspace conventions -// and the build.Default context. -// -// Use this importer instead of go/importer.For("gc", ...) to avoid the -// version-skew problems described in the documentation of this package, -// or to control the FileSet or access the imports map populated during -// package loading. -// -// Deprecated: Use the higher-level API in golang.org/x/tools/go/packages, -// which is more efficient. -func NewImporter(fset *token.FileSet, imports map[string]*types.Package) types.ImporterFrom { - return importer{fset, imports} -} - -type importer struct { - fset *token.FileSet - imports map[string]*types.Package -} - -func (imp importer) Import(importPath string) (*types.Package, error) { - return imp.ImportFrom(importPath, "", 0) -} - -func (imp importer) ImportFrom(importPath, srcDir string, mode types.ImportMode) (_ *types.Package, err error) { - filename, path := Find(importPath, srcDir) - if filename == "" { - if importPath == "unsafe" { - // Even for unsafe, call Find first in case - // the package was vendored. - return types.Unsafe, nil - } - return nil, fmt.Errorf("can't find import: %s", importPath) - } - - if pkg, ok := imp.imports[path]; ok && pkg.Complete() { - return pkg, nil // cache hit - } - - // open file - f, err := os.Open(filename) - if err != nil { - return nil, err - } - defer func() { - f.Close() - if err != nil { - // add file name to error - err = fmt.Errorf("reading export data: %s: %v", filename, err) - } - }() - - r, err := NewReader(f) - if err != nil { - return nil, err - } - - return Read(r, imp.fset, imp.imports, path) -} diff --git a/vendor/golang.org/x/tools/internal/event/core/event.go b/vendor/golang.org/x/tools/internal/event/core/event.go deleted file mode 100644 index a6cf0e64a4b..00000000000 --- a/vendor/golang.org/x/tools/internal/event/core/event.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package core provides support for event based telemetry. -package core - -import ( - "fmt" - "time" - - "golang.org/x/tools/internal/event/label" -) - -// Event holds the information about an event of note that occurred. -type Event struct { - at time.Time - - // As events are often on the stack, storing the first few labels directly - // in the event can avoid an allocation at all for the very common cases of - // simple events. - // The length needs to be large enough to cope with the majority of events - // but no so large as to cause undue stack pressure. - // A log message with two values will use 3 labels (one for each value and - // one for the message itself). - - static [3]label.Label // inline storage for the first few labels - dynamic []label.Label // dynamically sized storage for remaining labels -} - -// eventLabelMap implements label.Map for a the labels of an Event. -type eventLabelMap struct { - event Event -} - -func (ev Event) At() time.Time { return ev.at } - -func (ev Event) Format(f fmt.State, r rune) { - if !ev.at.IsZero() { - fmt.Fprint(f, ev.at.Format("2006/01/02 15:04:05 ")) - } - for index := 0; ev.Valid(index); index++ { - if l := ev.Label(index); l.Valid() { - fmt.Fprintf(f, "\n\t%v", l) - } - } -} - -func (ev Event) Valid(index int) bool { - return index >= 0 && index < len(ev.static)+len(ev.dynamic) -} - -func (ev Event) Label(index int) label.Label { - if index < len(ev.static) { - return ev.static[index] - } - return ev.dynamic[index-len(ev.static)] -} - -func (ev Event) Find(key label.Key) label.Label { - for _, l := range ev.static { - if l.Key() == key { - return l - } - } - for _, l := range ev.dynamic { - if l.Key() == key { - return l - } - } - return label.Label{} -} - -func MakeEvent(static [3]label.Label, labels []label.Label) Event { - return Event{ - static: static, - dynamic: labels, - } -} - -// CloneEvent event returns a copy of the event with the time adjusted to at. -func CloneEvent(ev Event, at time.Time) Event { - ev.at = at - return ev -} diff --git a/vendor/golang.org/x/tools/internal/event/core/export.go b/vendor/golang.org/x/tools/internal/event/core/export.go deleted file mode 100644 index 05f3a9a5791..00000000000 --- a/vendor/golang.org/x/tools/internal/event/core/export.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package core - -import ( - "context" - "sync/atomic" - "time" - "unsafe" - - "golang.org/x/tools/internal/event/label" -) - -// Exporter is a function that handles events. -// It may return a modified context and event. -type Exporter func(context.Context, Event, label.Map) context.Context - -var ( - exporter unsafe.Pointer -) - -// SetExporter sets the global exporter function that handles all events. -// The exporter is called synchronously from the event call site, so it should -// return quickly so as not to hold up user code. -func SetExporter(e Exporter) { - p := unsafe.Pointer(&e) - if e == nil { - // &e is always valid, and so p is always valid, but for the early abort - // of ProcessEvent to be efficient it needs to make the nil check on the - // pointer without having to dereference it, so we make the nil function - // also a nil pointer - p = nil - } - atomic.StorePointer(&exporter, p) -} - -// deliver is called to deliver an event to the supplied exporter. -// it will fill in the time. -func deliver(ctx context.Context, exporter Exporter, ev Event) context.Context { - // add the current time to the event - ev.at = time.Now() - // hand the event off to the current exporter - return exporter(ctx, ev, ev) -} - -// Export is called to deliver an event to the global exporter if set. -func Export(ctx context.Context, ev Event) context.Context { - // get the global exporter and abort early if there is not one - exporterPtr := (*Exporter)(atomic.LoadPointer(&exporter)) - if exporterPtr == nil { - return ctx - } - return deliver(ctx, *exporterPtr, ev) -} - -// ExportPair is called to deliver a start event to the supplied exporter. -// It also returns a function that will deliver the end event to the same -// exporter. -// It will fill in the time. -func ExportPair(ctx context.Context, begin, end Event) (context.Context, func()) { - // get the global exporter and abort early if there is not one - exporterPtr := (*Exporter)(atomic.LoadPointer(&exporter)) - if exporterPtr == nil { - return ctx, func() {} - } - ctx = deliver(ctx, *exporterPtr, begin) - return ctx, func() { deliver(ctx, *exporterPtr, end) } -} diff --git a/vendor/golang.org/x/tools/internal/event/core/fast.go b/vendor/golang.org/x/tools/internal/event/core/fast.go deleted file mode 100644 index 06c1d4615e6..00000000000 --- a/vendor/golang.org/x/tools/internal/event/core/fast.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package core - -import ( - "context" - - "golang.org/x/tools/internal/event/keys" - "golang.org/x/tools/internal/event/label" -) - -// Log1 takes a message and one label delivers a log event to the exporter. -// It is a customized version of Print that is faster and does no allocation. -func Log1(ctx context.Context, message string, t1 label.Label) { - Export(ctx, MakeEvent([3]label.Label{ - keys.Msg.Of(message), - t1, - }, nil)) -} - -// Log2 takes a message and two labels and delivers a log event to the exporter. -// It is a customized version of Print that is faster and does no allocation. -func Log2(ctx context.Context, message string, t1 label.Label, t2 label.Label) { - Export(ctx, MakeEvent([3]label.Label{ - keys.Msg.Of(message), - t1, - t2, - }, nil)) -} - -// Metric1 sends a label event to the exporter with the supplied labels. -func Metric1(ctx context.Context, t1 label.Label) context.Context { - return Export(ctx, MakeEvent([3]label.Label{ - keys.Metric.New(), - t1, - }, nil)) -} - -// Metric2 sends a label event to the exporter with the supplied labels. -func Metric2(ctx context.Context, t1, t2 label.Label) context.Context { - return Export(ctx, MakeEvent([3]label.Label{ - keys.Metric.New(), - t1, - t2, - }, nil)) -} - -// Start1 sends a span start event with the supplied label list to the exporter. -// It also returns a function that will end the span, which should normally be -// deferred. -func Start1(ctx context.Context, name string, t1 label.Label) (context.Context, func()) { - return ExportPair(ctx, - MakeEvent([3]label.Label{ - keys.Start.Of(name), - t1, - }, nil), - MakeEvent([3]label.Label{ - keys.End.New(), - }, nil)) -} - -// Start2 sends a span start event with the supplied label list to the exporter. -// It also returns a function that will end the span, which should normally be -// deferred. -func Start2(ctx context.Context, name string, t1, t2 label.Label) (context.Context, func()) { - return ExportPair(ctx, - MakeEvent([3]label.Label{ - keys.Start.Of(name), - t1, - t2, - }, nil), - MakeEvent([3]label.Label{ - keys.End.New(), - }, nil)) -} diff --git a/vendor/golang.org/x/tools/internal/event/doc.go b/vendor/golang.org/x/tools/internal/event/doc.go deleted file mode 100644 index 5dc6e6babed..00000000000 --- a/vendor/golang.org/x/tools/internal/event/doc.go +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package event provides a set of packages that cover the main -// concepts of telemetry in an implementation agnostic way. -package event diff --git a/vendor/golang.org/x/tools/internal/event/event.go b/vendor/golang.org/x/tools/internal/event/event.go deleted file mode 100644 index 4d55e577d1a..00000000000 --- a/vendor/golang.org/x/tools/internal/event/event.go +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package event - -import ( - "context" - - "golang.org/x/tools/internal/event/core" - "golang.org/x/tools/internal/event/keys" - "golang.org/x/tools/internal/event/label" -) - -// Exporter is a function that handles events. -// It may return a modified context and event. -type Exporter func(context.Context, core.Event, label.Map) context.Context - -// SetExporter sets the global exporter function that handles all events. -// The exporter is called synchronously from the event call site, so it should -// return quickly so as not to hold up user code. -func SetExporter(e Exporter) { - core.SetExporter(core.Exporter(e)) -} - -// Log takes a message and a label list and combines them into a single event -// before delivering them to the exporter. -func Log(ctx context.Context, message string, labels ...label.Label) { - core.Export(ctx, core.MakeEvent([3]label.Label{ - keys.Msg.Of(message), - }, labels)) -} - -// IsLog returns true if the event was built by the Log function. -// It is intended to be used in exporters to identify the semantics of the -// event when deciding what to do with it. -func IsLog(ev core.Event) bool { - return ev.Label(0).Key() == keys.Msg -} - -// Error takes a message and a label list and combines them into a single event -// before delivering them to the exporter. It captures the error in the -// delivered event. -func Error(ctx context.Context, message string, err error, labels ...label.Label) { - core.Export(ctx, core.MakeEvent([3]label.Label{ - keys.Msg.Of(message), - keys.Err.Of(err), - }, labels)) -} - -// IsError returns true if the event was built by the Error function. -// It is intended to be used in exporters to identify the semantics of the -// event when deciding what to do with it. -func IsError(ev core.Event) bool { - return ev.Label(0).Key() == keys.Msg && - ev.Label(1).Key() == keys.Err -} - -// Metric sends a label event to the exporter with the supplied labels. -func Metric(ctx context.Context, labels ...label.Label) { - core.Export(ctx, core.MakeEvent([3]label.Label{ - keys.Metric.New(), - }, labels)) -} - -// IsMetric returns true if the event was built by the Metric function. -// It is intended to be used in exporters to identify the semantics of the -// event when deciding what to do with it. -func IsMetric(ev core.Event) bool { - return ev.Label(0).Key() == keys.Metric -} - -// Label sends a label event to the exporter with the supplied labels. -func Label(ctx context.Context, labels ...label.Label) context.Context { - return core.Export(ctx, core.MakeEvent([3]label.Label{ - keys.Label.New(), - }, labels)) -} - -// IsLabel returns true if the event was built by the Label function. -// It is intended to be used in exporters to identify the semantics of the -// event when deciding what to do with it. -func IsLabel(ev core.Event) bool { - return ev.Label(0).Key() == keys.Label -} - -// Start sends a span start event with the supplied label list to the exporter. -// It also returns a function that will end the span, which should normally be -// deferred. -func Start(ctx context.Context, name string, labels ...label.Label) (context.Context, func()) { - return core.ExportPair(ctx, - core.MakeEvent([3]label.Label{ - keys.Start.Of(name), - }, labels), - core.MakeEvent([3]label.Label{ - keys.End.New(), - }, nil)) -} - -// IsStart returns true if the event was built by the Start function. -// It is intended to be used in exporters to identify the semantics of the -// event when deciding what to do with it. -func IsStart(ev core.Event) bool { - return ev.Label(0).Key() == keys.Start -} - -// IsEnd returns true if the event was built by the End function. -// It is intended to be used in exporters to identify the semantics of the -// event when deciding what to do with it. -func IsEnd(ev core.Event) bool { - return ev.Label(0).Key() == keys.End -} - -// Detach returns a context without an associated span. -// This allows the creation of spans that are not children of the current span. -func Detach(ctx context.Context) context.Context { - return core.Export(ctx, core.MakeEvent([3]label.Label{ - keys.Detach.New(), - }, nil)) -} - -// IsDetach returns true if the event was built by the Detach function. -// It is intended to be used in exporters to identify the semantics of the -// event when deciding what to do with it. -func IsDetach(ev core.Event) bool { - return ev.Label(0).Key() == keys.Detach -} diff --git a/vendor/golang.org/x/tools/internal/event/keys/keys.go b/vendor/golang.org/x/tools/internal/event/keys/keys.go deleted file mode 100644 index a02206e3015..00000000000 --- a/vendor/golang.org/x/tools/internal/event/keys/keys.go +++ /dev/null @@ -1,564 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package keys - -import ( - "fmt" - "io" - "math" - "strconv" - - "golang.org/x/tools/internal/event/label" -) - -// Value represents a key for untyped values. -type Value struct { - name string - description string -} - -// New creates a new Key for untyped values. -func New(name, description string) *Value { - return &Value{name: name, description: description} -} - -func (k *Value) Name() string { return k.name } -func (k *Value) Description() string { return k.description } - -func (k *Value) Format(w io.Writer, buf []byte, l label.Label) { - fmt.Fprint(w, k.From(l)) -} - -// Get can be used to get a label for the key from a label.Map. -func (k *Value) Get(lm label.Map) interface{} { - if t := lm.Find(k); t.Valid() { - return k.From(t) - } - return nil -} - -// From can be used to get a value from a Label. -func (k *Value) From(t label.Label) interface{} { return t.UnpackValue() } - -// Of creates a new Label with this key and the supplied value. -func (k *Value) Of(value interface{}) label.Label { return label.OfValue(k, value) } - -// Tag represents a key for tagging labels that have no value. -// These are used when the existence of the label is the entire information it -// carries, such as marking events to be of a specific kind, or from a specific -// package. -type Tag struct { - name string - description string -} - -// NewTag creates a new Key for tagging labels. -func NewTag(name, description string) *Tag { - return &Tag{name: name, description: description} -} - -func (k *Tag) Name() string { return k.name } -func (k *Tag) Description() string { return k.description } - -func (k *Tag) Format(w io.Writer, buf []byte, l label.Label) {} - -// New creates a new Label with this key. -func (k *Tag) New() label.Label { return label.OfValue(k, nil) } - -// Int represents a key -type Int struct { - name string - description string -} - -// NewInt creates a new Key for int values. -func NewInt(name, description string) *Int { - return &Int{name: name, description: description} -} - -func (k *Int) Name() string { return k.name } -func (k *Int) Description() string { return k.description } - -func (k *Int) Format(w io.Writer, buf []byte, l label.Label) { - w.Write(strconv.AppendInt(buf, int64(k.From(l)), 10)) -} - -// Of creates a new Label with this key and the supplied value. -func (k *Int) Of(v int) label.Label { return label.Of64(k, uint64(v)) } - -// Get can be used to get a label for the key from a label.Map. -func (k *Int) Get(lm label.Map) int { - if t := lm.Find(k); t.Valid() { - return k.From(t) - } - return 0 -} - -// From can be used to get a value from a Label. -func (k *Int) From(t label.Label) int { return int(t.Unpack64()) } - -// Int8 represents a key -type Int8 struct { - name string - description string -} - -// NewInt8 creates a new Key for int8 values. -func NewInt8(name, description string) *Int8 { - return &Int8{name: name, description: description} -} - -func (k *Int8) Name() string { return k.name } -func (k *Int8) Description() string { return k.description } - -func (k *Int8) Format(w io.Writer, buf []byte, l label.Label) { - w.Write(strconv.AppendInt(buf, int64(k.From(l)), 10)) -} - -// Of creates a new Label with this key and the supplied value. -func (k *Int8) Of(v int8) label.Label { return label.Of64(k, uint64(v)) } - -// Get can be used to get a label for the key from a label.Map. -func (k *Int8) Get(lm label.Map) int8 { - if t := lm.Find(k); t.Valid() { - return k.From(t) - } - return 0 -} - -// From can be used to get a value from a Label. -func (k *Int8) From(t label.Label) int8 { return int8(t.Unpack64()) } - -// Int16 represents a key -type Int16 struct { - name string - description string -} - -// NewInt16 creates a new Key for int16 values. -func NewInt16(name, description string) *Int16 { - return &Int16{name: name, description: description} -} - -func (k *Int16) Name() string { return k.name } -func (k *Int16) Description() string { return k.description } - -func (k *Int16) Format(w io.Writer, buf []byte, l label.Label) { - w.Write(strconv.AppendInt(buf, int64(k.From(l)), 10)) -} - -// Of creates a new Label with this key and the supplied value. -func (k *Int16) Of(v int16) label.Label { return label.Of64(k, uint64(v)) } - -// Get can be used to get a label for the key from a label.Map. -func (k *Int16) Get(lm label.Map) int16 { - if t := lm.Find(k); t.Valid() { - return k.From(t) - } - return 0 -} - -// From can be used to get a value from a Label. -func (k *Int16) From(t label.Label) int16 { return int16(t.Unpack64()) } - -// Int32 represents a key -type Int32 struct { - name string - description string -} - -// NewInt32 creates a new Key for int32 values. -func NewInt32(name, description string) *Int32 { - return &Int32{name: name, description: description} -} - -func (k *Int32) Name() string { return k.name } -func (k *Int32) Description() string { return k.description } - -func (k *Int32) Format(w io.Writer, buf []byte, l label.Label) { - w.Write(strconv.AppendInt(buf, int64(k.From(l)), 10)) -} - -// Of creates a new Label with this key and the supplied value. -func (k *Int32) Of(v int32) label.Label { return label.Of64(k, uint64(v)) } - -// Get can be used to get a label for the key from a label.Map. -func (k *Int32) Get(lm label.Map) int32 { - if t := lm.Find(k); t.Valid() { - return k.From(t) - } - return 0 -} - -// From can be used to get a value from a Label. -func (k *Int32) From(t label.Label) int32 { return int32(t.Unpack64()) } - -// Int64 represents a key -type Int64 struct { - name string - description string -} - -// NewInt64 creates a new Key for int64 values. -func NewInt64(name, description string) *Int64 { - return &Int64{name: name, description: description} -} - -func (k *Int64) Name() string { return k.name } -func (k *Int64) Description() string { return k.description } - -func (k *Int64) Format(w io.Writer, buf []byte, l label.Label) { - w.Write(strconv.AppendInt(buf, k.From(l), 10)) -} - -// Of creates a new Label with this key and the supplied value. -func (k *Int64) Of(v int64) label.Label { return label.Of64(k, uint64(v)) } - -// Get can be used to get a label for the key from a label.Map. -func (k *Int64) Get(lm label.Map) int64 { - if t := lm.Find(k); t.Valid() { - return k.From(t) - } - return 0 -} - -// From can be used to get a value from a Label. -func (k *Int64) From(t label.Label) int64 { return int64(t.Unpack64()) } - -// UInt represents a key -type UInt struct { - name string - description string -} - -// NewUInt creates a new Key for uint values. -func NewUInt(name, description string) *UInt { - return &UInt{name: name, description: description} -} - -func (k *UInt) Name() string { return k.name } -func (k *UInt) Description() string { return k.description } - -func (k *UInt) Format(w io.Writer, buf []byte, l label.Label) { - w.Write(strconv.AppendUint(buf, uint64(k.From(l)), 10)) -} - -// Of creates a new Label with this key and the supplied value. -func (k *UInt) Of(v uint) label.Label { return label.Of64(k, uint64(v)) } - -// Get can be used to get a label for the key from a label.Map. -func (k *UInt) Get(lm label.Map) uint { - if t := lm.Find(k); t.Valid() { - return k.From(t) - } - return 0 -} - -// From can be used to get a value from a Label. -func (k *UInt) From(t label.Label) uint { return uint(t.Unpack64()) } - -// UInt8 represents a key -type UInt8 struct { - name string - description string -} - -// NewUInt8 creates a new Key for uint8 values. -func NewUInt8(name, description string) *UInt8 { - return &UInt8{name: name, description: description} -} - -func (k *UInt8) Name() string { return k.name } -func (k *UInt8) Description() string { return k.description } - -func (k *UInt8) Format(w io.Writer, buf []byte, l label.Label) { - w.Write(strconv.AppendUint(buf, uint64(k.From(l)), 10)) -} - -// Of creates a new Label with this key and the supplied value. -func (k *UInt8) Of(v uint8) label.Label { return label.Of64(k, uint64(v)) } - -// Get can be used to get a label for the key from a label.Map. -func (k *UInt8) Get(lm label.Map) uint8 { - if t := lm.Find(k); t.Valid() { - return k.From(t) - } - return 0 -} - -// From can be used to get a value from a Label. -func (k *UInt8) From(t label.Label) uint8 { return uint8(t.Unpack64()) } - -// UInt16 represents a key -type UInt16 struct { - name string - description string -} - -// NewUInt16 creates a new Key for uint16 values. -func NewUInt16(name, description string) *UInt16 { - return &UInt16{name: name, description: description} -} - -func (k *UInt16) Name() string { return k.name } -func (k *UInt16) Description() string { return k.description } - -func (k *UInt16) Format(w io.Writer, buf []byte, l label.Label) { - w.Write(strconv.AppendUint(buf, uint64(k.From(l)), 10)) -} - -// Of creates a new Label with this key and the supplied value. -func (k *UInt16) Of(v uint16) label.Label { return label.Of64(k, uint64(v)) } - -// Get can be used to get a label for the key from a label.Map. -func (k *UInt16) Get(lm label.Map) uint16 { - if t := lm.Find(k); t.Valid() { - return k.From(t) - } - return 0 -} - -// From can be used to get a value from a Label. -func (k *UInt16) From(t label.Label) uint16 { return uint16(t.Unpack64()) } - -// UInt32 represents a key -type UInt32 struct { - name string - description string -} - -// NewUInt32 creates a new Key for uint32 values. -func NewUInt32(name, description string) *UInt32 { - return &UInt32{name: name, description: description} -} - -func (k *UInt32) Name() string { return k.name } -func (k *UInt32) Description() string { return k.description } - -func (k *UInt32) Format(w io.Writer, buf []byte, l label.Label) { - w.Write(strconv.AppendUint(buf, uint64(k.From(l)), 10)) -} - -// Of creates a new Label with this key and the supplied value. -func (k *UInt32) Of(v uint32) label.Label { return label.Of64(k, uint64(v)) } - -// Get can be used to get a label for the key from a label.Map. -func (k *UInt32) Get(lm label.Map) uint32 { - if t := lm.Find(k); t.Valid() { - return k.From(t) - } - return 0 -} - -// From can be used to get a value from a Label. -func (k *UInt32) From(t label.Label) uint32 { return uint32(t.Unpack64()) } - -// UInt64 represents a key -type UInt64 struct { - name string - description string -} - -// NewUInt64 creates a new Key for uint64 values. -func NewUInt64(name, description string) *UInt64 { - return &UInt64{name: name, description: description} -} - -func (k *UInt64) Name() string { return k.name } -func (k *UInt64) Description() string { return k.description } - -func (k *UInt64) Format(w io.Writer, buf []byte, l label.Label) { - w.Write(strconv.AppendUint(buf, k.From(l), 10)) -} - -// Of creates a new Label with this key and the supplied value. -func (k *UInt64) Of(v uint64) label.Label { return label.Of64(k, v) } - -// Get can be used to get a label for the key from a label.Map. -func (k *UInt64) Get(lm label.Map) uint64 { - if t := lm.Find(k); t.Valid() { - return k.From(t) - } - return 0 -} - -// From can be used to get a value from a Label. -func (k *UInt64) From(t label.Label) uint64 { return t.Unpack64() } - -// Float32 represents a key -type Float32 struct { - name string - description string -} - -// NewFloat32 creates a new Key for float32 values. -func NewFloat32(name, description string) *Float32 { - return &Float32{name: name, description: description} -} - -func (k *Float32) Name() string { return k.name } -func (k *Float32) Description() string { return k.description } - -func (k *Float32) Format(w io.Writer, buf []byte, l label.Label) { - w.Write(strconv.AppendFloat(buf, float64(k.From(l)), 'E', -1, 32)) -} - -// Of creates a new Label with this key and the supplied value. -func (k *Float32) Of(v float32) label.Label { - return label.Of64(k, uint64(math.Float32bits(v))) -} - -// Get can be used to get a label for the key from a label.Map. -func (k *Float32) Get(lm label.Map) float32 { - if t := lm.Find(k); t.Valid() { - return k.From(t) - } - return 0 -} - -// From can be used to get a value from a Label. -func (k *Float32) From(t label.Label) float32 { - return math.Float32frombits(uint32(t.Unpack64())) -} - -// Float64 represents a key -type Float64 struct { - name string - description string -} - -// NewFloat64 creates a new Key for int64 values. -func NewFloat64(name, description string) *Float64 { - return &Float64{name: name, description: description} -} - -func (k *Float64) Name() string { return k.name } -func (k *Float64) Description() string { return k.description } - -func (k *Float64) Format(w io.Writer, buf []byte, l label.Label) { - w.Write(strconv.AppendFloat(buf, k.From(l), 'E', -1, 64)) -} - -// Of creates a new Label with this key and the supplied value. -func (k *Float64) Of(v float64) label.Label { - return label.Of64(k, math.Float64bits(v)) -} - -// Get can be used to get a label for the key from a label.Map. -func (k *Float64) Get(lm label.Map) float64 { - if t := lm.Find(k); t.Valid() { - return k.From(t) - } - return 0 -} - -// From can be used to get a value from a Label. -func (k *Float64) From(t label.Label) float64 { - return math.Float64frombits(t.Unpack64()) -} - -// String represents a key -type String struct { - name string - description string -} - -// NewString creates a new Key for int64 values. -func NewString(name, description string) *String { - return &String{name: name, description: description} -} - -func (k *String) Name() string { return k.name } -func (k *String) Description() string { return k.description } - -func (k *String) Format(w io.Writer, buf []byte, l label.Label) { - w.Write(strconv.AppendQuote(buf, k.From(l))) -} - -// Of creates a new Label with this key and the supplied value. -func (k *String) Of(v string) label.Label { return label.OfString(k, v) } - -// Get can be used to get a label for the key from a label.Map. -func (k *String) Get(lm label.Map) string { - if t := lm.Find(k); t.Valid() { - return k.From(t) - } - return "" -} - -// From can be used to get a value from a Label. -func (k *String) From(t label.Label) string { return t.UnpackString() } - -// Boolean represents a key -type Boolean struct { - name string - description string -} - -// NewBoolean creates a new Key for bool values. -func NewBoolean(name, description string) *Boolean { - return &Boolean{name: name, description: description} -} - -func (k *Boolean) Name() string { return k.name } -func (k *Boolean) Description() string { return k.description } - -func (k *Boolean) Format(w io.Writer, buf []byte, l label.Label) { - w.Write(strconv.AppendBool(buf, k.From(l))) -} - -// Of creates a new Label with this key and the supplied value. -func (k *Boolean) Of(v bool) label.Label { - if v { - return label.Of64(k, 1) - } - return label.Of64(k, 0) -} - -// Get can be used to get a label for the key from a label.Map. -func (k *Boolean) Get(lm label.Map) bool { - if t := lm.Find(k); t.Valid() { - return k.From(t) - } - return false -} - -// From can be used to get a value from a Label. -func (k *Boolean) From(t label.Label) bool { return t.Unpack64() > 0 } - -// Error represents a key -type Error struct { - name string - description string -} - -// NewError creates a new Key for int64 values. -func NewError(name, description string) *Error { - return &Error{name: name, description: description} -} - -func (k *Error) Name() string { return k.name } -func (k *Error) Description() string { return k.description } - -func (k *Error) Format(w io.Writer, buf []byte, l label.Label) { - io.WriteString(w, k.From(l).Error()) -} - -// Of creates a new Label with this key and the supplied value. -func (k *Error) Of(v error) label.Label { return label.OfValue(k, v) } - -// Get can be used to get a label for the key from a label.Map. -func (k *Error) Get(lm label.Map) error { - if t := lm.Find(k); t.Valid() { - return k.From(t) - } - return nil -} - -// From can be used to get a value from a Label. -func (k *Error) From(t label.Label) error { - err, _ := t.UnpackValue().(error) - return err -} diff --git a/vendor/golang.org/x/tools/internal/event/keys/standard.go b/vendor/golang.org/x/tools/internal/event/keys/standard.go deleted file mode 100644 index 7e958665921..00000000000 --- a/vendor/golang.org/x/tools/internal/event/keys/standard.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2020 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package keys - -var ( - // Msg is a key used to add message strings to label lists. - Msg = NewString("message", "a readable message") - // Label is a key used to indicate an event adds labels to the context. - Label = NewTag("label", "a label context marker") - // Start is used for things like traces that have a name. - Start = NewString("start", "span start") - // Metric is a key used to indicate an event records metrics. - End = NewTag("end", "a span end marker") - // Metric is a key used to indicate an event records metrics. - Detach = NewTag("detach", "a span detach marker") - // Err is a key used to add error values to label lists. - Err = NewError("error", "an error that occurred") - // Metric is a key used to indicate an event records metrics. - Metric = NewTag("metric", "a metric event marker") -) diff --git a/vendor/golang.org/x/tools/internal/event/label/label.go b/vendor/golang.org/x/tools/internal/event/label/label.go deleted file mode 100644 index 0f526e1f9ab..00000000000 --- a/vendor/golang.org/x/tools/internal/event/label/label.go +++ /dev/null @@ -1,215 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package label - -import ( - "fmt" - "io" - "reflect" - "unsafe" -) - -// Key is used as the identity of a Label. -// Keys are intended to be compared by pointer only, the name should be unique -// for communicating with external systems, but it is not required or enforced. -type Key interface { - // Name returns the key name. - Name() string - // Description returns a string that can be used to describe the value. - Description() string - - // Format is used in formatting to append the value of the label to the - // supplied buffer. - // The formatter may use the supplied buf as a scratch area to avoid - // allocations. - Format(w io.Writer, buf []byte, l Label) -} - -// Label holds a key and value pair. -// It is normally used when passing around lists of labels. -type Label struct { - key Key - packed uint64 - untyped interface{} -} - -// Map is the interface to a collection of Labels indexed by key. -type Map interface { - // Find returns the label that matches the supplied key. - Find(key Key) Label -} - -// List is the interface to something that provides an iterable -// list of labels. -// Iteration should start from 0 and continue until Valid returns false. -type List interface { - // Valid returns true if the index is within range for the list. - // It does not imply the label at that index will itself be valid. - Valid(index int) bool - // Label returns the label at the given index. - Label(index int) Label -} - -// list implements LabelList for a list of Labels. -type list struct { - labels []Label -} - -// filter wraps a LabelList filtering out specific labels. -type filter struct { - keys []Key - underlying List -} - -// listMap implements LabelMap for a simple list of labels. -type listMap struct { - labels []Label -} - -// mapChain implements LabelMap for a list of underlying LabelMap. -type mapChain struct { - maps []Map -} - -// OfValue creates a new label from the key and value. -// This method is for implementing new key types, label creation should -// normally be done with the Of method of the key. -func OfValue(k Key, value interface{}) Label { return Label{key: k, untyped: value} } - -// UnpackValue assumes the label was built using LabelOfValue and returns the value -// that was passed to that constructor. -// This method is for implementing new key types, for type safety normal -// access should be done with the From method of the key. -func (t Label) UnpackValue() interface{} { return t.untyped } - -// Of64 creates a new label from a key and a uint64. This is often -// used for non uint64 values that can be packed into a uint64. -// This method is for implementing new key types, label creation should -// normally be done with the Of method of the key. -func Of64(k Key, v uint64) Label { return Label{key: k, packed: v} } - -// Unpack64 assumes the label was built using LabelOf64 and returns the value that -// was passed to that constructor. -// This method is for implementing new key types, for type safety normal -// access should be done with the From method of the key. -func (t Label) Unpack64() uint64 { return t.packed } - -type stringptr unsafe.Pointer - -// OfString creates a new label from a key and a string. -// This method is for implementing new key types, label creation should -// normally be done with the Of method of the key. -func OfString(k Key, v string) Label { - hdr := (*reflect.StringHeader)(unsafe.Pointer(&v)) - return Label{ - key: k, - packed: uint64(hdr.Len), - untyped: stringptr(hdr.Data), - } -} - -// UnpackString assumes the label was built using LabelOfString and returns the -// value that was passed to that constructor. -// This method is for implementing new key types, for type safety normal -// access should be done with the From method of the key. -func (t Label) UnpackString() string { - var v string - hdr := (*reflect.StringHeader)(unsafe.Pointer(&v)) - hdr.Data = uintptr(t.untyped.(stringptr)) - hdr.Len = int(t.packed) - return v -} - -// Valid returns true if the Label is a valid one (it has a key). -func (t Label) Valid() bool { return t.key != nil } - -// Key returns the key of this Label. -func (t Label) Key() Key { return t.key } - -// Format is used for debug printing of labels. -func (t Label) Format(f fmt.State, r rune) { - if !t.Valid() { - io.WriteString(f, `nil`) - return - } - io.WriteString(f, t.Key().Name()) - io.WriteString(f, "=") - var buf [128]byte - t.Key().Format(f, buf[:0], t) -} - -func (l *list) Valid(index int) bool { - return index >= 0 && index < len(l.labels) -} - -func (l *list) Label(index int) Label { - return l.labels[index] -} - -func (f *filter) Valid(index int) bool { - return f.underlying.Valid(index) -} - -func (f *filter) Label(index int) Label { - l := f.underlying.Label(index) - for _, f := range f.keys { - if l.Key() == f { - return Label{} - } - } - return l -} - -func (lm listMap) Find(key Key) Label { - for _, l := range lm.labels { - if l.Key() == key { - return l - } - } - return Label{} -} - -func (c mapChain) Find(key Key) Label { - for _, src := range c.maps { - l := src.Find(key) - if l.Valid() { - return l - } - } - return Label{} -} - -var emptyList = &list{} - -func NewList(labels ...Label) List { - if len(labels) == 0 { - return emptyList - } - return &list{labels: labels} -} - -func Filter(l List, keys ...Key) List { - if len(keys) == 0 { - return l - } - return &filter{keys: keys, underlying: l} -} - -func NewMap(labels ...Label) Map { - return listMap{labels: labels} -} - -func MergeMaps(srcs ...Map) Map { - var nonNil []Map - for _, src := range srcs { - if src != nil { - nonNil = append(nonNil, src) - } - } - if len(nonNil) == 1 { - return nonNil[0] - } - return mapChain{maps: nonNil} -} diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk.go deleted file mode 100644 index 798fe599be4..00000000000 --- a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk.go +++ /dev/null @@ -1,196 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package fastwalk provides a faster version of filepath.Walk for file system -// scanning tools. -package fastwalk - -import ( - "errors" - "os" - "path/filepath" - "runtime" - "sync" -) - -// ErrTraverseLink is used as a return value from WalkFuncs to indicate that the -// symlink named in the call may be traversed. -var ErrTraverseLink = errors.New("fastwalk: traverse symlink, assuming target is a directory") - -// ErrSkipFiles is a used as a return value from WalkFuncs to indicate that the -// callback should not be called for any other files in the current directory. -// Child directories will still be traversed. -var ErrSkipFiles = errors.New("fastwalk: skip remaining files in directory") - -// Walk is a faster implementation of filepath.Walk. -// -// filepath.Walk's design necessarily calls os.Lstat on each file, -// even if the caller needs less info. -// Many tools need only the type of each file. -// On some platforms, this information is provided directly by the readdir -// system call, avoiding the need to stat each file individually. -// fastwalk_unix.go contains a fork of the syscall routines. -// -// See golang.org/issue/16399 -// -// Walk walks the file tree rooted at root, calling walkFn for -// each file or directory in the tree, including root. -// -// If fastWalk returns filepath.SkipDir, the directory is skipped. -// -// Unlike filepath.Walk: -// - file stat calls must be done by the user. -// The only provided metadata is the file type, which does not include -// any permission bits. -// - multiple goroutines stat the filesystem concurrently. The provided -// walkFn must be safe for concurrent use. -// - fastWalk can follow symlinks if walkFn returns the TraverseLink -// sentinel error. It is the walkFn's responsibility to prevent -// fastWalk from going into symlink cycles. -func Walk(root string, walkFn func(path string, typ os.FileMode) error) error { - // TODO(bradfitz): make numWorkers configurable? We used a - // minimum of 4 to give the kernel more info about multiple - // things we want, in hopes its I/O scheduling can take - // advantage of that. Hopefully most are in cache. Maybe 4 is - // even too low of a minimum. Profile more. - numWorkers := 4 - if n := runtime.NumCPU(); n > numWorkers { - numWorkers = n - } - - // Make sure to wait for all workers to finish, otherwise - // walkFn could still be called after returning. This Wait call - // runs after close(e.donec) below. - var wg sync.WaitGroup - defer wg.Wait() - - w := &walker{ - fn: walkFn, - enqueuec: make(chan walkItem, numWorkers), // buffered for performance - workc: make(chan walkItem, numWorkers), // buffered for performance - donec: make(chan struct{}), - - // buffered for correctness & not leaking goroutines: - resc: make(chan error, numWorkers), - } - defer close(w.donec) - - for i := 0; i < numWorkers; i++ { - wg.Add(1) - go w.doWork(&wg) - } - todo := []walkItem{{dir: root}} - out := 0 - for { - workc := w.workc - var workItem walkItem - if len(todo) == 0 { - workc = nil - } else { - workItem = todo[len(todo)-1] - } - select { - case workc <- workItem: - todo = todo[:len(todo)-1] - out++ - case it := <-w.enqueuec: - todo = append(todo, it) - case err := <-w.resc: - out-- - if err != nil { - return err - } - if out == 0 && len(todo) == 0 { - // It's safe to quit here, as long as the buffered - // enqueue channel isn't also readable, which might - // happen if the worker sends both another unit of - // work and its result before the other select was - // scheduled and both w.resc and w.enqueuec were - // readable. - select { - case it := <-w.enqueuec: - todo = append(todo, it) - default: - return nil - } - } - } - } -} - -// doWork reads directories as instructed (via workc) and runs the -// user's callback function. -func (w *walker) doWork(wg *sync.WaitGroup) { - defer wg.Done() - for { - select { - case <-w.donec: - return - case it := <-w.workc: - select { - case <-w.donec: - return - case w.resc <- w.walk(it.dir, !it.callbackDone): - } - } - } -} - -type walker struct { - fn func(path string, typ os.FileMode) error - - donec chan struct{} // closed on fastWalk's return - workc chan walkItem // to workers - enqueuec chan walkItem // from workers - resc chan error // from workers -} - -type walkItem struct { - dir string - callbackDone bool // callback already called; don't do it again -} - -func (w *walker) enqueue(it walkItem) { - select { - case w.enqueuec <- it: - case <-w.donec: - } -} - -func (w *walker) onDirEnt(dirName, baseName string, typ os.FileMode) error { - joined := dirName + string(os.PathSeparator) + baseName - if typ == os.ModeDir { - w.enqueue(walkItem{dir: joined}) - return nil - } - - err := w.fn(joined, typ) - if typ == os.ModeSymlink { - if err == ErrTraverseLink { - // Set callbackDone so we don't call it twice for both the - // symlink-as-symlink and the symlink-as-directory later: - w.enqueue(walkItem{dir: joined, callbackDone: true}) - return nil - } - if err == filepath.SkipDir { - // Permit SkipDir on symlinks too. - return nil - } - } - return err -} - -func (w *walker) walk(root string, runUserCallback bool) error { - if runUserCallback { - err := w.fn(root, os.ModeDir) - if err == filepath.SkipDir { - return nil - } - if err != nil { - return err - } - } - - return readDir(root, w.onDirEnt) -} diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_darwin.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_darwin.go deleted file mode 100644 index 0ca55e0d56f..00000000000 --- a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_darwin.go +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build darwin && cgo -// +build darwin,cgo - -package fastwalk - -/* -#include - -// fastwalk_readdir_r wraps readdir_r so that we don't have to pass a dirent** -// result pointer which triggers CGO's "Go pointer to Go pointer" check unless -// we allocat the result dirent* with malloc. -// -// fastwalk_readdir_r returns 0 on success, -1 upon reaching the end of the -// directory, or a positive error number to indicate failure. -static int fastwalk_readdir_r(DIR *fd, struct dirent *entry) { - struct dirent *result; - int ret = readdir_r(fd, entry, &result); - if (ret == 0 && result == NULL) { - ret = -1; // EOF - } - return ret; -} -*/ -import "C" - -import ( - "os" - "syscall" - "unsafe" -) - -func readDir(dirName string, fn func(dirName, entName string, typ os.FileMode) error) error { - fd, err := openDir(dirName) - if err != nil { - return &os.PathError{Op: "opendir", Path: dirName, Err: err} - } - defer C.closedir(fd) - - skipFiles := false - var dirent syscall.Dirent - for { - ret := int(C.fastwalk_readdir_r(fd, (*C.struct_dirent)(unsafe.Pointer(&dirent)))) - if ret != 0 { - if ret == -1 { - break // EOF - } - if ret == int(syscall.EINTR) { - continue - } - return &os.PathError{Op: "readdir", Path: dirName, Err: syscall.Errno(ret)} - } - if dirent.Ino == 0 { - continue - } - typ := dtToType(dirent.Type) - if skipFiles && typ.IsRegular() { - continue - } - name := (*[len(syscall.Dirent{}.Name)]byte)(unsafe.Pointer(&dirent.Name))[:] - name = name[:dirent.Namlen] - for i, c := range name { - if c == 0 { - name = name[:i] - break - } - } - // Check for useless names before allocating a string. - if string(name) == "." || string(name) == ".." { - continue - } - if err := fn(dirName, string(name), typ); err != nil { - if err != ErrSkipFiles { - return err - } - skipFiles = true - } - } - - return nil -} - -func dtToType(typ uint8) os.FileMode { - switch typ { - case syscall.DT_BLK: - return os.ModeDevice - case syscall.DT_CHR: - return os.ModeDevice | os.ModeCharDevice - case syscall.DT_DIR: - return os.ModeDir - case syscall.DT_FIFO: - return os.ModeNamedPipe - case syscall.DT_LNK: - return os.ModeSymlink - case syscall.DT_REG: - return 0 - case syscall.DT_SOCK: - return os.ModeSocket - } - return ^os.FileMode(0) -} - -// openDir wraps opendir(3) and handles any EINTR errors. The returned *DIR -// needs to be closed with closedir(3). -func openDir(path string) (*C.DIR, error) { - name, err := syscall.BytePtrFromString(path) - if err != nil { - return nil, err - } - for { - fd, err := C.opendir((*C.char)(unsafe.Pointer(name))) - if err != syscall.EINTR { - return fd, err - } - } -} diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_fileno.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_fileno.go deleted file mode 100644 index d58595dbd3f..00000000000 --- a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_fileno.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build freebsd || openbsd || netbsd -// +build freebsd openbsd netbsd - -package fastwalk - -import "syscall" - -func direntInode(dirent *syscall.Dirent) uint64 { - return uint64(dirent.Fileno) -} diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_ino.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_ino.go deleted file mode 100644 index d3922890b0b..00000000000 --- a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_ino.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build (linux || (darwin && !cgo)) && !appengine -// +build linux darwin,!cgo -// +build !appengine - -package fastwalk - -import "syscall" - -func direntInode(dirent *syscall.Dirent) uint64 { - return dirent.Ino -} diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_bsd.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_bsd.go deleted file mode 100644 index 38a4db6af3a..00000000000 --- a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_bsd.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build (darwin && !cgo) || freebsd || openbsd || netbsd -// +build darwin,!cgo freebsd openbsd netbsd - -package fastwalk - -import "syscall" - -func direntNamlen(dirent *syscall.Dirent) uint64 { - return uint64(dirent.Namlen) -} diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_linux.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_linux.go deleted file mode 100644 index c82e57df85e..00000000000 --- a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_dirent_namlen_linux.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build linux && !appengine -// +build linux,!appengine - -package fastwalk - -import ( - "bytes" - "syscall" - "unsafe" -) - -func direntNamlen(dirent *syscall.Dirent) uint64 { - const fixedHdr = uint16(unsafe.Offsetof(syscall.Dirent{}.Name)) - nameBuf := (*[unsafe.Sizeof(dirent.Name)]byte)(unsafe.Pointer(&dirent.Name[0])) - const nameBufLen = uint16(len(nameBuf)) - limit := dirent.Reclen - fixedHdr - if limit > nameBufLen { - limit = nameBufLen - } - nameLen := bytes.IndexByte(nameBuf[:limit], 0) - if nameLen < 0 { - panic("failed to find terminating 0 byte in dirent") - } - return uint64(nameLen) -} diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_portable.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_portable.go deleted file mode 100644 index 085d311600b..00000000000 --- a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_portable.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build appengine || (!linux && !darwin && !freebsd && !openbsd && !netbsd) -// +build appengine !linux,!darwin,!freebsd,!openbsd,!netbsd - -package fastwalk - -import ( - "io/ioutil" - "os" -) - -// readDir calls fn for each directory entry in dirName. -// It does not descend into directories or follow symlinks. -// If fn returns a non-nil error, readDir returns with that error -// immediately. -func readDir(dirName string, fn func(dirName, entName string, typ os.FileMode) error) error { - fis, err := ioutil.ReadDir(dirName) - if err != nil { - return err - } - skipFiles := false - for _, fi := range fis { - if fi.Mode().IsRegular() && skipFiles { - continue - } - if err := fn(dirName, fi.Name(), fi.Mode()&os.ModeType); err != nil { - if err == ErrSkipFiles { - skipFiles = true - continue - } - return err - } - } - return nil -} diff --git a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_unix.go b/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_unix.go deleted file mode 100644 index f12f1a734cc..00000000000 --- a/vendor/golang.org/x/tools/internal/fastwalk/fastwalk_unix.go +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build (linux || freebsd || openbsd || netbsd || (darwin && !cgo)) && !appengine -// +build linux freebsd openbsd netbsd darwin,!cgo -// +build !appengine - -package fastwalk - -import ( - "fmt" - "os" - "syscall" - "unsafe" -) - -const blockSize = 8 << 10 - -// unknownFileMode is a sentinel (and bogus) os.FileMode -// value used to represent a syscall.DT_UNKNOWN Dirent.Type. -const unknownFileMode os.FileMode = os.ModeNamedPipe | os.ModeSocket | os.ModeDevice - -func readDir(dirName string, fn func(dirName, entName string, typ os.FileMode) error) error { - fd, err := open(dirName, 0, 0) - if err != nil { - return &os.PathError{Op: "open", Path: dirName, Err: err} - } - defer syscall.Close(fd) - - // The buffer must be at least a block long. - buf := make([]byte, blockSize) // stack-allocated; doesn't escape - bufp := 0 // starting read position in buf - nbuf := 0 // end valid data in buf - skipFiles := false - for { - if bufp >= nbuf { - bufp = 0 - nbuf, err = readDirent(fd, buf) - if err != nil { - return os.NewSyscallError("readdirent", err) - } - if nbuf <= 0 { - return nil - } - } - consumed, name, typ := parseDirEnt(buf[bufp:nbuf]) - bufp += consumed - if name == "" || name == "." || name == ".." { - continue - } - // Fallback for filesystems (like old XFS) that don't - // support Dirent.Type and have DT_UNKNOWN (0) there - // instead. - if typ == unknownFileMode { - fi, err := os.Lstat(dirName + "/" + name) - if err != nil { - // It got deleted in the meantime. - if os.IsNotExist(err) { - continue - } - return err - } - typ = fi.Mode() & os.ModeType - } - if skipFiles && typ.IsRegular() { - continue - } - if err := fn(dirName, name, typ); err != nil { - if err == ErrSkipFiles { - skipFiles = true - continue - } - return err - } - } -} - -func parseDirEnt(buf []byte) (consumed int, name string, typ os.FileMode) { - // golang.org/issue/37269 - dirent := &syscall.Dirent{} - copy((*[unsafe.Sizeof(syscall.Dirent{})]byte)(unsafe.Pointer(dirent))[:], buf) - if v := unsafe.Offsetof(dirent.Reclen) + unsafe.Sizeof(dirent.Reclen); uintptr(len(buf)) < v { - panic(fmt.Sprintf("buf size of %d smaller than dirent header size %d", len(buf), v)) - } - if len(buf) < int(dirent.Reclen) { - panic(fmt.Sprintf("buf size %d < record length %d", len(buf), dirent.Reclen)) - } - consumed = int(dirent.Reclen) - if direntInode(dirent) == 0 { // File absent in directory. - return - } - switch dirent.Type { - case syscall.DT_REG: - typ = 0 - case syscall.DT_DIR: - typ = os.ModeDir - case syscall.DT_LNK: - typ = os.ModeSymlink - case syscall.DT_BLK: - typ = os.ModeDevice - case syscall.DT_FIFO: - typ = os.ModeNamedPipe - case syscall.DT_SOCK: - typ = os.ModeSocket - case syscall.DT_UNKNOWN: - typ = unknownFileMode - default: - // Skip weird things. - // It's probably a DT_WHT (http://lwn.net/Articles/325369/) - // or something. Revisit if/when this package is moved outside - // of goimports. goimports only cares about regular files, - // symlinks, and directories. - return - } - - nameBuf := (*[unsafe.Sizeof(dirent.Name)]byte)(unsafe.Pointer(&dirent.Name[0])) - nameLen := direntNamlen(dirent) - - // Special cases for common things: - if nameLen == 1 && nameBuf[0] == '.' { - name = "." - } else if nameLen == 2 && nameBuf[0] == '.' && nameBuf[1] == '.' { - name = ".." - } else { - name = string(nameBuf[:nameLen]) - } - return -} - -// According to https://golang.org/doc/go1.14#runtime -// A consequence of the implementation of preemption is that on Unix systems, including Linux and macOS -// systems, programs built with Go 1.14 will receive more signals than programs built with earlier releases. -// -// This causes syscall.Open and syscall.ReadDirent sometimes fail with EINTR errors. -// We need to retry in this case. -func open(path string, mode int, perm uint32) (fd int, err error) { - for { - fd, err := syscall.Open(path, mode, perm) - if err != syscall.EINTR { - return fd, err - } - } -} - -func readDirent(fd int, buf []byte) (n int, err error) { - for { - nbuf, err := syscall.ReadDirent(fd, buf) - if err != syscall.EINTR { - return nbuf, err - } - } -} diff --git a/vendor/golang.org/x/tools/internal/gcimporter/bexport.go b/vendor/golang.org/x/tools/internal/gcimporter/bexport.go deleted file mode 100644 index 30582ed6d3d..00000000000 --- a/vendor/golang.org/x/tools/internal/gcimporter/bexport.go +++ /dev/null @@ -1,852 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Binary package export. -// This file was derived from $GOROOT/src/cmd/compile/internal/gc/bexport.go; -// see that file for specification of the format. - -package gcimporter - -import ( - "bytes" - "encoding/binary" - "fmt" - "go/constant" - "go/token" - "go/types" - "math" - "math/big" - "sort" - "strings" -) - -// If debugFormat is set, each integer and string value is preceded by a marker -// and position information in the encoding. This mechanism permits an importer -// to recognize immediately when it is out of sync. The importer recognizes this -// mode automatically (i.e., it can import export data produced with debugging -// support even if debugFormat is not set at the time of import). This mode will -// lead to massively larger export data (by a factor of 2 to 3) and should only -// be enabled during development and debugging. -// -// NOTE: This flag is the first flag to enable if importing dies because of -// (suspected) format errors, and whenever a change is made to the format. -const debugFormat = false // default: false - -// Current export format version. Increase with each format change. -// -// Note: The latest binary (non-indexed) export format is at version 6. -// This exporter is still at level 4, but it doesn't matter since -// the binary importer can handle older versions just fine. -// -// 6: package height (CL 105038) -- NOT IMPLEMENTED HERE -// 5: improved position encoding efficiency (issue 20080, CL 41619) -- NOT IMPLEMENTED HERE -// 4: type name objects support type aliases, uses aliasTag -// 3: Go1.8 encoding (same as version 2, aliasTag defined but never used) -// 2: removed unused bool in ODCL export (compiler only) -// 1: header format change (more regular), export package for _ struct fields -// 0: Go1.7 encoding -const exportVersion = 4 - -// trackAllTypes enables cycle tracking for all types, not just named -// types. The existing compiler invariants assume that unnamed types -// that are not completely set up are not used, or else there are spurious -// errors. -// If disabled, only named types are tracked, possibly leading to slightly -// less efficient encoding in rare cases. It also prevents the export of -// some corner-case type declarations (but those are not handled correctly -// with with the textual export format either). -// TODO(gri) enable and remove once issues caused by it are fixed -const trackAllTypes = false - -type exporter struct { - fset *token.FileSet - out bytes.Buffer - - // object -> index maps, indexed in order of serialization - strIndex map[string]int - pkgIndex map[*types.Package]int - typIndex map[types.Type]int - - // position encoding - posInfoFormat bool - prevFile string - prevLine int - - // debugging support - written int // bytes written - indent int // for trace -} - -// internalError represents an error generated inside this package. -type internalError string - -func (e internalError) Error() string { return "gcimporter: " + string(e) } - -func internalErrorf(format string, args ...interface{}) error { - return internalError(fmt.Sprintf(format, args...)) -} - -// BExportData returns binary export data for pkg. -// If no file set is provided, position info will be missing. -func BExportData(fset *token.FileSet, pkg *types.Package) (b []byte, err error) { - if !debug { - defer func() { - if e := recover(); e != nil { - if ierr, ok := e.(internalError); ok { - err = ierr - return - } - // Not an internal error; panic again. - panic(e) - } - }() - } - - p := exporter{ - fset: fset, - strIndex: map[string]int{"": 0}, // empty string is mapped to 0 - pkgIndex: make(map[*types.Package]int), - typIndex: make(map[types.Type]int), - posInfoFormat: true, // TODO(gri) might become a flag, eventually - } - - // write version info - // The version string must start with "version %d" where %d is the version - // number. Additional debugging information may follow after a blank; that - // text is ignored by the importer. - p.rawStringln(fmt.Sprintf("version %d", exportVersion)) - var debug string - if debugFormat { - debug = "debug" - } - p.rawStringln(debug) // cannot use p.bool since it's affected by debugFormat; also want to see this clearly - p.bool(trackAllTypes) - p.bool(p.posInfoFormat) - - // --- generic export data --- - - // populate type map with predeclared "known" types - for index, typ := range predeclared() { - p.typIndex[typ] = index - } - if len(p.typIndex) != len(predeclared()) { - return nil, internalError("duplicate entries in type map?") - } - - // write package data - p.pkg(pkg, true) - if trace { - p.tracef("\n") - } - - // write objects - objcount := 0 - scope := pkg.Scope() - for _, name := range scope.Names() { - if !token.IsExported(name) { - continue - } - if trace { - p.tracef("\n") - } - p.obj(scope.Lookup(name)) - objcount++ - } - - // indicate end of list - if trace { - p.tracef("\n") - } - p.tag(endTag) - - // for self-verification only (redundant) - p.int(objcount) - - if trace { - p.tracef("\n") - } - - // --- end of export data --- - - return p.out.Bytes(), nil -} - -func (p *exporter) pkg(pkg *types.Package, emptypath bool) { - if pkg == nil { - panic(internalError("unexpected nil pkg")) - } - - // if we saw the package before, write its index (>= 0) - if i, ok := p.pkgIndex[pkg]; ok { - p.index('P', i) - return - } - - // otherwise, remember the package, write the package tag (< 0) and package data - if trace { - p.tracef("P%d = { ", len(p.pkgIndex)) - defer p.tracef("} ") - } - p.pkgIndex[pkg] = len(p.pkgIndex) - - p.tag(packageTag) - p.string(pkg.Name()) - if emptypath { - p.string("") - } else { - p.string(pkg.Path()) - } -} - -func (p *exporter) obj(obj types.Object) { - switch obj := obj.(type) { - case *types.Const: - p.tag(constTag) - p.pos(obj) - p.qualifiedName(obj) - p.typ(obj.Type()) - p.value(obj.Val()) - - case *types.TypeName: - if obj.IsAlias() { - p.tag(aliasTag) - p.pos(obj) - p.qualifiedName(obj) - } else { - p.tag(typeTag) - } - p.typ(obj.Type()) - - case *types.Var: - p.tag(varTag) - p.pos(obj) - p.qualifiedName(obj) - p.typ(obj.Type()) - - case *types.Func: - p.tag(funcTag) - p.pos(obj) - p.qualifiedName(obj) - sig := obj.Type().(*types.Signature) - p.paramList(sig.Params(), sig.Variadic()) - p.paramList(sig.Results(), false) - - default: - panic(internalErrorf("unexpected object %v (%T)", obj, obj)) - } -} - -func (p *exporter) pos(obj types.Object) { - if !p.posInfoFormat { - return - } - - file, line := p.fileLine(obj) - if file == p.prevFile { - // common case: write line delta - // delta == 0 means different file or no line change - delta := line - p.prevLine - p.int(delta) - if delta == 0 { - p.int(-1) // -1 means no file change - } - } else { - // different file - p.int(0) - // Encode filename as length of common prefix with previous - // filename, followed by (possibly empty) suffix. Filenames - // frequently share path prefixes, so this can save a lot - // of space and make export data size less dependent on file - // path length. The suffix is unlikely to be empty because - // file names tend to end in ".go". - n := commonPrefixLen(p.prevFile, file) - p.int(n) // n >= 0 - p.string(file[n:]) // write suffix only - p.prevFile = file - p.int(line) - } - p.prevLine = line -} - -func (p *exporter) fileLine(obj types.Object) (file string, line int) { - if p.fset != nil { - pos := p.fset.Position(obj.Pos()) - file = pos.Filename - line = pos.Line - } - return -} - -func commonPrefixLen(a, b string) int { - if len(a) > len(b) { - a, b = b, a - } - // len(a) <= len(b) - i := 0 - for i < len(a) && a[i] == b[i] { - i++ - } - return i -} - -func (p *exporter) qualifiedName(obj types.Object) { - p.string(obj.Name()) - p.pkg(obj.Pkg(), false) -} - -func (p *exporter) typ(t types.Type) { - if t == nil { - panic(internalError("nil type")) - } - - // Possible optimization: Anonymous pointer types *T where - // T is a named type are common. We could canonicalize all - // such types *T to a single type PT = *T. This would lead - // to at most one *T entry in typIndex, and all future *T's - // would be encoded as the respective index directly. Would - // save 1 byte (pointerTag) per *T and reduce the typIndex - // size (at the cost of a canonicalization map). We can do - // this later, without encoding format change. - - // if we saw the type before, write its index (>= 0) - if i, ok := p.typIndex[t]; ok { - p.index('T', i) - return - } - - // otherwise, remember the type, write the type tag (< 0) and type data - if trackAllTypes { - if trace { - p.tracef("T%d = {>\n", len(p.typIndex)) - defer p.tracef("<\n} ") - } - p.typIndex[t] = len(p.typIndex) - } - - switch t := t.(type) { - case *types.Named: - if !trackAllTypes { - // if we don't track all types, track named types now - p.typIndex[t] = len(p.typIndex) - } - - p.tag(namedTag) - p.pos(t.Obj()) - p.qualifiedName(t.Obj()) - p.typ(t.Underlying()) - if !types.IsInterface(t) { - p.assocMethods(t) - } - - case *types.Array: - p.tag(arrayTag) - p.int64(t.Len()) - p.typ(t.Elem()) - - case *types.Slice: - p.tag(sliceTag) - p.typ(t.Elem()) - - case *dddSlice: - p.tag(dddTag) - p.typ(t.elem) - - case *types.Struct: - p.tag(structTag) - p.fieldList(t) - - case *types.Pointer: - p.tag(pointerTag) - p.typ(t.Elem()) - - case *types.Signature: - p.tag(signatureTag) - p.paramList(t.Params(), t.Variadic()) - p.paramList(t.Results(), false) - - case *types.Interface: - p.tag(interfaceTag) - p.iface(t) - - case *types.Map: - p.tag(mapTag) - p.typ(t.Key()) - p.typ(t.Elem()) - - case *types.Chan: - p.tag(chanTag) - p.int(int(3 - t.Dir())) // hack - p.typ(t.Elem()) - - default: - panic(internalErrorf("unexpected type %T: %s", t, t)) - } -} - -func (p *exporter) assocMethods(named *types.Named) { - // Sort methods (for determinism). - var methods []*types.Func - for i := 0; i < named.NumMethods(); i++ { - methods = append(methods, named.Method(i)) - } - sort.Sort(methodsByName(methods)) - - p.int(len(methods)) - - if trace && methods != nil { - p.tracef("associated methods {>\n") - } - - for i, m := range methods { - if trace && i > 0 { - p.tracef("\n") - } - - p.pos(m) - name := m.Name() - p.string(name) - if !exported(name) { - p.pkg(m.Pkg(), false) - } - - sig := m.Type().(*types.Signature) - p.paramList(types.NewTuple(sig.Recv()), false) - p.paramList(sig.Params(), sig.Variadic()) - p.paramList(sig.Results(), false) - p.int(0) // dummy value for go:nointerface pragma - ignored by importer - } - - if trace && methods != nil { - p.tracef("<\n} ") - } -} - -type methodsByName []*types.Func - -func (x methodsByName) Len() int { return len(x) } -func (x methodsByName) Swap(i, j int) { x[i], x[j] = x[j], x[i] } -func (x methodsByName) Less(i, j int) bool { return x[i].Name() < x[j].Name() } - -func (p *exporter) fieldList(t *types.Struct) { - if trace && t.NumFields() > 0 { - p.tracef("fields {>\n") - defer p.tracef("<\n} ") - } - - p.int(t.NumFields()) - for i := 0; i < t.NumFields(); i++ { - if trace && i > 0 { - p.tracef("\n") - } - p.field(t.Field(i)) - p.string(t.Tag(i)) - } -} - -func (p *exporter) field(f *types.Var) { - if !f.IsField() { - panic(internalError("field expected")) - } - - p.pos(f) - p.fieldName(f) - p.typ(f.Type()) -} - -func (p *exporter) iface(t *types.Interface) { - // TODO(gri): enable importer to load embedded interfaces, - // then emit Embeddeds and ExplicitMethods separately here. - p.int(0) - - n := t.NumMethods() - if trace && n > 0 { - p.tracef("methods {>\n") - defer p.tracef("<\n} ") - } - p.int(n) - for i := 0; i < n; i++ { - if trace && i > 0 { - p.tracef("\n") - } - p.method(t.Method(i)) - } -} - -func (p *exporter) method(m *types.Func) { - sig := m.Type().(*types.Signature) - if sig.Recv() == nil { - panic(internalError("method expected")) - } - - p.pos(m) - p.string(m.Name()) - if m.Name() != "_" && !token.IsExported(m.Name()) { - p.pkg(m.Pkg(), false) - } - - // interface method; no need to encode receiver. - p.paramList(sig.Params(), sig.Variadic()) - p.paramList(sig.Results(), false) -} - -func (p *exporter) fieldName(f *types.Var) { - name := f.Name() - - if f.Anonymous() { - // anonymous field - we distinguish between 3 cases: - // 1) field name matches base type name and is exported - // 2) field name matches base type name and is not exported - // 3) field name doesn't match base type name (alias name) - bname := basetypeName(f.Type()) - if name == bname { - if token.IsExported(name) { - name = "" // 1) we don't need to know the field name or package - } else { - name = "?" // 2) use unexported name "?" to force package export - } - } else { - // 3) indicate alias and export name as is - // (this requires an extra "@" but this is a rare case) - p.string("@") - } - } - - p.string(name) - if name != "" && !token.IsExported(name) { - p.pkg(f.Pkg(), false) - } -} - -func basetypeName(typ types.Type) string { - switch typ := deref(typ).(type) { - case *types.Basic: - return typ.Name() - case *types.Named: - return typ.Obj().Name() - default: - return "" // unnamed type - } -} - -func (p *exporter) paramList(params *types.Tuple, variadic bool) { - // use negative length to indicate unnamed parameters - // (look at the first parameter only since either all - // names are present or all are absent) - n := params.Len() - if n > 0 && params.At(0).Name() == "" { - n = -n - } - p.int(n) - for i := 0; i < params.Len(); i++ { - q := params.At(i) - t := q.Type() - if variadic && i == params.Len()-1 { - t = &dddSlice{t.(*types.Slice).Elem()} - } - p.typ(t) - if n > 0 { - name := q.Name() - p.string(name) - if name != "_" { - p.pkg(q.Pkg(), false) - } - } - p.string("") // no compiler-specific info - } -} - -func (p *exporter) value(x constant.Value) { - if trace { - p.tracef("= ") - } - - switch x.Kind() { - case constant.Bool: - tag := falseTag - if constant.BoolVal(x) { - tag = trueTag - } - p.tag(tag) - - case constant.Int: - if v, exact := constant.Int64Val(x); exact { - // common case: x fits into an int64 - use compact encoding - p.tag(int64Tag) - p.int64(v) - return - } - // uncommon case: large x - use float encoding - // (powers of 2 will be encoded efficiently with exponent) - p.tag(floatTag) - p.float(constant.ToFloat(x)) - - case constant.Float: - p.tag(floatTag) - p.float(x) - - case constant.Complex: - p.tag(complexTag) - p.float(constant.Real(x)) - p.float(constant.Imag(x)) - - case constant.String: - p.tag(stringTag) - p.string(constant.StringVal(x)) - - case constant.Unknown: - // package contains type errors - p.tag(unknownTag) - - default: - panic(internalErrorf("unexpected value %v (%T)", x, x)) - } -} - -func (p *exporter) float(x constant.Value) { - if x.Kind() != constant.Float { - panic(internalErrorf("unexpected constant %v, want float", x)) - } - // extract sign (there is no -0) - sign := constant.Sign(x) - if sign == 0 { - // x == 0 - p.int(0) - return - } - // x != 0 - - var f big.Float - if v, exact := constant.Float64Val(x); exact { - // float64 - f.SetFloat64(v) - } else if num, denom := constant.Num(x), constant.Denom(x); num.Kind() == constant.Int { - // TODO(gri): add big.Rat accessor to constant.Value. - r := valueToRat(num) - f.SetRat(r.Quo(r, valueToRat(denom))) - } else { - // Value too large to represent as a fraction => inaccessible. - // TODO(gri): add big.Float accessor to constant.Value. - f.SetFloat64(math.MaxFloat64) // FIXME - } - - // extract exponent such that 0.5 <= m < 1.0 - var m big.Float - exp := f.MantExp(&m) - - // extract mantissa as *big.Int - // - set exponent large enough so mant satisfies mant.IsInt() - // - get *big.Int from mant - m.SetMantExp(&m, int(m.MinPrec())) - mant, acc := m.Int(nil) - if acc != big.Exact { - panic(internalError("internal error")) - } - - p.int(sign) - p.int(exp) - p.string(string(mant.Bytes())) -} - -func valueToRat(x constant.Value) *big.Rat { - // Convert little-endian to big-endian. - // I can't believe this is necessary. - bytes := constant.Bytes(x) - for i := 0; i < len(bytes)/2; i++ { - bytes[i], bytes[len(bytes)-1-i] = bytes[len(bytes)-1-i], bytes[i] - } - return new(big.Rat).SetInt(new(big.Int).SetBytes(bytes)) -} - -func (p *exporter) bool(b bool) bool { - if trace { - p.tracef("[") - defer p.tracef("= %v] ", b) - } - - x := 0 - if b { - x = 1 - } - p.int(x) - return b -} - -// ---------------------------------------------------------------------------- -// Low-level encoders - -func (p *exporter) index(marker byte, index int) { - if index < 0 { - panic(internalError("invalid index < 0")) - } - if debugFormat { - p.marker('t') - } - if trace { - p.tracef("%c%d ", marker, index) - } - p.rawInt64(int64(index)) -} - -func (p *exporter) tag(tag int) { - if tag >= 0 { - panic(internalError("invalid tag >= 0")) - } - if debugFormat { - p.marker('t') - } - if trace { - p.tracef("%s ", tagString[-tag]) - } - p.rawInt64(int64(tag)) -} - -func (p *exporter) int(x int) { - p.int64(int64(x)) -} - -func (p *exporter) int64(x int64) { - if debugFormat { - p.marker('i') - } - if trace { - p.tracef("%d ", x) - } - p.rawInt64(x) -} - -func (p *exporter) string(s string) { - if debugFormat { - p.marker('s') - } - if trace { - p.tracef("%q ", s) - } - // if we saw the string before, write its index (>= 0) - // (the empty string is mapped to 0) - if i, ok := p.strIndex[s]; ok { - p.rawInt64(int64(i)) - return - } - // otherwise, remember string and write its negative length and bytes - p.strIndex[s] = len(p.strIndex) - p.rawInt64(-int64(len(s))) - for i := 0; i < len(s); i++ { - p.rawByte(s[i]) - } -} - -// marker emits a marker byte and position information which makes -// it easy for a reader to detect if it is "out of sync". Used for -// debugFormat format only. -func (p *exporter) marker(m byte) { - p.rawByte(m) - // Enable this for help tracking down the location - // of an incorrect marker when running in debugFormat. - if false && trace { - p.tracef("#%d ", p.written) - } - p.rawInt64(int64(p.written)) -} - -// rawInt64 should only be used by low-level encoders. -func (p *exporter) rawInt64(x int64) { - var tmp [binary.MaxVarintLen64]byte - n := binary.PutVarint(tmp[:], x) - for i := 0; i < n; i++ { - p.rawByte(tmp[i]) - } -} - -// rawStringln should only be used to emit the initial version string. -func (p *exporter) rawStringln(s string) { - for i := 0; i < len(s); i++ { - p.rawByte(s[i]) - } - p.rawByte('\n') -} - -// rawByte is the bottleneck interface to write to p.out. -// rawByte escapes b as follows (any encoding does that -// hides '$'): -// -// '$' => '|' 'S' -// '|' => '|' '|' -// -// Necessary so other tools can find the end of the -// export data by searching for "$$". -// rawByte should only be used by low-level encoders. -func (p *exporter) rawByte(b byte) { - switch b { - case '$': - // write '$' as '|' 'S' - b = 'S' - fallthrough - case '|': - // write '|' as '|' '|' - p.out.WriteByte('|') - p.written++ - } - p.out.WriteByte(b) - p.written++ -} - -// tracef is like fmt.Printf but it rewrites the format string -// to take care of indentation. -func (p *exporter) tracef(format string, args ...interface{}) { - if strings.ContainsAny(format, "<>\n") { - var buf bytes.Buffer - for i := 0; i < len(format); i++ { - // no need to deal with runes - ch := format[i] - switch ch { - case '>': - p.indent++ - continue - case '<': - p.indent-- - continue - } - buf.WriteByte(ch) - if ch == '\n' { - for j := p.indent; j > 0; j-- { - buf.WriteString(". ") - } - } - } - format = buf.String() - } - fmt.Printf(format, args...) -} - -// Debugging support. -// (tagString is only used when tracing is enabled) -var tagString = [...]string{ - // Packages - -packageTag: "package", - - // Types - -namedTag: "named type", - -arrayTag: "array", - -sliceTag: "slice", - -dddTag: "ddd", - -structTag: "struct", - -pointerTag: "pointer", - -signatureTag: "signature", - -interfaceTag: "interface", - -mapTag: "map", - -chanTag: "chan", - - // Values - -falseTag: "false", - -trueTag: "true", - -int64Tag: "int64", - -floatTag: "float", - -fractionTag: "fraction", - -complexTag: "complex", - -stringTag: "string", - -unknownTag: "unknown", - - // Type aliases - -aliasTag: "alias", -} diff --git a/vendor/golang.org/x/tools/internal/gcimporter/bimport.go b/vendor/golang.org/x/tools/internal/gcimporter/bimport.go deleted file mode 100644 index b85de014700..00000000000 --- a/vendor/golang.org/x/tools/internal/gcimporter/bimport.go +++ /dev/null @@ -1,1053 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// This file is a copy of $GOROOT/src/go/internal/gcimporter/bimport.go. - -package gcimporter - -import ( - "encoding/binary" - "fmt" - "go/constant" - "go/token" - "go/types" - "sort" - "strconv" - "strings" - "sync" - "unicode" - "unicode/utf8" -) - -type importer struct { - imports map[string]*types.Package - data []byte - importpath string - buf []byte // for reading strings - version int // export format version - - // object lists - strList []string // in order of appearance - pathList []string // in order of appearance - pkgList []*types.Package // in order of appearance - typList []types.Type // in order of appearance - interfaceList []*types.Interface // for delayed completion only - trackAllTypes bool - - // position encoding - posInfoFormat bool - prevFile string - prevLine int - fake fakeFileSet - - // debugging support - debugFormat bool - read int // bytes read -} - -// BImportData imports a package from the serialized package data -// and returns the number of bytes consumed and a reference to the package. -// If the export data version is not recognized or the format is otherwise -// compromised, an error is returned. -func BImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, pkg *types.Package, err error) { - // catch panics and return them as errors - const currentVersion = 6 - version := -1 // unknown version - defer func() { - if e := recover(); e != nil { - // Return a (possibly nil or incomplete) package unchanged (see #16088). - if version > currentVersion { - err = fmt.Errorf("cannot import %q (%v), export data is newer version - update tool", path, e) - } else { - err = fmt.Errorf("cannot import %q (%v), possibly version skew - reinstall package", path, e) - } - } - }() - - p := importer{ - imports: imports, - data: data, - importpath: path, - version: version, - strList: []string{""}, // empty string is mapped to 0 - pathList: []string{""}, // empty string is mapped to 0 - fake: fakeFileSet{ - fset: fset, - files: make(map[string]*fileInfo), - }, - } - defer p.fake.setLines() // set lines for files in fset - - // read version info - var versionstr string - if b := p.rawByte(); b == 'c' || b == 'd' { - // Go1.7 encoding; first byte encodes low-level - // encoding format (compact vs debug). - // For backward-compatibility only (avoid problems with - // old installed packages). Newly compiled packages use - // the extensible format string. - // TODO(gri) Remove this support eventually; after Go1.8. - if b == 'd' { - p.debugFormat = true - } - p.trackAllTypes = p.rawByte() == 'a' - p.posInfoFormat = p.int() != 0 - versionstr = p.string() - if versionstr == "v1" { - version = 0 - } - } else { - // Go1.8 extensible encoding - // read version string and extract version number (ignore anything after the version number) - versionstr = p.rawStringln(b) - if s := strings.SplitN(versionstr, " ", 3); len(s) >= 2 && s[0] == "version" { - if v, err := strconv.Atoi(s[1]); err == nil && v > 0 { - version = v - } - } - } - p.version = version - - // read version specific flags - extend as necessary - switch p.version { - // case currentVersion: - // ... - // fallthrough - case currentVersion, 5, 4, 3, 2, 1: - p.debugFormat = p.rawStringln(p.rawByte()) == "debug" - p.trackAllTypes = p.int() != 0 - p.posInfoFormat = p.int() != 0 - case 0: - // Go1.7 encoding format - nothing to do here - default: - errorf("unknown bexport format version %d (%q)", p.version, versionstr) - } - - // --- generic export data --- - - // populate typList with predeclared "known" types - p.typList = append(p.typList, predeclared()...) - - // read package data - pkg = p.pkg() - - // read objects of phase 1 only (see cmd/compile/internal/gc/bexport.go) - objcount := 0 - for { - tag := p.tagOrIndex() - if tag == endTag { - break - } - p.obj(tag) - objcount++ - } - - // self-verification - if count := p.int(); count != objcount { - errorf("got %d objects; want %d", objcount, count) - } - - // ignore compiler-specific import data - - // complete interfaces - // TODO(gri) re-investigate if we still need to do this in a delayed fashion - for _, typ := range p.interfaceList { - typ.Complete() - } - - // record all referenced packages as imports - list := append(([]*types.Package)(nil), p.pkgList[1:]...) - sort.Sort(byPath(list)) - pkg.SetImports(list) - - // package was imported completely and without errors - pkg.MarkComplete() - - return p.read, pkg, nil -} - -func errorf(format string, args ...interface{}) { - panic(fmt.Sprintf(format, args...)) -} - -func (p *importer) pkg() *types.Package { - // if the package was seen before, i is its index (>= 0) - i := p.tagOrIndex() - if i >= 0 { - return p.pkgList[i] - } - - // otherwise, i is the package tag (< 0) - if i != packageTag { - errorf("unexpected package tag %d version %d", i, p.version) - } - - // read package data - name := p.string() - var path string - if p.version >= 5 { - path = p.path() - } else { - path = p.string() - } - if p.version >= 6 { - p.int() // package height; unused by go/types - } - - // we should never see an empty package name - if name == "" { - errorf("empty package name in import") - } - - // an empty path denotes the package we are currently importing; - // it must be the first package we see - if (path == "") != (len(p.pkgList) == 0) { - errorf("package path %q for pkg index %d", path, len(p.pkgList)) - } - - // if the package was imported before, use that one; otherwise create a new one - if path == "" { - path = p.importpath - } - pkg := p.imports[path] - if pkg == nil { - pkg = types.NewPackage(path, name) - p.imports[path] = pkg - } else if pkg.Name() != name { - errorf("conflicting names %s and %s for package %q", pkg.Name(), name, path) - } - p.pkgList = append(p.pkgList, pkg) - - return pkg -} - -// objTag returns the tag value for each object kind. -func objTag(obj types.Object) int { - switch obj.(type) { - case *types.Const: - return constTag - case *types.TypeName: - return typeTag - case *types.Var: - return varTag - case *types.Func: - return funcTag - default: - errorf("unexpected object: %v (%T)", obj, obj) // panics - panic("unreachable") - } -} - -func sameObj(a, b types.Object) bool { - // Because unnamed types are not canonicalized, we cannot simply compare types for - // (pointer) identity. - // Ideally we'd check equality of constant values as well, but this is good enough. - return objTag(a) == objTag(b) && types.Identical(a.Type(), b.Type()) -} - -func (p *importer) declare(obj types.Object) { - pkg := obj.Pkg() - if alt := pkg.Scope().Insert(obj); alt != nil { - // This can only trigger if we import a (non-type) object a second time. - // Excluding type aliases, this cannot happen because 1) we only import a package - // once; and b) we ignore compiler-specific export data which may contain - // functions whose inlined function bodies refer to other functions that - // were already imported. - // However, type aliases require reexporting the original type, so we need - // to allow it (see also the comment in cmd/compile/internal/gc/bimport.go, - // method importer.obj, switch case importing functions). - // TODO(gri) review/update this comment once the gc compiler handles type aliases. - if !sameObj(obj, alt) { - errorf("inconsistent import:\n\t%v\npreviously imported as:\n\t%v\n", obj, alt) - } - } -} - -func (p *importer) obj(tag int) { - switch tag { - case constTag: - pos := p.pos() - pkg, name := p.qualifiedName() - typ := p.typ(nil, nil) - val := p.value() - p.declare(types.NewConst(pos, pkg, name, typ, val)) - - case aliasTag: - // TODO(gri) verify type alias hookup is correct - pos := p.pos() - pkg, name := p.qualifiedName() - typ := p.typ(nil, nil) - p.declare(types.NewTypeName(pos, pkg, name, typ)) - - case typeTag: - p.typ(nil, nil) - - case varTag: - pos := p.pos() - pkg, name := p.qualifiedName() - typ := p.typ(nil, nil) - p.declare(types.NewVar(pos, pkg, name, typ)) - - case funcTag: - pos := p.pos() - pkg, name := p.qualifiedName() - params, isddd := p.paramList() - result, _ := p.paramList() - sig := types.NewSignature(nil, params, result, isddd) - p.declare(types.NewFunc(pos, pkg, name, sig)) - - default: - errorf("unexpected object tag %d", tag) - } -} - -const deltaNewFile = -64 // see cmd/compile/internal/gc/bexport.go - -func (p *importer) pos() token.Pos { - if !p.posInfoFormat { - return token.NoPos - } - - file := p.prevFile - line := p.prevLine - delta := p.int() - line += delta - if p.version >= 5 { - if delta == deltaNewFile { - if n := p.int(); n >= 0 { - // file changed - file = p.path() - line = n - } - } - } else { - if delta == 0 { - if n := p.int(); n >= 0 { - // file changed - file = p.prevFile[:n] + p.string() - line = p.int() - } - } - } - p.prevFile = file - p.prevLine = line - - return p.fake.pos(file, line, 0) -} - -// Synthesize a token.Pos -type fakeFileSet struct { - fset *token.FileSet - files map[string]*fileInfo -} - -type fileInfo struct { - file *token.File - lastline int -} - -const maxlines = 64 * 1024 - -func (s *fakeFileSet) pos(file string, line, column int) token.Pos { - // TODO(mdempsky): Make use of column. - - // Since we don't know the set of needed file positions, we reserve maxlines - // positions per file. We delay calling token.File.SetLines until all - // positions have been calculated (by way of fakeFileSet.setLines), so that - // we can avoid setting unnecessary lines. See also golang/go#46586. - f := s.files[file] - if f == nil { - f = &fileInfo{file: s.fset.AddFile(file, -1, maxlines)} - s.files[file] = f - } - if line > maxlines { - line = 1 - } - if line > f.lastline { - f.lastline = line - } - - // Return a fake position assuming that f.file consists only of newlines. - return token.Pos(f.file.Base() + line - 1) -} - -func (s *fakeFileSet) setLines() { - fakeLinesOnce.Do(func() { - fakeLines = make([]int, maxlines) - for i := range fakeLines { - fakeLines[i] = i - } - }) - for _, f := range s.files { - f.file.SetLines(fakeLines[:f.lastline]) - } -} - -var ( - fakeLines []int - fakeLinesOnce sync.Once -) - -func (p *importer) qualifiedName() (pkg *types.Package, name string) { - name = p.string() - pkg = p.pkg() - return -} - -func (p *importer) record(t types.Type) { - p.typList = append(p.typList, t) -} - -// A dddSlice is a types.Type representing ...T parameters. -// It only appears for parameter types and does not escape -// the importer. -type dddSlice struct { - elem types.Type -} - -func (t *dddSlice) Underlying() types.Type { return t } -func (t *dddSlice) String() string { return "..." + t.elem.String() } - -// parent is the package which declared the type; parent == nil means -// the package currently imported. The parent package is needed for -// exported struct fields and interface methods which don't contain -// explicit package information in the export data. -// -// A non-nil tname is used as the "owner" of the result type; i.e., -// the result type is the underlying type of tname. tname is used -// to give interface methods a named receiver type where possible. -func (p *importer) typ(parent *types.Package, tname *types.Named) types.Type { - // if the type was seen before, i is its index (>= 0) - i := p.tagOrIndex() - if i >= 0 { - return p.typList[i] - } - - // otherwise, i is the type tag (< 0) - switch i { - case namedTag: - // read type object - pos := p.pos() - parent, name := p.qualifiedName() - scope := parent.Scope() - obj := scope.Lookup(name) - - // if the object doesn't exist yet, create and insert it - if obj == nil { - obj = types.NewTypeName(pos, parent, name, nil) - scope.Insert(obj) - } - - if _, ok := obj.(*types.TypeName); !ok { - errorf("pkg = %s, name = %s => %s", parent, name, obj) - } - - // associate new named type with obj if it doesn't exist yet - t0 := types.NewNamed(obj.(*types.TypeName), nil, nil) - - // but record the existing type, if any - tname := obj.Type().(*types.Named) // tname is either t0 or the existing type - p.record(tname) - - // read underlying type - t0.SetUnderlying(p.typ(parent, t0)) - - // interfaces don't have associated methods - if types.IsInterface(t0) { - return tname - } - - // read associated methods - for i := p.int(); i > 0; i-- { - // TODO(gri) replace this with something closer to fieldName - pos := p.pos() - name := p.string() - if !exported(name) { - p.pkg() - } - - recv, _ := p.paramList() // TODO(gri) do we need a full param list for the receiver? - params, isddd := p.paramList() - result, _ := p.paramList() - p.int() // go:nointerface pragma - discarded - - sig := types.NewSignature(recv.At(0), params, result, isddd) - t0.AddMethod(types.NewFunc(pos, parent, name, sig)) - } - - return tname - - case arrayTag: - t := new(types.Array) - if p.trackAllTypes { - p.record(t) - } - - n := p.int64() - *t = *types.NewArray(p.typ(parent, nil), n) - return t - - case sliceTag: - t := new(types.Slice) - if p.trackAllTypes { - p.record(t) - } - - *t = *types.NewSlice(p.typ(parent, nil)) - return t - - case dddTag: - t := new(dddSlice) - if p.trackAllTypes { - p.record(t) - } - - t.elem = p.typ(parent, nil) - return t - - case structTag: - t := new(types.Struct) - if p.trackAllTypes { - p.record(t) - } - - *t = *types.NewStruct(p.fieldList(parent)) - return t - - case pointerTag: - t := new(types.Pointer) - if p.trackAllTypes { - p.record(t) - } - - *t = *types.NewPointer(p.typ(parent, nil)) - return t - - case signatureTag: - t := new(types.Signature) - if p.trackAllTypes { - p.record(t) - } - - params, isddd := p.paramList() - result, _ := p.paramList() - *t = *types.NewSignature(nil, params, result, isddd) - return t - - case interfaceTag: - // Create a dummy entry in the type list. This is safe because we - // cannot expect the interface type to appear in a cycle, as any - // such cycle must contain a named type which would have been - // first defined earlier. - // TODO(gri) Is this still true now that we have type aliases? - // See issue #23225. - n := len(p.typList) - if p.trackAllTypes { - p.record(nil) - } - - var embeddeds []types.Type - for n := p.int(); n > 0; n-- { - p.pos() - embeddeds = append(embeddeds, p.typ(parent, nil)) - } - - t := newInterface(p.methodList(parent, tname), embeddeds) - p.interfaceList = append(p.interfaceList, t) - if p.trackAllTypes { - p.typList[n] = t - } - return t - - case mapTag: - t := new(types.Map) - if p.trackAllTypes { - p.record(t) - } - - key := p.typ(parent, nil) - val := p.typ(parent, nil) - *t = *types.NewMap(key, val) - return t - - case chanTag: - t := new(types.Chan) - if p.trackAllTypes { - p.record(t) - } - - dir := chanDir(p.int()) - val := p.typ(parent, nil) - *t = *types.NewChan(dir, val) - return t - - default: - errorf("unexpected type tag %d", i) // panics - panic("unreachable") - } -} - -func chanDir(d int) types.ChanDir { - // tag values must match the constants in cmd/compile/internal/gc/go.go - switch d { - case 1 /* Crecv */ : - return types.RecvOnly - case 2 /* Csend */ : - return types.SendOnly - case 3 /* Cboth */ : - return types.SendRecv - default: - errorf("unexpected channel dir %d", d) - return 0 - } -} - -func (p *importer) fieldList(parent *types.Package) (fields []*types.Var, tags []string) { - if n := p.int(); n > 0 { - fields = make([]*types.Var, n) - tags = make([]string, n) - for i := range fields { - fields[i], tags[i] = p.field(parent) - } - } - return -} - -func (p *importer) field(parent *types.Package) (*types.Var, string) { - pos := p.pos() - pkg, name, alias := p.fieldName(parent) - typ := p.typ(parent, nil) - tag := p.string() - - anonymous := false - if name == "" { - // anonymous field - typ must be T or *T and T must be a type name - switch typ := deref(typ).(type) { - case *types.Basic: // basic types are named types - pkg = nil // // objects defined in Universe scope have no package - name = typ.Name() - case *types.Named: - name = typ.Obj().Name() - default: - errorf("named base type expected") - } - anonymous = true - } else if alias { - // anonymous field: we have an explicit name because it's an alias - anonymous = true - } - - return types.NewField(pos, pkg, name, typ, anonymous), tag -} - -func (p *importer) methodList(parent *types.Package, baseType *types.Named) (methods []*types.Func) { - if n := p.int(); n > 0 { - methods = make([]*types.Func, n) - for i := range methods { - methods[i] = p.method(parent, baseType) - } - } - return -} - -func (p *importer) method(parent *types.Package, baseType *types.Named) *types.Func { - pos := p.pos() - pkg, name, _ := p.fieldName(parent) - // If we don't have a baseType, use a nil receiver. - // A receiver using the actual interface type (which - // we don't know yet) will be filled in when we call - // types.Interface.Complete. - var recv *types.Var - if baseType != nil { - recv = types.NewVar(token.NoPos, parent, "", baseType) - } - params, isddd := p.paramList() - result, _ := p.paramList() - sig := types.NewSignature(recv, params, result, isddd) - return types.NewFunc(pos, pkg, name, sig) -} - -func (p *importer) fieldName(parent *types.Package) (pkg *types.Package, name string, alias bool) { - name = p.string() - pkg = parent - if pkg == nil { - // use the imported package instead - pkg = p.pkgList[0] - } - if p.version == 0 && name == "_" { - // version 0 didn't export a package for _ fields - return - } - switch name { - case "": - // 1) field name matches base type name and is exported: nothing to do - case "?": - // 2) field name matches base type name and is not exported: need package - name = "" - pkg = p.pkg() - case "@": - // 3) field name doesn't match type name (alias) - name = p.string() - alias = true - fallthrough - default: - if !exported(name) { - pkg = p.pkg() - } - } - return -} - -func (p *importer) paramList() (*types.Tuple, bool) { - n := p.int() - if n == 0 { - return nil, false - } - // negative length indicates unnamed parameters - named := true - if n < 0 { - n = -n - named = false - } - // n > 0 - params := make([]*types.Var, n) - isddd := false - for i := range params { - params[i], isddd = p.param(named) - } - return types.NewTuple(params...), isddd -} - -func (p *importer) param(named bool) (*types.Var, bool) { - t := p.typ(nil, nil) - td, isddd := t.(*dddSlice) - if isddd { - t = types.NewSlice(td.elem) - } - - var pkg *types.Package - var name string - if named { - name = p.string() - if name == "" { - errorf("expected named parameter") - } - if name != "_" { - pkg = p.pkg() - } - if i := strings.Index(name, "·"); i > 0 { - name = name[:i] // cut off gc-specific parameter numbering - } - } - - // read and discard compiler-specific info - p.string() - - return types.NewVar(token.NoPos, pkg, name, t), isddd -} - -func exported(name string) bool { - ch, _ := utf8.DecodeRuneInString(name) - return unicode.IsUpper(ch) -} - -func (p *importer) value() constant.Value { - switch tag := p.tagOrIndex(); tag { - case falseTag: - return constant.MakeBool(false) - case trueTag: - return constant.MakeBool(true) - case int64Tag: - return constant.MakeInt64(p.int64()) - case floatTag: - return p.float() - case complexTag: - re := p.float() - im := p.float() - return constant.BinaryOp(re, token.ADD, constant.MakeImag(im)) - case stringTag: - return constant.MakeString(p.string()) - case unknownTag: - return constant.MakeUnknown() - default: - errorf("unexpected value tag %d", tag) // panics - panic("unreachable") - } -} - -func (p *importer) float() constant.Value { - sign := p.int() - if sign == 0 { - return constant.MakeInt64(0) - } - - exp := p.int() - mant := []byte(p.string()) // big endian - - // remove leading 0's if any - for len(mant) > 0 && mant[0] == 0 { - mant = mant[1:] - } - - // convert to little endian - // TODO(gri) go/constant should have a more direct conversion function - // (e.g., once it supports a big.Float based implementation) - for i, j := 0, len(mant)-1; i < j; i, j = i+1, j-1 { - mant[i], mant[j] = mant[j], mant[i] - } - - // adjust exponent (constant.MakeFromBytes creates an integer value, - // but mant represents the mantissa bits such that 0.5 <= mant < 1.0) - exp -= len(mant) << 3 - if len(mant) > 0 { - for msd := mant[len(mant)-1]; msd&0x80 == 0; msd <<= 1 { - exp++ - } - } - - x := constant.MakeFromBytes(mant) - switch { - case exp < 0: - d := constant.Shift(constant.MakeInt64(1), token.SHL, uint(-exp)) - x = constant.BinaryOp(x, token.QUO, d) - case exp > 0: - x = constant.Shift(x, token.SHL, uint(exp)) - } - - if sign < 0 { - x = constant.UnaryOp(token.SUB, x, 0) - } - return x -} - -// ---------------------------------------------------------------------------- -// Low-level decoders - -func (p *importer) tagOrIndex() int { - if p.debugFormat { - p.marker('t') - } - - return int(p.rawInt64()) -} - -func (p *importer) int() int { - x := p.int64() - if int64(int(x)) != x { - errorf("exported integer too large") - } - return int(x) -} - -func (p *importer) int64() int64 { - if p.debugFormat { - p.marker('i') - } - - return p.rawInt64() -} - -func (p *importer) path() string { - if p.debugFormat { - p.marker('p') - } - // if the path was seen before, i is its index (>= 0) - // (the empty string is at index 0) - i := p.rawInt64() - if i >= 0 { - return p.pathList[i] - } - // otherwise, i is the negative path length (< 0) - a := make([]string, -i) - for n := range a { - a[n] = p.string() - } - s := strings.Join(a, "/") - p.pathList = append(p.pathList, s) - return s -} - -func (p *importer) string() string { - if p.debugFormat { - p.marker('s') - } - // if the string was seen before, i is its index (>= 0) - // (the empty string is at index 0) - i := p.rawInt64() - if i >= 0 { - return p.strList[i] - } - // otherwise, i is the negative string length (< 0) - if n := int(-i); n <= cap(p.buf) { - p.buf = p.buf[:n] - } else { - p.buf = make([]byte, n) - } - for i := range p.buf { - p.buf[i] = p.rawByte() - } - s := string(p.buf) - p.strList = append(p.strList, s) - return s -} - -func (p *importer) marker(want byte) { - if got := p.rawByte(); got != want { - errorf("incorrect marker: got %c; want %c (pos = %d)", got, want, p.read) - } - - pos := p.read - if n := int(p.rawInt64()); n != pos { - errorf("incorrect position: got %d; want %d", n, pos) - } -} - -// rawInt64 should only be used by low-level decoders. -func (p *importer) rawInt64() int64 { - i, err := binary.ReadVarint(p) - if err != nil { - errorf("read error: %v", err) - } - return i -} - -// rawStringln should only be used to read the initial version string. -func (p *importer) rawStringln(b byte) string { - p.buf = p.buf[:0] - for b != '\n' { - p.buf = append(p.buf, b) - b = p.rawByte() - } - return string(p.buf) -} - -// needed for binary.ReadVarint in rawInt64 -func (p *importer) ReadByte() (byte, error) { - return p.rawByte(), nil -} - -// byte is the bottleneck interface for reading p.data. -// It unescapes '|' 'S' to '$' and '|' '|' to '|'. -// rawByte should only be used by low-level decoders. -func (p *importer) rawByte() byte { - b := p.data[0] - r := 1 - if b == '|' { - b = p.data[1] - r = 2 - switch b { - case 'S': - b = '$' - case '|': - // nothing to do - default: - errorf("unexpected escape sequence in export data") - } - } - p.data = p.data[r:] - p.read += r - return b - -} - -// ---------------------------------------------------------------------------- -// Export format - -// Tags. Must be < 0. -const ( - // Objects - packageTag = -(iota + 1) - constTag - typeTag - varTag - funcTag - endTag - - // Types - namedTag - arrayTag - sliceTag - dddTag - structTag - pointerTag - signatureTag - interfaceTag - mapTag - chanTag - - // Values - falseTag - trueTag - int64Tag - floatTag - fractionTag // not used by gc - complexTag - stringTag - nilTag // only used by gc (appears in exported inlined function bodies) - unknownTag // not used by gc (only appears in packages with errors) - - // Type aliases - aliasTag -) - -var predeclOnce sync.Once -var predecl []types.Type // initialized lazily - -func predeclared() []types.Type { - predeclOnce.Do(func() { - // initialize lazily to be sure that all - // elements have been initialized before - predecl = []types.Type{ // basic types - types.Typ[types.Bool], - types.Typ[types.Int], - types.Typ[types.Int8], - types.Typ[types.Int16], - types.Typ[types.Int32], - types.Typ[types.Int64], - types.Typ[types.Uint], - types.Typ[types.Uint8], - types.Typ[types.Uint16], - types.Typ[types.Uint32], - types.Typ[types.Uint64], - types.Typ[types.Uintptr], - types.Typ[types.Float32], - types.Typ[types.Float64], - types.Typ[types.Complex64], - types.Typ[types.Complex128], - types.Typ[types.String], - - // basic type aliases - types.Universe.Lookup("byte").Type(), - types.Universe.Lookup("rune").Type(), - - // error - types.Universe.Lookup("error").Type(), - - // untyped types - types.Typ[types.UntypedBool], - types.Typ[types.UntypedInt], - types.Typ[types.UntypedRune], - types.Typ[types.UntypedFloat], - types.Typ[types.UntypedComplex], - types.Typ[types.UntypedString], - types.Typ[types.UntypedNil], - - // package unsafe - types.Typ[types.UnsafePointer], - - // invalid type - types.Typ[types.Invalid], // only appears in packages with errors - - // used internally by gc; never used by this package or in .a files - anyType{}, - } - predecl = append(predecl, additionalPredeclared()...) - }) - return predecl -} - -type anyType struct{} - -func (t anyType) Underlying() types.Type { return t } -func (t anyType) String() string { return "any" } diff --git a/vendor/golang.org/x/tools/internal/gcimporter/exportdata.go b/vendor/golang.org/x/tools/internal/gcimporter/exportdata.go deleted file mode 100644 index f6437feb1cf..00000000000 --- a/vendor/golang.org/x/tools/internal/gcimporter/exportdata.go +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// This file is a copy of $GOROOT/src/go/internal/gcimporter/exportdata.go. - -// This file implements FindExportData. - -package gcimporter - -import ( - "bufio" - "fmt" - "io" - "strconv" - "strings" -) - -func readGopackHeader(r *bufio.Reader) (name string, size int64, err error) { - // See $GOROOT/include/ar.h. - hdr := make([]byte, 16+12+6+6+8+10+2) - _, err = io.ReadFull(r, hdr) - if err != nil { - return - } - // leave for debugging - if false { - fmt.Printf("header: %s", hdr) - } - s := strings.TrimSpace(string(hdr[16+12+6+6+8:][:10])) - length, err := strconv.Atoi(s) - size = int64(length) - if err != nil || hdr[len(hdr)-2] != '`' || hdr[len(hdr)-1] != '\n' { - err = fmt.Errorf("invalid archive header") - return - } - name = strings.TrimSpace(string(hdr[:16])) - return -} - -// FindExportData positions the reader r at the beginning of the -// export data section of an underlying GC-created object/archive -// file by reading from it. The reader must be positioned at the -// start of the file before calling this function. The hdr result -// is the string before the export data, either "$$" or "$$B". -// The size result is the length of the export data in bytes, or -1 if not known. -func FindExportData(r *bufio.Reader) (hdr string, size int64, err error) { - // Read first line to make sure this is an object file. - line, err := r.ReadSlice('\n') - if err != nil { - err = fmt.Errorf("can't find export data (%v)", err) - return - } - - if string(line) == "!\n" { - // Archive file. Scan to __.PKGDEF. - var name string - if name, size, err = readGopackHeader(r); err != nil { - return - } - - // First entry should be __.PKGDEF. - if name != "__.PKGDEF" { - err = fmt.Errorf("go archive is missing __.PKGDEF") - return - } - - // Read first line of __.PKGDEF data, so that line - // is once again the first line of the input. - if line, err = r.ReadSlice('\n'); err != nil { - err = fmt.Errorf("can't find export data (%v)", err) - return - } - size -= int64(len(line)) - } - - // Now at __.PKGDEF in archive or still at beginning of file. - // Either way, line should begin with "go object ". - if !strings.HasPrefix(string(line), "go object ") { - err = fmt.Errorf("not a Go object file") - return - } - - // Skip over object header to export data. - // Begins after first line starting with $$. - for line[0] != '$' { - if line, err = r.ReadSlice('\n'); err != nil { - err = fmt.Errorf("can't find export data (%v)", err) - return - } - size -= int64(len(line)) - } - hdr = string(line) - if size < 0 { - size = -1 - } - - return -} diff --git a/vendor/golang.org/x/tools/internal/gcimporter/gcimporter.go b/vendor/golang.org/x/tools/internal/gcimporter/gcimporter.go deleted file mode 100644 index 0372fb3a646..00000000000 --- a/vendor/golang.org/x/tools/internal/gcimporter/gcimporter.go +++ /dev/null @@ -1,265 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// This file is a reduced copy of $GOROOT/src/go/internal/gcimporter/gcimporter.go. - -// Package gcimporter provides various functions for reading -// gc-generated object files that can be used to implement the -// Importer interface defined by the Go 1.5 standard library package. -package gcimporter // import "golang.org/x/tools/internal/gcimporter" - -import ( - "bufio" - "bytes" - "fmt" - "go/build" - "go/token" - "go/types" - "io" - "io/ioutil" - "os" - "os/exec" - "path/filepath" - "strings" - "sync" -) - -const ( - // Enable debug during development: it adds some additional checks, and - // prevents errors from being recovered. - debug = false - - // If trace is set, debugging output is printed to std out. - trace = false -) - -var exportMap sync.Map // package dir → func() (string, bool) - -// lookupGorootExport returns the location of the export data -// (normally found in the build cache, but located in GOROOT/pkg -// in prior Go releases) for the package located in pkgDir. -// -// (We use the package's directory instead of its import path -// mainly to simplify handling of the packages in src/vendor -// and cmd/vendor.) -func lookupGorootExport(pkgDir string) (string, bool) { - f, ok := exportMap.Load(pkgDir) - if !ok { - var ( - listOnce sync.Once - exportPath string - ) - f, _ = exportMap.LoadOrStore(pkgDir, func() (string, bool) { - listOnce.Do(func() { - cmd := exec.Command("go", "list", "-export", "-f", "{{.Export}}", pkgDir) - cmd.Dir = build.Default.GOROOT - var output []byte - output, err := cmd.Output() - if err != nil { - return - } - - exports := strings.Split(string(bytes.TrimSpace(output)), "\n") - if len(exports) != 1 { - return - } - - exportPath = exports[0] - }) - - return exportPath, exportPath != "" - }) - } - - return f.(func() (string, bool))() -} - -var pkgExts = [...]string{".a", ".o"} - -// FindPkg returns the filename and unique package id for an import -// path based on package information provided by build.Import (using -// the build.Default build.Context). A relative srcDir is interpreted -// relative to the current working directory. -// If no file was found, an empty filename is returned. -func FindPkg(path, srcDir string) (filename, id string) { - if path == "" { - return - } - - var noext string - switch { - default: - // "x" -> "$GOPATH/pkg/$GOOS_$GOARCH/x.ext", "x" - // Don't require the source files to be present. - if abs, err := filepath.Abs(srcDir); err == nil { // see issue 14282 - srcDir = abs - } - bp, _ := build.Import(path, srcDir, build.FindOnly|build.AllowBinary) - if bp.PkgObj == "" { - var ok bool - if bp.Goroot && bp.Dir != "" { - filename, ok = lookupGorootExport(bp.Dir) - } - if !ok { - id = path // make sure we have an id to print in error message - return - } - } else { - noext = strings.TrimSuffix(bp.PkgObj, ".a") - id = bp.ImportPath - } - - case build.IsLocalImport(path): - // "./x" -> "/this/directory/x.ext", "/this/directory/x" - noext = filepath.Join(srcDir, path) - id = noext - - case filepath.IsAbs(path): - // for completeness only - go/build.Import - // does not support absolute imports - // "/x" -> "/x.ext", "/x" - noext = path - id = path - } - - if false { // for debugging - if path != id { - fmt.Printf("%s -> %s\n", path, id) - } - } - - if filename != "" { - if f, err := os.Stat(filename); err == nil && !f.IsDir() { - return - } - } - - // try extensions - for _, ext := range pkgExts { - filename = noext + ext - if f, err := os.Stat(filename); err == nil && !f.IsDir() { - return - } - } - - filename = "" // not found - return -} - -// Import imports a gc-generated package given its import path and srcDir, adds -// the corresponding package object to the packages map, and returns the object. -// The packages map must contain all packages already imported. -func Import(packages map[string]*types.Package, path, srcDir string, lookup func(path string) (io.ReadCloser, error)) (pkg *types.Package, err error) { - var rc io.ReadCloser - var filename, id string - if lookup != nil { - // With custom lookup specified, assume that caller has - // converted path to a canonical import path for use in the map. - if path == "unsafe" { - return types.Unsafe, nil - } - id = path - - // No need to re-import if the package was imported completely before. - if pkg = packages[id]; pkg != nil && pkg.Complete() { - return - } - f, err := lookup(path) - if err != nil { - return nil, err - } - rc = f - } else { - filename, id = FindPkg(path, srcDir) - if filename == "" { - if path == "unsafe" { - return types.Unsafe, nil - } - return nil, fmt.Errorf("can't find import: %q", id) - } - - // no need to re-import if the package was imported completely before - if pkg = packages[id]; pkg != nil && pkg.Complete() { - return - } - - // open file - f, err := os.Open(filename) - if err != nil { - return nil, err - } - defer func() { - if err != nil { - // add file name to error - err = fmt.Errorf("%s: %v", filename, err) - } - }() - rc = f - } - defer rc.Close() - - var hdr string - var size int64 - buf := bufio.NewReader(rc) - if hdr, size, err = FindExportData(buf); err != nil { - return - } - - switch hdr { - case "$$B\n": - var data []byte - data, err = ioutil.ReadAll(buf) - if err != nil { - break - } - - // TODO(gri): allow clients of go/importer to provide a FileSet. - // Or, define a new standard go/types/gcexportdata package. - fset := token.NewFileSet() - - // The indexed export format starts with an 'i'; the older - // binary export format starts with a 'c', 'd', or 'v' - // (from "version"). Select appropriate importer. - if len(data) > 0 { - switch data[0] { - case 'i': - _, pkg, err := IImportData(fset, packages, data[1:], id) - return pkg, err - - case 'v', 'c', 'd': - _, pkg, err := BImportData(fset, packages, data, id) - return pkg, err - - case 'u': - _, pkg, err := UImportData(fset, packages, data[1:size], id) - return pkg, err - - default: - l := len(data) - if l > 10 { - l = 10 - } - return nil, fmt.Errorf("unexpected export data with prefix %q for path %s", string(data[:l]), id) - } - } - - default: - err = fmt.Errorf("unknown export data header: %q", hdr) - } - - return -} - -func deref(typ types.Type) types.Type { - if p, _ := typ.(*types.Pointer); p != nil { - return p.Elem() - } - return typ -} - -type byPath []*types.Package - -func (a byPath) Len() int { return len(a) } -func (a byPath) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a byPath) Less(i, j int) bool { return a[i].Path() < a[j].Path() } diff --git a/vendor/golang.org/x/tools/internal/gcimporter/iexport.go b/vendor/golang.org/x/tools/internal/gcimporter/iexport.go deleted file mode 100644 index ba53cdcdd10..00000000000 --- a/vendor/golang.org/x/tools/internal/gcimporter/iexport.go +++ /dev/null @@ -1,1180 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Indexed binary package export. -// This file was derived from $GOROOT/src/cmd/compile/internal/gc/iexport.go; -// see that file for specification of the format. - -package gcimporter - -import ( - "bytes" - "encoding/binary" - "fmt" - "go/constant" - "go/token" - "go/types" - "io" - "math/big" - "reflect" - "sort" - "strconv" - "strings" - - "golang.org/x/tools/internal/tokeninternal" - "golang.org/x/tools/internal/typeparams" -) - -// IExportShallow encodes "shallow" export data for the specified package. -// -// No promises are made about the encoding other than that it can be -// decoded by the same version of IIExportShallow. If you plan to save -// export data in the file system, be sure to include a cryptographic -// digest of the executable in the key to avoid version skew. -func IExportShallow(fset *token.FileSet, pkg *types.Package) ([]byte, error) { - // In principle this operation can only fail if out.Write fails, - // but that's impossible for bytes.Buffer---and as a matter of - // fact iexportCommon doesn't even check for I/O errors. - // TODO(adonovan): handle I/O errors properly. - // TODO(adonovan): use byte slices throughout, avoiding copying. - const bundle, shallow = false, true - var out bytes.Buffer - err := iexportCommon(&out, fset, bundle, shallow, iexportVersion, []*types.Package{pkg}) - return out.Bytes(), err -} - -// IImportShallow decodes "shallow" types.Package data encoded by IExportShallow -// in the same executable. This function cannot import data from -// cmd/compile or gcexportdata.Write. -func IImportShallow(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string, insert InsertType) (*types.Package, error) { - const bundle = false - pkgs, err := iimportCommon(fset, imports, data, bundle, path, insert) - if err != nil { - return nil, err - } - return pkgs[0], nil -} - -// InsertType is the type of a function that creates a types.TypeName -// object for a named type and inserts it into the scope of the -// specified Package. -type InsertType = func(pkg *types.Package, name string) - -// Current bundled export format version. Increase with each format change. -// 0: initial implementation -const bundleVersion = 0 - -// IExportData writes indexed export data for pkg to out. -// -// If no file set is provided, position info will be missing. -// The package path of the top-level package will not be recorded, -// so that calls to IImportData can override with a provided package path. -func IExportData(out io.Writer, fset *token.FileSet, pkg *types.Package) error { - const bundle, shallow = false, false - return iexportCommon(out, fset, bundle, shallow, iexportVersion, []*types.Package{pkg}) -} - -// IExportBundle writes an indexed export bundle for pkgs to out. -func IExportBundle(out io.Writer, fset *token.FileSet, pkgs []*types.Package) error { - const bundle, shallow = true, false - return iexportCommon(out, fset, bundle, shallow, iexportVersion, pkgs) -} - -func iexportCommon(out io.Writer, fset *token.FileSet, bundle, shallow bool, version int, pkgs []*types.Package) (err error) { - if !debug { - defer func() { - if e := recover(); e != nil { - if ierr, ok := e.(internalError); ok { - err = ierr - return - } - // Not an internal error; panic again. - panic(e) - } - }() - } - - p := iexporter{ - fset: fset, - version: version, - shallow: shallow, - allPkgs: map[*types.Package]bool{}, - stringIndex: map[string]uint64{}, - declIndex: map[types.Object]uint64{}, - tparamNames: map[types.Object]string{}, - typIndex: map[types.Type]uint64{}, - } - if !bundle { - p.localpkg = pkgs[0] - } - - for i, pt := range predeclared() { - p.typIndex[pt] = uint64(i) - } - if len(p.typIndex) > predeclReserved { - panic(internalErrorf("too many predeclared types: %d > %d", len(p.typIndex), predeclReserved)) - } - - // Initialize work queue with exported declarations. - for _, pkg := range pkgs { - scope := pkg.Scope() - for _, name := range scope.Names() { - if token.IsExported(name) { - p.pushDecl(scope.Lookup(name)) - } - } - - if bundle { - // Ensure pkg and its imports are included in the index. - p.allPkgs[pkg] = true - for _, imp := range pkg.Imports() { - p.allPkgs[imp] = true - } - } - } - - // Loop until no more work. - for !p.declTodo.empty() { - p.doDecl(p.declTodo.popHead()) - } - - // Produce index of offset of each file record in files. - var files intWriter - var fileOffset []uint64 // fileOffset[i] is offset in files of file encoded as i - if p.shallow { - fileOffset = make([]uint64, len(p.fileInfos)) - for i, info := range p.fileInfos { - fileOffset[i] = uint64(files.Len()) - p.encodeFile(&files, info.file, info.needed) - } - } - - // Append indices to data0 section. - dataLen := uint64(p.data0.Len()) - w := p.newWriter() - w.writeIndex(p.declIndex) - - if bundle { - w.uint64(uint64(len(pkgs))) - for _, pkg := range pkgs { - w.pkg(pkg) - imps := pkg.Imports() - w.uint64(uint64(len(imps))) - for _, imp := range imps { - w.pkg(imp) - } - } - } - w.flush() - - // Assemble header. - var hdr intWriter - if bundle { - hdr.uint64(bundleVersion) - } - hdr.uint64(uint64(p.version)) - hdr.uint64(uint64(p.strings.Len())) - if p.shallow { - hdr.uint64(uint64(files.Len())) - hdr.uint64(uint64(len(fileOffset))) - for _, offset := range fileOffset { - hdr.uint64(offset) - } - } - hdr.uint64(dataLen) - - // Flush output. - io.Copy(out, &hdr) - io.Copy(out, &p.strings) - if p.shallow { - io.Copy(out, &files) - } - io.Copy(out, &p.data0) - - return nil -} - -// encodeFile writes to w a representation of the file sufficient to -// faithfully restore position information about all needed offsets. -// Mutates the needed array. -func (p *iexporter) encodeFile(w *intWriter, file *token.File, needed []uint64) { - _ = needed[0] // precondition: needed is non-empty - - w.uint64(p.stringOff(file.Name())) - - size := uint64(file.Size()) - w.uint64(size) - - // Sort the set of needed offsets. Duplicates are harmless. - sort.Slice(needed, func(i, j int) bool { return needed[i] < needed[j] }) - - lines := tokeninternal.GetLines(file) // byte offset of each line start - w.uint64(uint64(len(lines))) - - // Rather than record the entire array of line start offsets, - // we save only a sparse list of (index, offset) pairs for - // the start of each line that contains a needed position. - var sparse [][2]int // (index, offset) pairs -outer: - for i, lineStart := range lines { - lineEnd := size - if i < len(lines)-1 { - lineEnd = uint64(lines[i+1]) - } - // Does this line contains a needed offset? - if needed[0] < lineEnd { - sparse = append(sparse, [2]int{i, lineStart}) - for needed[0] < lineEnd { - needed = needed[1:] - if len(needed) == 0 { - break outer - } - } - } - } - - // Delta-encode the columns. - w.uint64(uint64(len(sparse))) - var prev [2]int - for _, pair := range sparse { - w.uint64(uint64(pair[0] - prev[0])) - w.uint64(uint64(pair[1] - prev[1])) - prev = pair - } -} - -// writeIndex writes out an object index. mainIndex indicates whether -// we're writing out the main index, which is also read by -// non-compiler tools and includes a complete package description -// (i.e., name and height). -func (w *exportWriter) writeIndex(index map[types.Object]uint64) { - type pkgObj struct { - obj types.Object - name string // qualified name; differs from obj.Name for type params - } - // Build a map from packages to objects from that package. - pkgObjs := map[*types.Package][]pkgObj{} - - // For the main index, make sure to include every package that - // we reference, even if we're not exporting (or reexporting) - // any symbols from it. - if w.p.localpkg != nil { - pkgObjs[w.p.localpkg] = nil - } - for pkg := range w.p.allPkgs { - pkgObjs[pkg] = nil - } - - for obj := range index { - name := w.p.exportName(obj) - pkgObjs[obj.Pkg()] = append(pkgObjs[obj.Pkg()], pkgObj{obj, name}) - } - - var pkgs []*types.Package - for pkg, objs := range pkgObjs { - pkgs = append(pkgs, pkg) - - sort.Slice(objs, func(i, j int) bool { - return objs[i].name < objs[j].name - }) - } - - sort.Slice(pkgs, func(i, j int) bool { - return w.exportPath(pkgs[i]) < w.exportPath(pkgs[j]) - }) - - w.uint64(uint64(len(pkgs))) - for _, pkg := range pkgs { - w.string(w.exportPath(pkg)) - w.string(pkg.Name()) - w.uint64(uint64(0)) // package height is not needed for go/types - - objs := pkgObjs[pkg] - w.uint64(uint64(len(objs))) - for _, obj := range objs { - w.string(obj.name) - w.uint64(index[obj.obj]) - } - } -} - -// exportName returns the 'exported' name of an object. It differs from -// obj.Name() only for type parameters (see tparamExportName for details). -func (p *iexporter) exportName(obj types.Object) (res string) { - if name := p.tparamNames[obj]; name != "" { - return name - } - return obj.Name() -} - -type iexporter struct { - fset *token.FileSet - out *bytes.Buffer - version int - - shallow bool // don't put types from other packages in the index - localpkg *types.Package // (nil in bundle mode) - - // allPkgs tracks all packages that have been referenced by - // the export data, so we can ensure to include them in the - // main index. - allPkgs map[*types.Package]bool - - declTodo objQueue - - strings intWriter - stringIndex map[string]uint64 - - // In shallow mode, object positions are encoded as (file, offset). - // Each file is recorded as a line-number table. - // Only the lines of needed positions are saved faithfully. - fileInfo map[*token.File]uint64 // value is index in fileInfos - fileInfos []*filePositions - - data0 intWriter - declIndex map[types.Object]uint64 - tparamNames map[types.Object]string // typeparam->exported name - typIndex map[types.Type]uint64 - - indent int // for tracing support -} - -type filePositions struct { - file *token.File - needed []uint64 // unordered list of needed file offsets -} - -func (p *iexporter) trace(format string, args ...interface{}) { - if !trace { - // Call sites should also be guarded, but having this check here allows - // easily enabling/disabling debug trace statements. - return - } - fmt.Printf(strings.Repeat("..", p.indent)+format+"\n", args...) -} - -// stringOff returns the offset of s within the string section. -// If not already present, it's added to the end. -func (p *iexporter) stringOff(s string) uint64 { - off, ok := p.stringIndex[s] - if !ok { - off = uint64(p.strings.Len()) - p.stringIndex[s] = off - - p.strings.uint64(uint64(len(s))) - p.strings.WriteString(s) - } - return off -} - -// fileIndexAndOffset returns the index of the token.File and the byte offset of pos within it. -func (p *iexporter) fileIndexAndOffset(file *token.File, pos token.Pos) (uint64, uint64) { - index, ok := p.fileInfo[file] - if !ok { - index = uint64(len(p.fileInfo)) - p.fileInfos = append(p.fileInfos, &filePositions{file: file}) - if p.fileInfo == nil { - p.fileInfo = make(map[*token.File]uint64) - } - p.fileInfo[file] = index - } - // Record each needed offset. - info := p.fileInfos[index] - offset := uint64(file.Offset(pos)) - info.needed = append(info.needed, offset) - - return index, offset -} - -// pushDecl adds n to the declaration work queue, if not already present. -func (p *iexporter) pushDecl(obj types.Object) { - // Package unsafe is known to the compiler and predeclared. - // Caller should not ask us to do export it. - if obj.Pkg() == types.Unsafe { - panic("cannot export package unsafe") - } - - // Shallow export data: don't index decls from other packages. - if p.shallow && obj.Pkg() != p.localpkg { - return - } - - if _, ok := p.declIndex[obj]; ok { - return - } - - p.declIndex[obj] = ^uint64(0) // mark obj present in work queue - p.declTodo.pushTail(obj) -} - -// exportWriter handles writing out individual data section chunks. -type exportWriter struct { - p *iexporter - - data intWriter - currPkg *types.Package - prevFile string - prevLine int64 - prevColumn int64 -} - -func (w *exportWriter) exportPath(pkg *types.Package) string { - if pkg == w.p.localpkg { - return "" - } - return pkg.Path() -} - -func (p *iexporter) doDecl(obj types.Object) { - if trace { - p.trace("exporting decl %v (%T)", obj, obj) - p.indent++ - defer func() { - p.indent-- - p.trace("=> %s", obj) - }() - } - w := p.newWriter() - w.setPkg(obj.Pkg(), false) - - switch obj := obj.(type) { - case *types.Var: - w.tag('V') - w.pos(obj.Pos()) - w.typ(obj.Type(), obj.Pkg()) - - case *types.Func: - sig, _ := obj.Type().(*types.Signature) - if sig.Recv() != nil { - // We shouldn't see methods in the package scope, - // but the type checker may repair "func () F() {}" - // to "func (Invalid) F()" and then treat it like "func F()", - // so allow that. See golang/go#57729. - if sig.Recv().Type() != types.Typ[types.Invalid] { - panic(internalErrorf("unexpected method: %v", sig)) - } - } - - // Function. - if typeparams.ForSignature(sig).Len() == 0 { - w.tag('F') - } else { - w.tag('G') - } - w.pos(obj.Pos()) - // The tparam list of the function type is the declaration of the type - // params. So, write out the type params right now. Then those type params - // will be referenced via their type offset (via typOff) in all other - // places in the signature and function where they are used. - // - // While importing the type parameters, tparamList computes and records - // their export name, so that it can be later used when writing the index. - if tparams := typeparams.ForSignature(sig); tparams.Len() > 0 { - w.tparamList(obj.Name(), tparams, obj.Pkg()) - } - w.signature(sig) - - case *types.Const: - w.tag('C') - w.pos(obj.Pos()) - w.value(obj.Type(), obj.Val()) - - case *types.TypeName: - t := obj.Type() - - if tparam, ok := t.(*typeparams.TypeParam); ok { - w.tag('P') - w.pos(obj.Pos()) - constraint := tparam.Constraint() - if p.version >= iexportVersionGo1_18 { - implicit := false - if iface, _ := constraint.(*types.Interface); iface != nil { - implicit = typeparams.IsImplicit(iface) - } - w.bool(implicit) - } - w.typ(constraint, obj.Pkg()) - break - } - - if obj.IsAlias() { - w.tag('A') - w.pos(obj.Pos()) - w.typ(t, obj.Pkg()) - break - } - - // Defined type. - named, ok := t.(*types.Named) - if !ok { - panic(internalErrorf("%s is not a defined type", t)) - } - - if typeparams.ForNamed(named).Len() == 0 { - w.tag('T') - } else { - w.tag('U') - } - w.pos(obj.Pos()) - - if typeparams.ForNamed(named).Len() > 0 { - // While importing the type parameters, tparamList computes and records - // their export name, so that it can be later used when writing the index. - w.tparamList(obj.Name(), typeparams.ForNamed(named), obj.Pkg()) - } - - underlying := obj.Type().Underlying() - w.typ(underlying, obj.Pkg()) - - if types.IsInterface(t) { - break - } - - n := named.NumMethods() - w.uint64(uint64(n)) - for i := 0; i < n; i++ { - m := named.Method(i) - w.pos(m.Pos()) - w.string(m.Name()) - sig, _ := m.Type().(*types.Signature) - - // Receiver type parameters are type arguments of the receiver type, so - // their name must be qualified before exporting recv. - if rparams := typeparams.RecvTypeParams(sig); rparams.Len() > 0 { - prefix := obj.Name() + "." + m.Name() - for i := 0; i < rparams.Len(); i++ { - rparam := rparams.At(i) - name := tparamExportName(prefix, rparam) - w.p.tparamNames[rparam.Obj()] = name - } - } - w.param(sig.Recv()) - w.signature(sig) - } - - default: - panic(internalErrorf("unexpected object: %v", obj)) - } - - p.declIndex[obj] = w.flush() -} - -func (w *exportWriter) tag(tag byte) { - w.data.WriteByte(tag) -} - -func (w *exportWriter) pos(pos token.Pos) { - if w.p.shallow { - w.posV2(pos) - } else if w.p.version >= iexportVersionPosCol { - w.posV1(pos) - } else { - w.posV0(pos) - } -} - -// posV2 encoding (used only in shallow mode) records positions as -// (file, offset), where file is the index in the token.File table -// (which records the file name and newline offsets) and offset is a -// byte offset. It effectively ignores //line directives. -func (w *exportWriter) posV2(pos token.Pos) { - if pos == token.NoPos { - w.uint64(0) - return - } - file := w.p.fset.File(pos) // fset must be non-nil - index, offset := w.p.fileIndexAndOffset(file, pos) - w.uint64(1 + index) - w.uint64(offset) -} - -func (w *exportWriter) posV1(pos token.Pos) { - if w.p.fset == nil { - w.int64(0) - return - } - - p := w.p.fset.Position(pos) - file := p.Filename - line := int64(p.Line) - column := int64(p.Column) - - deltaColumn := (column - w.prevColumn) << 1 - deltaLine := (line - w.prevLine) << 1 - - if file != w.prevFile { - deltaLine |= 1 - } - if deltaLine != 0 { - deltaColumn |= 1 - } - - w.int64(deltaColumn) - if deltaColumn&1 != 0 { - w.int64(deltaLine) - if deltaLine&1 != 0 { - w.string(file) - } - } - - w.prevFile = file - w.prevLine = line - w.prevColumn = column -} - -func (w *exportWriter) posV0(pos token.Pos) { - if w.p.fset == nil { - w.int64(0) - return - } - - p := w.p.fset.Position(pos) - file := p.Filename - line := int64(p.Line) - - // When file is the same as the last position (common case), - // we can save a few bytes by delta encoding just the line - // number. - // - // Note: Because data objects may be read out of order (or not - // at all), we can only apply delta encoding within a single - // object. This is handled implicitly by tracking prevFile and - // prevLine as fields of exportWriter. - - if file == w.prevFile { - delta := line - w.prevLine - w.int64(delta) - if delta == deltaNewFile { - w.int64(-1) - } - } else { - w.int64(deltaNewFile) - w.int64(line) // line >= 0 - w.string(file) - w.prevFile = file - } - w.prevLine = line -} - -func (w *exportWriter) pkg(pkg *types.Package) { - // Ensure any referenced packages are declared in the main index. - w.p.allPkgs[pkg] = true - - w.string(w.exportPath(pkg)) -} - -func (w *exportWriter) qualifiedType(obj *types.TypeName) { - name := w.p.exportName(obj) - - // Ensure any referenced declarations are written out too. - w.p.pushDecl(obj) - w.string(name) - w.pkg(obj.Pkg()) -} - -func (w *exportWriter) typ(t types.Type, pkg *types.Package) { - w.data.uint64(w.p.typOff(t, pkg)) -} - -func (p *iexporter) newWriter() *exportWriter { - return &exportWriter{p: p} -} - -func (w *exportWriter) flush() uint64 { - off := uint64(w.p.data0.Len()) - io.Copy(&w.p.data0, &w.data) - return off -} - -func (p *iexporter) typOff(t types.Type, pkg *types.Package) uint64 { - off, ok := p.typIndex[t] - if !ok { - w := p.newWriter() - w.doTyp(t, pkg) - off = predeclReserved + w.flush() - p.typIndex[t] = off - } - return off -} - -func (w *exportWriter) startType(k itag) { - w.data.uint64(uint64(k)) -} - -func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) { - if trace { - w.p.trace("exporting type %s (%T)", t, t) - w.p.indent++ - defer func() { - w.p.indent-- - w.p.trace("=> %s", t) - }() - } - switch t := t.(type) { - case *types.Named: - if targs := typeparams.NamedTypeArgs(t); targs.Len() > 0 { - w.startType(instanceType) - // TODO(rfindley): investigate if this position is correct, and if it - // matters. - w.pos(t.Obj().Pos()) - w.typeList(targs, pkg) - w.typ(typeparams.NamedTypeOrigin(t), pkg) - return - } - w.startType(definedType) - w.qualifiedType(t.Obj()) - - case *typeparams.TypeParam: - w.startType(typeParamType) - w.qualifiedType(t.Obj()) - - case *types.Pointer: - w.startType(pointerType) - w.typ(t.Elem(), pkg) - - case *types.Slice: - w.startType(sliceType) - w.typ(t.Elem(), pkg) - - case *types.Array: - w.startType(arrayType) - w.uint64(uint64(t.Len())) - w.typ(t.Elem(), pkg) - - case *types.Chan: - w.startType(chanType) - // 1 RecvOnly; 2 SendOnly; 3 SendRecv - var dir uint64 - switch t.Dir() { - case types.RecvOnly: - dir = 1 - case types.SendOnly: - dir = 2 - case types.SendRecv: - dir = 3 - } - w.uint64(dir) - w.typ(t.Elem(), pkg) - - case *types.Map: - w.startType(mapType) - w.typ(t.Key(), pkg) - w.typ(t.Elem(), pkg) - - case *types.Signature: - w.startType(signatureType) - w.setPkg(pkg, true) - w.signature(t) - - case *types.Struct: - w.startType(structType) - n := t.NumFields() - if n > 0 { - w.setPkg(t.Field(0).Pkg(), true) // qualifying package for field objects - } else { - w.setPkg(pkg, true) - } - w.uint64(uint64(n)) - for i := 0; i < n; i++ { - f := t.Field(i) - w.pos(f.Pos()) - w.string(f.Name()) // unexported fields implicitly qualified by prior setPkg - w.typ(f.Type(), pkg) - w.bool(f.Anonymous()) - w.string(t.Tag(i)) // note (or tag) - } - - case *types.Interface: - w.startType(interfaceType) - w.setPkg(pkg, true) - - n := t.NumEmbeddeds() - w.uint64(uint64(n)) - for i := 0; i < n; i++ { - ft := t.EmbeddedType(i) - tPkg := pkg - if named, _ := ft.(*types.Named); named != nil { - w.pos(named.Obj().Pos()) - } else { - w.pos(token.NoPos) - } - w.typ(ft, tPkg) - } - - n = t.NumExplicitMethods() - w.uint64(uint64(n)) - for i := 0; i < n; i++ { - m := t.ExplicitMethod(i) - w.pos(m.Pos()) - w.string(m.Name()) - sig, _ := m.Type().(*types.Signature) - w.signature(sig) - } - - case *typeparams.Union: - w.startType(unionType) - nt := t.Len() - w.uint64(uint64(nt)) - for i := 0; i < nt; i++ { - term := t.Term(i) - w.bool(term.Tilde()) - w.typ(term.Type(), pkg) - } - - default: - panic(internalErrorf("unexpected type: %v, %v", t, reflect.TypeOf(t))) - } -} - -func (w *exportWriter) setPkg(pkg *types.Package, write bool) { - if write { - w.pkg(pkg) - } - - w.currPkg = pkg -} - -func (w *exportWriter) signature(sig *types.Signature) { - w.paramList(sig.Params()) - w.paramList(sig.Results()) - if sig.Params().Len() > 0 { - w.bool(sig.Variadic()) - } -} - -func (w *exportWriter) typeList(ts *typeparams.TypeList, pkg *types.Package) { - w.uint64(uint64(ts.Len())) - for i := 0; i < ts.Len(); i++ { - w.typ(ts.At(i), pkg) - } -} - -func (w *exportWriter) tparamList(prefix string, list *typeparams.TypeParamList, pkg *types.Package) { - ll := uint64(list.Len()) - w.uint64(ll) - for i := 0; i < list.Len(); i++ { - tparam := list.At(i) - // Set the type parameter exportName before exporting its type. - exportName := tparamExportName(prefix, tparam) - w.p.tparamNames[tparam.Obj()] = exportName - w.typ(list.At(i), pkg) - } -} - -const blankMarker = "$" - -// tparamExportName returns the 'exported' name of a type parameter, which -// differs from its actual object name: it is prefixed with a qualifier, and -// blank type parameter names are disambiguated by their index in the type -// parameter list. -func tparamExportName(prefix string, tparam *typeparams.TypeParam) string { - assert(prefix != "") - name := tparam.Obj().Name() - if name == "_" { - name = blankMarker + strconv.Itoa(tparam.Index()) - } - return prefix + "." + name -} - -// tparamName returns the real name of a type parameter, after stripping its -// qualifying prefix and reverting blank-name encoding. See tparamExportName -// for details. -func tparamName(exportName string) string { - // Remove the "path" from the type param name that makes it unique. - ix := strings.LastIndex(exportName, ".") - if ix < 0 { - errorf("malformed type parameter export name %s: missing prefix", exportName) - } - name := exportName[ix+1:] - if strings.HasPrefix(name, blankMarker) { - return "_" - } - return name -} - -func (w *exportWriter) paramList(tup *types.Tuple) { - n := tup.Len() - w.uint64(uint64(n)) - for i := 0; i < n; i++ { - w.param(tup.At(i)) - } -} - -func (w *exportWriter) param(obj types.Object) { - w.pos(obj.Pos()) - w.localIdent(obj) - w.typ(obj.Type(), obj.Pkg()) -} - -func (w *exportWriter) value(typ types.Type, v constant.Value) { - w.typ(typ, nil) - if w.p.version >= iexportVersionGo1_18 { - w.int64(int64(v.Kind())) - } - - switch b := typ.Underlying().(*types.Basic); b.Info() & types.IsConstType { - case types.IsBoolean: - w.bool(constant.BoolVal(v)) - case types.IsInteger: - var i big.Int - if i64, exact := constant.Int64Val(v); exact { - i.SetInt64(i64) - } else if ui64, exact := constant.Uint64Val(v); exact { - i.SetUint64(ui64) - } else { - i.SetString(v.ExactString(), 10) - } - w.mpint(&i, typ) - case types.IsFloat: - f := constantToFloat(v) - w.mpfloat(f, typ) - case types.IsComplex: - w.mpfloat(constantToFloat(constant.Real(v)), typ) - w.mpfloat(constantToFloat(constant.Imag(v)), typ) - case types.IsString: - w.string(constant.StringVal(v)) - default: - if b.Kind() == types.Invalid { - // package contains type errors - break - } - panic(internalErrorf("unexpected type %v (%v)", typ, typ.Underlying())) - } -} - -// constantToFloat converts a constant.Value with kind constant.Float to a -// big.Float. -func constantToFloat(x constant.Value) *big.Float { - x = constant.ToFloat(x) - // Use the same floating-point precision (512) as cmd/compile - // (see Mpprec in cmd/compile/internal/gc/mpfloat.go). - const mpprec = 512 - var f big.Float - f.SetPrec(mpprec) - if v, exact := constant.Float64Val(x); exact { - // float64 - f.SetFloat64(v) - } else if num, denom := constant.Num(x), constant.Denom(x); num.Kind() == constant.Int { - // TODO(gri): add big.Rat accessor to constant.Value. - n := valueToRat(num) - d := valueToRat(denom) - f.SetRat(n.Quo(n, d)) - } else { - // Value too large to represent as a fraction => inaccessible. - // TODO(gri): add big.Float accessor to constant.Value. - _, ok := f.SetString(x.ExactString()) - assert(ok) - } - return &f -} - -// mpint exports a multi-precision integer. -// -// For unsigned types, small values are written out as a single -// byte. Larger values are written out as a length-prefixed big-endian -// byte string, where the length prefix is encoded as its complement. -// For example, bytes 0, 1, and 2 directly represent the integer -// values 0, 1, and 2; while bytes 255, 254, and 253 indicate a 1-, -// 2-, and 3-byte big-endian string follow. -// -// Encoding for signed types use the same general approach as for -// unsigned types, except small values use zig-zag encoding and the -// bottom bit of length prefix byte for large values is reserved as a -// sign bit. -// -// The exact boundary between small and large encodings varies -// according to the maximum number of bytes needed to encode a value -// of type typ. As a special case, 8-bit types are always encoded as a -// single byte. -// -// TODO(mdempsky): Is this level of complexity really worthwhile? -func (w *exportWriter) mpint(x *big.Int, typ types.Type) { - basic, ok := typ.Underlying().(*types.Basic) - if !ok { - panic(internalErrorf("unexpected type %v (%T)", typ.Underlying(), typ.Underlying())) - } - - signed, maxBytes := intSize(basic) - - negative := x.Sign() < 0 - if !signed && negative { - panic(internalErrorf("negative unsigned integer; type %v, value %v", typ, x)) - } - - b := x.Bytes() - if len(b) > 0 && b[0] == 0 { - panic(internalErrorf("leading zeros")) - } - if uint(len(b)) > maxBytes { - panic(internalErrorf("bad mpint length: %d > %d (type %v, value %v)", len(b), maxBytes, typ, x)) - } - - maxSmall := 256 - maxBytes - if signed { - maxSmall = 256 - 2*maxBytes - } - if maxBytes == 1 { - maxSmall = 256 - } - - // Check if x can use small value encoding. - if len(b) <= 1 { - var ux uint - if len(b) == 1 { - ux = uint(b[0]) - } - if signed { - ux <<= 1 - if negative { - ux-- - } - } - if ux < maxSmall { - w.data.WriteByte(byte(ux)) - return - } - } - - n := 256 - uint(len(b)) - if signed { - n = 256 - 2*uint(len(b)) - if negative { - n |= 1 - } - } - if n < maxSmall || n >= 256 { - panic(internalErrorf("encoding mistake: %d, %v, %v => %d", len(b), signed, negative, n)) - } - - w.data.WriteByte(byte(n)) - w.data.Write(b) -} - -// mpfloat exports a multi-precision floating point number. -// -// The number's value is decomposed into mantissa × 2**exponent, where -// mantissa is an integer. The value is written out as mantissa (as a -// multi-precision integer) and then the exponent, except exponent is -// omitted if mantissa is zero. -func (w *exportWriter) mpfloat(f *big.Float, typ types.Type) { - if f.IsInf() { - panic("infinite constant") - } - - // Break into f = mant × 2**exp, with 0.5 <= mant < 1. - var mant big.Float - exp := int64(f.MantExp(&mant)) - - // Scale so that mant is an integer. - prec := mant.MinPrec() - mant.SetMantExp(&mant, int(prec)) - exp -= int64(prec) - - manti, acc := mant.Int(nil) - if acc != big.Exact { - panic(internalErrorf("mantissa scaling failed for %f (%s)", f, acc)) - } - w.mpint(manti, typ) - if manti.Sign() != 0 { - w.int64(exp) - } -} - -func (w *exportWriter) bool(b bool) bool { - var x uint64 - if b { - x = 1 - } - w.uint64(x) - return b -} - -func (w *exportWriter) int64(x int64) { w.data.int64(x) } -func (w *exportWriter) uint64(x uint64) { w.data.uint64(x) } -func (w *exportWriter) string(s string) { w.uint64(w.p.stringOff(s)) } - -func (w *exportWriter) localIdent(obj types.Object) { - // Anonymous parameters. - if obj == nil { - w.string("") - return - } - - name := obj.Name() - if name == "_" { - w.string("_") - return - } - - w.string(name) -} - -type intWriter struct { - bytes.Buffer -} - -func (w *intWriter) int64(x int64) { - var buf [binary.MaxVarintLen64]byte - n := binary.PutVarint(buf[:], x) - w.Write(buf[:n]) -} - -func (w *intWriter) uint64(x uint64) { - var buf [binary.MaxVarintLen64]byte - n := binary.PutUvarint(buf[:], x) - w.Write(buf[:n]) -} - -func assert(cond bool) { - if !cond { - panic("internal error: assertion failed") - } -} - -// The below is copied from go/src/cmd/compile/internal/gc/syntax.go. - -// objQueue is a FIFO queue of types.Object. The zero value of objQueue is -// a ready-to-use empty queue. -type objQueue struct { - ring []types.Object - head, tail int -} - -// empty returns true if q contains no Nodes. -func (q *objQueue) empty() bool { - return q.head == q.tail -} - -// pushTail appends n to the tail of the queue. -func (q *objQueue) pushTail(obj types.Object) { - if len(q.ring) == 0 { - q.ring = make([]types.Object, 16) - } else if q.head+len(q.ring) == q.tail { - // Grow the ring. - nring := make([]types.Object, len(q.ring)*2) - // Copy the old elements. - part := q.ring[q.head%len(q.ring):] - if q.tail-q.head <= len(part) { - part = part[:q.tail-q.head] - copy(nring, part) - } else { - pos := copy(nring, part) - copy(nring[pos:], q.ring[:q.tail%len(q.ring)]) - } - q.ring, q.head, q.tail = nring, 0, q.tail-q.head - } - - q.ring[q.tail%len(q.ring)] = obj - q.tail++ -} - -// popHead pops a node from the head of the queue. It panics if q is empty. -func (q *objQueue) popHead() types.Object { - if q.empty() { - panic("dequeue empty") - } - obj := q.ring[q.head%len(q.ring)] - q.head++ - return obj -} diff --git a/vendor/golang.org/x/tools/internal/gcimporter/iimport.go b/vendor/golang.org/x/tools/internal/gcimporter/iimport.go deleted file mode 100644 index 448f903e86a..00000000000 --- a/vendor/golang.org/x/tools/internal/gcimporter/iimport.go +++ /dev/null @@ -1,976 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Indexed package import. -// See cmd/compile/internal/gc/iexport.go for the export data format. - -// This file is a copy of $GOROOT/src/go/internal/gcimporter/iimport.go. - -package gcimporter - -import ( - "bytes" - "encoding/binary" - "fmt" - "go/constant" - "go/token" - "go/types" - "io" - "math/big" - "sort" - "strings" - - "golang.org/x/tools/internal/typeparams" -) - -type intReader struct { - *bytes.Reader - path string -} - -func (r *intReader) int64() int64 { - i, err := binary.ReadVarint(r.Reader) - if err != nil { - errorf("import %q: read varint error: %v", r.path, err) - } - return i -} - -func (r *intReader) uint64() uint64 { - i, err := binary.ReadUvarint(r.Reader) - if err != nil { - errorf("import %q: read varint error: %v", r.path, err) - } - return i -} - -// Keep this in sync with constants in iexport.go. -const ( - iexportVersionGo1_11 = 0 - iexportVersionPosCol = 1 - iexportVersionGo1_18 = 2 - iexportVersionGenerics = 2 - - iexportVersionCurrent = 2 -) - -type ident struct { - pkg *types.Package - name string -} - -const predeclReserved = 32 - -type itag uint64 - -const ( - // Types - definedType itag = iota - pointerType - sliceType - arrayType - chanType - mapType - signatureType - structType - interfaceType - typeParamType - instanceType - unionType -) - -// IImportData imports a package from the serialized package data -// and returns 0 and a reference to the package. -// If the export data version is not recognized or the format is otherwise -// compromised, an error is returned. -func IImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (int, *types.Package, error) { - pkgs, err := iimportCommon(fset, imports, data, false, path, nil) - if err != nil { - return 0, nil, err - } - return 0, pkgs[0], nil -} - -// IImportBundle imports a set of packages from the serialized package bundle. -func IImportBundle(fset *token.FileSet, imports map[string]*types.Package, data []byte) ([]*types.Package, error) { - return iimportCommon(fset, imports, data, true, "", nil) -} - -func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data []byte, bundle bool, path string, insert InsertType) (pkgs []*types.Package, err error) { - const currentVersion = iexportVersionCurrent - version := int64(-1) - if !debug { - defer func() { - if e := recover(); e != nil { - if bundle { - err = fmt.Errorf("%v", e) - } else if version > currentVersion { - err = fmt.Errorf("cannot import %q (%v), export data is newer version - update tool", path, e) - } else { - err = fmt.Errorf("cannot import %q (%v), possibly version skew - reinstall package", path, e) - } - } - }() - } - - r := &intReader{bytes.NewReader(data), path} - - if bundle { - bundleVersion := r.uint64() - switch bundleVersion { - case bundleVersion: - default: - errorf("unknown bundle format version %d", bundleVersion) - } - } - - version = int64(r.uint64()) - switch version { - case iexportVersionGo1_18, iexportVersionPosCol, iexportVersionGo1_11: - default: - if version > iexportVersionGo1_18 { - errorf("unstable iexport format version %d, just rebuild compiler and std library", version) - } else { - errorf("unknown iexport format version %d", version) - } - } - - sLen := int64(r.uint64()) - var fLen int64 - var fileOffset []uint64 - if insert != nil { - // Shallow mode uses a different position encoding. - fLen = int64(r.uint64()) - fileOffset = make([]uint64, r.uint64()) - for i := range fileOffset { - fileOffset[i] = r.uint64() - } - } - dLen := int64(r.uint64()) - - whence, _ := r.Seek(0, io.SeekCurrent) - stringData := data[whence : whence+sLen] - fileData := data[whence+sLen : whence+sLen+fLen] - declData := data[whence+sLen+fLen : whence+sLen+fLen+dLen] - r.Seek(sLen+fLen+dLen, io.SeekCurrent) - - p := iimporter{ - version: int(version), - ipath: path, - insert: insert, - - stringData: stringData, - stringCache: make(map[uint64]string), - fileOffset: fileOffset, - fileData: fileData, - fileCache: make([]*token.File, len(fileOffset)), - pkgCache: make(map[uint64]*types.Package), - - declData: declData, - pkgIndex: make(map[*types.Package]map[string]uint64), - typCache: make(map[uint64]types.Type), - // Separate map for typeparams, keyed by their package and unique - // name. - tparamIndex: make(map[ident]types.Type), - - fake: fakeFileSet{ - fset: fset, - files: make(map[string]*fileInfo), - }, - } - defer p.fake.setLines() // set lines for files in fset - - for i, pt := range predeclared() { - p.typCache[uint64(i)] = pt - } - - pkgList := make([]*types.Package, r.uint64()) - for i := range pkgList { - pkgPathOff := r.uint64() - pkgPath := p.stringAt(pkgPathOff) - pkgName := p.stringAt(r.uint64()) - _ = r.uint64() // package height; unused by go/types - - if pkgPath == "" { - pkgPath = path - } - pkg := imports[pkgPath] - if pkg == nil { - pkg = types.NewPackage(pkgPath, pkgName) - imports[pkgPath] = pkg - } else if pkg.Name() != pkgName { - errorf("conflicting names %s and %s for package %q", pkg.Name(), pkgName, path) - } - if i == 0 && !bundle { - p.localpkg = pkg - } - - p.pkgCache[pkgPathOff] = pkg - - // Read index for package. - nameIndex := make(map[string]uint64) - nSyms := r.uint64() - // In shallow mode we don't expect an index for other packages. - assert(nSyms == 0 || p.localpkg == pkg || p.insert == nil) - for ; nSyms > 0; nSyms-- { - name := p.stringAt(r.uint64()) - nameIndex[name] = r.uint64() - } - - p.pkgIndex[pkg] = nameIndex - pkgList[i] = pkg - } - - if bundle { - pkgs = make([]*types.Package, r.uint64()) - for i := range pkgs { - pkg := p.pkgAt(r.uint64()) - imps := make([]*types.Package, r.uint64()) - for j := range imps { - imps[j] = p.pkgAt(r.uint64()) - } - pkg.SetImports(imps) - pkgs[i] = pkg - } - } else { - if len(pkgList) == 0 { - errorf("no packages found for %s", path) - panic("unreachable") - } - pkgs = pkgList[:1] - - // record all referenced packages as imports - list := append(([]*types.Package)(nil), pkgList[1:]...) - sort.Sort(byPath(list)) - pkgs[0].SetImports(list) - } - - for _, pkg := range pkgs { - if pkg.Complete() { - continue - } - - names := make([]string, 0, len(p.pkgIndex[pkg])) - for name := range p.pkgIndex[pkg] { - names = append(names, name) - } - sort.Strings(names) - for _, name := range names { - p.doDecl(pkg, name) - } - - // package was imported completely and without errors - pkg.MarkComplete() - } - - // SetConstraint can't be called if the constraint type is not yet complete. - // When type params are created in the 'P' case of (*importReader).obj(), - // the associated constraint type may not be complete due to recursion. - // Therefore, we defer calling SetConstraint there, and call it here instead - // after all types are complete. - for _, d := range p.later { - typeparams.SetTypeParamConstraint(d.t, d.constraint) - } - - for _, typ := range p.interfaceList { - typ.Complete() - } - - return pkgs, nil -} - -type setConstraintArgs struct { - t *typeparams.TypeParam - constraint types.Type -} - -type iimporter struct { - version int - ipath string - - localpkg *types.Package - insert func(pkg *types.Package, name string) // "shallow" mode only - - stringData []byte - stringCache map[uint64]string - fileOffset []uint64 // fileOffset[i] is offset in fileData for info about file encoded as i - fileData []byte - fileCache []*token.File // memoized decoding of file encoded as i - pkgCache map[uint64]*types.Package - - declData []byte - pkgIndex map[*types.Package]map[string]uint64 - typCache map[uint64]types.Type - tparamIndex map[ident]types.Type - - fake fakeFileSet - interfaceList []*types.Interface - - // Arguments for calls to SetConstraint that are deferred due to recursive types - later []setConstraintArgs - - indent int // for tracing support -} - -func (p *iimporter) trace(format string, args ...interface{}) { - if !trace { - // Call sites should also be guarded, but having this check here allows - // easily enabling/disabling debug trace statements. - return - } - fmt.Printf(strings.Repeat("..", p.indent)+format+"\n", args...) -} - -func (p *iimporter) doDecl(pkg *types.Package, name string) { - if debug { - p.trace("import decl %s", name) - p.indent++ - defer func() { - p.indent-- - p.trace("=> %s", name) - }() - } - // See if we've already imported this declaration. - if obj := pkg.Scope().Lookup(name); obj != nil { - return - } - - off, ok := p.pkgIndex[pkg][name] - if !ok { - // In "shallow" mode, call back to the application to - // find the object and insert it into the package scope. - if p.insert != nil { - assert(pkg != p.localpkg) - p.insert(pkg, name) // "can't fail" - return - } - errorf("%v.%v not in index", pkg, name) - } - - r := &importReader{p: p, currPkg: pkg} - r.declReader.Reset(p.declData[off:]) - - r.obj(name) -} - -func (p *iimporter) stringAt(off uint64) string { - if s, ok := p.stringCache[off]; ok { - return s - } - - slen, n := binary.Uvarint(p.stringData[off:]) - if n <= 0 { - errorf("varint failed") - } - spos := off + uint64(n) - s := string(p.stringData[spos : spos+slen]) - p.stringCache[off] = s - return s -} - -func (p *iimporter) fileAt(index uint64) *token.File { - file := p.fileCache[index] - if file == nil { - off := p.fileOffset[index] - file = p.decodeFile(intReader{bytes.NewReader(p.fileData[off:]), p.ipath}) - p.fileCache[index] = file - } - return file -} - -func (p *iimporter) decodeFile(rd intReader) *token.File { - filename := p.stringAt(rd.uint64()) - size := int(rd.uint64()) - file := p.fake.fset.AddFile(filename, -1, size) - - // SetLines requires a nondecreasing sequence. - // Because it is common for clients to derive the interval - // [start, start+len(name)] from a start position, and we - // want to ensure that the end offset is on the same line, - // we fill in the gaps of the sparse encoding with values - // that strictly increase by the largest possible amount. - // This allows us to avoid having to record the actual end - // offset of each needed line. - - lines := make([]int, int(rd.uint64())) - var index, offset int - for i, n := 0, int(rd.uint64()); i < n; i++ { - index += int(rd.uint64()) - offset += int(rd.uint64()) - lines[index] = offset - - // Ensure monotonicity between points. - for j := index - 1; j > 0 && lines[j] == 0; j-- { - lines[j] = lines[j+1] - 1 - } - } - - // Ensure monotonicity after last point. - for j := len(lines) - 1; j > 0 && lines[j] == 0; j-- { - size-- - lines[j] = size - } - - if !file.SetLines(lines) { - errorf("SetLines failed: %d", lines) // can't happen - } - return file -} - -func (p *iimporter) pkgAt(off uint64) *types.Package { - if pkg, ok := p.pkgCache[off]; ok { - return pkg - } - path := p.stringAt(off) - errorf("missing package %q in %q", path, p.ipath) - return nil -} - -func (p *iimporter) typAt(off uint64, base *types.Named) types.Type { - if t, ok := p.typCache[off]; ok && canReuse(base, t) { - return t - } - - if off < predeclReserved { - errorf("predeclared type missing from cache: %v", off) - } - - r := &importReader{p: p} - r.declReader.Reset(p.declData[off-predeclReserved:]) - t := r.doType(base) - - if canReuse(base, t) { - p.typCache[off] = t - } - return t -} - -// canReuse reports whether the type rhs on the RHS of the declaration for def -// may be re-used. -// -// Specifically, if def is non-nil and rhs is an interface type with methods, it -// may not be re-used because we have a convention of setting the receiver type -// for interface methods to def. -func canReuse(def *types.Named, rhs types.Type) bool { - if def == nil { - return true - } - iface, _ := rhs.(*types.Interface) - if iface == nil { - return true - } - // Don't use iface.Empty() here as iface may not be complete. - return iface.NumEmbeddeds() == 0 && iface.NumExplicitMethods() == 0 -} - -type importReader struct { - p *iimporter - declReader bytes.Reader - currPkg *types.Package - prevFile string - prevLine int64 - prevColumn int64 -} - -func (r *importReader) obj(name string) { - tag := r.byte() - pos := r.pos() - - switch tag { - case 'A': - typ := r.typ() - - r.declare(types.NewTypeName(pos, r.currPkg, name, typ)) - - case 'C': - typ, val := r.value() - - r.declare(types.NewConst(pos, r.currPkg, name, typ, val)) - - case 'F', 'G': - var tparams []*typeparams.TypeParam - if tag == 'G' { - tparams = r.tparamList() - } - sig := r.signature(nil, nil, tparams) - r.declare(types.NewFunc(pos, r.currPkg, name, sig)) - - case 'T', 'U': - // Types can be recursive. We need to setup a stub - // declaration before recursing. - obj := types.NewTypeName(pos, r.currPkg, name, nil) - named := types.NewNamed(obj, nil, nil) - // Declare obj before calling r.tparamList, so the new type name is recognized - // if used in the constraint of one of its own typeparams (see #48280). - r.declare(obj) - if tag == 'U' { - tparams := r.tparamList() - typeparams.SetForNamed(named, tparams) - } - - underlying := r.p.typAt(r.uint64(), named).Underlying() - named.SetUnderlying(underlying) - - if !isInterface(underlying) { - for n := r.uint64(); n > 0; n-- { - mpos := r.pos() - mname := r.ident() - recv := r.param() - - // If the receiver has any targs, set those as the - // rparams of the method (since those are the - // typeparams being used in the method sig/body). - base := baseType(recv.Type()) - assert(base != nil) - targs := typeparams.NamedTypeArgs(base) - var rparams []*typeparams.TypeParam - if targs.Len() > 0 { - rparams = make([]*typeparams.TypeParam, targs.Len()) - for i := range rparams { - rparams[i] = targs.At(i).(*typeparams.TypeParam) - } - } - msig := r.signature(recv, rparams, nil) - - named.AddMethod(types.NewFunc(mpos, r.currPkg, mname, msig)) - } - } - - case 'P': - // We need to "declare" a typeparam in order to have a name that - // can be referenced recursively (if needed) in the type param's - // bound. - if r.p.version < iexportVersionGenerics { - errorf("unexpected type param type") - } - name0 := tparamName(name) - tn := types.NewTypeName(pos, r.currPkg, name0, nil) - t := typeparams.NewTypeParam(tn, nil) - - // To handle recursive references to the typeparam within its - // bound, save the partial type in tparamIndex before reading the bounds. - id := ident{r.currPkg, name} - r.p.tparamIndex[id] = t - var implicit bool - if r.p.version >= iexportVersionGo1_18 { - implicit = r.bool() - } - constraint := r.typ() - if implicit { - iface, _ := constraint.(*types.Interface) - if iface == nil { - errorf("non-interface constraint marked implicit") - } - typeparams.MarkImplicit(iface) - } - // The constraint type may not be complete, if we - // are in the middle of a type recursion involving type - // constraints. So, we defer SetConstraint until we have - // completely set up all types in ImportData. - r.p.later = append(r.p.later, setConstraintArgs{t: t, constraint: constraint}) - - case 'V': - typ := r.typ() - - r.declare(types.NewVar(pos, r.currPkg, name, typ)) - - default: - errorf("unexpected tag: %v", tag) - } -} - -func (r *importReader) declare(obj types.Object) { - obj.Pkg().Scope().Insert(obj) -} - -func (r *importReader) value() (typ types.Type, val constant.Value) { - typ = r.typ() - if r.p.version >= iexportVersionGo1_18 { - // TODO: add support for using the kind. - _ = constant.Kind(r.int64()) - } - - switch b := typ.Underlying().(*types.Basic); b.Info() & types.IsConstType { - case types.IsBoolean: - val = constant.MakeBool(r.bool()) - - case types.IsString: - val = constant.MakeString(r.string()) - - case types.IsInteger: - var x big.Int - r.mpint(&x, b) - val = constant.Make(&x) - - case types.IsFloat: - val = r.mpfloat(b) - - case types.IsComplex: - re := r.mpfloat(b) - im := r.mpfloat(b) - val = constant.BinaryOp(re, token.ADD, constant.MakeImag(im)) - - default: - if b.Kind() == types.Invalid { - val = constant.MakeUnknown() - return - } - errorf("unexpected type %v", typ) // panics - panic("unreachable") - } - - return -} - -func intSize(b *types.Basic) (signed bool, maxBytes uint) { - if (b.Info() & types.IsUntyped) != 0 { - return true, 64 - } - - switch b.Kind() { - case types.Float32, types.Complex64: - return true, 3 - case types.Float64, types.Complex128: - return true, 7 - } - - signed = (b.Info() & types.IsUnsigned) == 0 - switch b.Kind() { - case types.Int8, types.Uint8: - maxBytes = 1 - case types.Int16, types.Uint16: - maxBytes = 2 - case types.Int32, types.Uint32: - maxBytes = 4 - default: - maxBytes = 8 - } - - return -} - -func (r *importReader) mpint(x *big.Int, typ *types.Basic) { - signed, maxBytes := intSize(typ) - - maxSmall := 256 - maxBytes - if signed { - maxSmall = 256 - 2*maxBytes - } - if maxBytes == 1 { - maxSmall = 256 - } - - n, _ := r.declReader.ReadByte() - if uint(n) < maxSmall { - v := int64(n) - if signed { - v >>= 1 - if n&1 != 0 { - v = ^v - } - } - x.SetInt64(v) - return - } - - v := -n - if signed { - v = -(n &^ 1) >> 1 - } - if v < 1 || uint(v) > maxBytes { - errorf("weird decoding: %v, %v => %v", n, signed, v) - } - b := make([]byte, v) - io.ReadFull(&r.declReader, b) - x.SetBytes(b) - if signed && n&1 != 0 { - x.Neg(x) - } -} - -func (r *importReader) mpfloat(typ *types.Basic) constant.Value { - var mant big.Int - r.mpint(&mant, typ) - var f big.Float - f.SetInt(&mant) - if f.Sign() != 0 { - f.SetMantExp(&f, int(r.int64())) - } - return constant.Make(&f) -} - -func (r *importReader) ident() string { - return r.string() -} - -func (r *importReader) qualifiedIdent() (*types.Package, string) { - name := r.string() - pkg := r.pkg() - return pkg, name -} - -func (r *importReader) pos() token.Pos { - if r.p.insert != nil { // shallow mode - return r.posv2() - } - if r.p.version >= iexportVersionPosCol { - r.posv1() - } else { - r.posv0() - } - - if r.prevFile == "" && r.prevLine == 0 && r.prevColumn == 0 { - return token.NoPos - } - return r.p.fake.pos(r.prevFile, int(r.prevLine), int(r.prevColumn)) -} - -func (r *importReader) posv0() { - delta := r.int64() - if delta != deltaNewFile { - r.prevLine += delta - } else if l := r.int64(); l == -1 { - r.prevLine += deltaNewFile - } else { - r.prevFile = r.string() - r.prevLine = l - } -} - -func (r *importReader) posv1() { - delta := r.int64() - r.prevColumn += delta >> 1 - if delta&1 != 0 { - delta = r.int64() - r.prevLine += delta >> 1 - if delta&1 != 0 { - r.prevFile = r.string() - } - } -} - -func (r *importReader) posv2() token.Pos { - file := r.uint64() - if file == 0 { - return token.NoPos - } - tf := r.p.fileAt(file - 1) - return tf.Pos(int(r.uint64())) -} - -func (r *importReader) typ() types.Type { - return r.p.typAt(r.uint64(), nil) -} - -func isInterface(t types.Type) bool { - _, ok := t.(*types.Interface) - return ok -} - -func (r *importReader) pkg() *types.Package { return r.p.pkgAt(r.uint64()) } -func (r *importReader) string() string { return r.p.stringAt(r.uint64()) } - -func (r *importReader) doType(base *types.Named) (res types.Type) { - k := r.kind() - if debug { - r.p.trace("importing type %d (base: %s)", k, base) - r.p.indent++ - defer func() { - r.p.indent-- - r.p.trace("=> %s", res) - }() - } - switch k { - default: - errorf("unexpected kind tag in %q: %v", r.p.ipath, k) - return nil - - case definedType: - pkg, name := r.qualifiedIdent() - r.p.doDecl(pkg, name) - return pkg.Scope().Lookup(name).(*types.TypeName).Type() - case pointerType: - return types.NewPointer(r.typ()) - case sliceType: - return types.NewSlice(r.typ()) - case arrayType: - n := r.uint64() - return types.NewArray(r.typ(), int64(n)) - case chanType: - dir := chanDir(int(r.uint64())) - return types.NewChan(dir, r.typ()) - case mapType: - return types.NewMap(r.typ(), r.typ()) - case signatureType: - r.currPkg = r.pkg() - return r.signature(nil, nil, nil) - - case structType: - r.currPkg = r.pkg() - - fields := make([]*types.Var, r.uint64()) - tags := make([]string, len(fields)) - for i := range fields { - fpos := r.pos() - fname := r.ident() - ftyp := r.typ() - emb := r.bool() - tag := r.string() - - fields[i] = types.NewField(fpos, r.currPkg, fname, ftyp, emb) - tags[i] = tag - } - return types.NewStruct(fields, tags) - - case interfaceType: - r.currPkg = r.pkg() - - embeddeds := make([]types.Type, r.uint64()) - for i := range embeddeds { - _ = r.pos() - embeddeds[i] = r.typ() - } - - methods := make([]*types.Func, r.uint64()) - for i := range methods { - mpos := r.pos() - mname := r.ident() - - // TODO(mdempsky): Matches bimport.go, but I - // don't agree with this. - var recv *types.Var - if base != nil { - recv = types.NewVar(token.NoPos, r.currPkg, "", base) - } - - msig := r.signature(recv, nil, nil) - methods[i] = types.NewFunc(mpos, r.currPkg, mname, msig) - } - - typ := newInterface(methods, embeddeds) - r.p.interfaceList = append(r.p.interfaceList, typ) - return typ - - case typeParamType: - if r.p.version < iexportVersionGenerics { - errorf("unexpected type param type") - } - pkg, name := r.qualifiedIdent() - id := ident{pkg, name} - if t, ok := r.p.tparamIndex[id]; ok { - // We're already in the process of importing this typeparam. - return t - } - // Otherwise, import the definition of the typeparam now. - r.p.doDecl(pkg, name) - return r.p.tparamIndex[id] - - case instanceType: - if r.p.version < iexportVersionGenerics { - errorf("unexpected instantiation type") - } - // pos does not matter for instances: they are positioned on the original - // type. - _ = r.pos() - len := r.uint64() - targs := make([]types.Type, len) - for i := range targs { - targs[i] = r.typ() - } - baseType := r.typ() - // The imported instantiated type doesn't include any methods, so - // we must always use the methods of the base (orig) type. - // TODO provide a non-nil *Environment - t, _ := typeparams.Instantiate(nil, baseType, targs, false) - return t - - case unionType: - if r.p.version < iexportVersionGenerics { - errorf("unexpected instantiation type") - } - terms := make([]*typeparams.Term, r.uint64()) - for i := range terms { - terms[i] = typeparams.NewTerm(r.bool(), r.typ()) - } - return typeparams.NewUnion(terms) - } -} - -func (r *importReader) kind() itag { - return itag(r.uint64()) -} - -func (r *importReader) signature(recv *types.Var, rparams []*typeparams.TypeParam, tparams []*typeparams.TypeParam) *types.Signature { - params := r.paramList() - results := r.paramList() - variadic := params.Len() > 0 && r.bool() - return typeparams.NewSignatureType(recv, rparams, tparams, params, results, variadic) -} - -func (r *importReader) tparamList() []*typeparams.TypeParam { - n := r.uint64() - if n == 0 { - return nil - } - xs := make([]*typeparams.TypeParam, n) - for i := range xs { - // Note: the standard library importer is tolerant of nil types here, - // though would panic in SetTypeParams. - xs[i] = r.typ().(*typeparams.TypeParam) - } - return xs -} - -func (r *importReader) paramList() *types.Tuple { - xs := make([]*types.Var, r.uint64()) - for i := range xs { - xs[i] = r.param() - } - return types.NewTuple(xs...) -} - -func (r *importReader) param() *types.Var { - pos := r.pos() - name := r.ident() - typ := r.typ() - return types.NewParam(pos, r.currPkg, name, typ) -} - -func (r *importReader) bool() bool { - return r.uint64() != 0 -} - -func (r *importReader) int64() int64 { - n, err := binary.ReadVarint(&r.declReader) - if err != nil { - errorf("readVarint: %v", err) - } - return n -} - -func (r *importReader) uint64() uint64 { - n, err := binary.ReadUvarint(&r.declReader) - if err != nil { - errorf("readUvarint: %v", err) - } - return n -} - -func (r *importReader) byte() byte { - x, err := r.declReader.ReadByte() - if err != nil { - errorf("declReader.ReadByte: %v", err) - } - return x -} - -func baseType(typ types.Type) *types.Named { - // pointer receivers are never types.Named types - if p, _ := typ.(*types.Pointer); p != nil { - typ = p.Elem() - } - // receiver base types are always (possibly generic) types.Named types - n, _ := typ.(*types.Named) - return n -} diff --git a/vendor/golang.org/x/tools/internal/gcimporter/newInterface10.go b/vendor/golang.org/x/tools/internal/gcimporter/newInterface10.go deleted file mode 100644 index 8b163e3d058..00000000000 --- a/vendor/golang.org/x/tools/internal/gcimporter/newInterface10.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !go1.11 -// +build !go1.11 - -package gcimporter - -import "go/types" - -func newInterface(methods []*types.Func, embeddeds []types.Type) *types.Interface { - named := make([]*types.Named, len(embeddeds)) - for i, e := range embeddeds { - var ok bool - named[i], ok = e.(*types.Named) - if !ok { - panic("embedding of non-defined interfaces in interfaces is not supported before Go 1.11") - } - } - return types.NewInterface(methods, named) -} diff --git a/vendor/golang.org/x/tools/internal/gcimporter/newInterface11.go b/vendor/golang.org/x/tools/internal/gcimporter/newInterface11.go deleted file mode 100644 index 49984f40fd8..00000000000 --- a/vendor/golang.org/x/tools/internal/gcimporter/newInterface11.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build go1.11 -// +build go1.11 - -package gcimporter - -import "go/types" - -func newInterface(methods []*types.Func, embeddeds []types.Type) *types.Interface { - return types.NewInterfaceType(methods, embeddeds) -} diff --git a/vendor/golang.org/x/tools/internal/gcimporter/support_go117.go b/vendor/golang.org/x/tools/internal/gcimporter/support_go117.go deleted file mode 100644 index d892273efb6..00000000000 --- a/vendor/golang.org/x/tools/internal/gcimporter/support_go117.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !go1.18 -// +build !go1.18 - -package gcimporter - -import "go/types" - -const iexportVersion = iexportVersionGo1_11 - -func additionalPredeclared() []types.Type { - return nil -} diff --git a/vendor/golang.org/x/tools/internal/gcimporter/support_go118.go b/vendor/golang.org/x/tools/internal/gcimporter/support_go118.go deleted file mode 100644 index edbe6ea7041..00000000000 --- a/vendor/golang.org/x/tools/internal/gcimporter/support_go118.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build go1.18 -// +build go1.18 - -package gcimporter - -import "go/types" - -const iexportVersion = iexportVersionGenerics - -// additionalPredeclared returns additional predeclared types in go.1.18. -func additionalPredeclared() []types.Type { - return []types.Type{ - // comparable - types.Universe.Lookup("comparable").Type(), - - // any - types.Universe.Lookup("any").Type(), - } -} - -// See cmd/compile/internal/types.SplitVargenSuffix. -func splitVargenSuffix(name string) (base, suffix string) { - i := len(name) - for i > 0 && name[i-1] >= '0' && name[i-1] <= '9' { - i-- - } - const dot = "·" - if i >= len(dot) && name[i-len(dot):i] == dot { - i -= len(dot) - return name[:i], name[i:] - } - return name, "" -} diff --git a/vendor/golang.org/x/tools/internal/gcimporter/unified_no.go b/vendor/golang.org/x/tools/internal/gcimporter/unified_no.go deleted file mode 100644 index 286bf445483..00000000000 --- a/vendor/golang.org/x/tools/internal/gcimporter/unified_no.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !(go1.18 && goexperiment.unified) -// +build !go1.18 !goexperiment.unified - -package gcimporter - -const unifiedIR = false diff --git a/vendor/golang.org/x/tools/internal/gcimporter/unified_yes.go b/vendor/golang.org/x/tools/internal/gcimporter/unified_yes.go deleted file mode 100644 index b5d69ffbe68..00000000000 --- a/vendor/golang.org/x/tools/internal/gcimporter/unified_yes.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build go1.18 && goexperiment.unified -// +build go1.18,goexperiment.unified - -package gcimporter - -const unifiedIR = true diff --git a/vendor/golang.org/x/tools/internal/gcimporter/ureader_no.go b/vendor/golang.org/x/tools/internal/gcimporter/ureader_no.go deleted file mode 100644 index 8eb20729c2a..00000000000 --- a/vendor/golang.org/x/tools/internal/gcimporter/ureader_no.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !go1.18 -// +build !go1.18 - -package gcimporter - -import ( - "fmt" - "go/token" - "go/types" -) - -func UImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, pkg *types.Package, err error) { - err = fmt.Errorf("go/tools compiled with a Go version earlier than 1.18 cannot read unified IR export data") - return -} diff --git a/vendor/golang.org/x/tools/internal/gcimporter/ureader_yes.go b/vendor/golang.org/x/tools/internal/gcimporter/ureader_yes.go deleted file mode 100644 index b285a11ce25..00000000000 --- a/vendor/golang.org/x/tools/internal/gcimporter/ureader_yes.go +++ /dev/null @@ -1,738 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Derived from go/internal/gcimporter/ureader.go - -//go:build go1.18 -// +build go1.18 - -package gcimporter - -import ( - "go/token" - "go/types" - "strings" - - "golang.org/x/tools/internal/pkgbits" -) - -// A pkgReader holds the shared state for reading a unified IR package -// description. -type pkgReader struct { - pkgbits.PkgDecoder - - fake fakeFileSet - - ctxt *types.Context - imports map[string]*types.Package // previously imported packages, indexed by path - - // lazily initialized arrays corresponding to the unified IR - // PosBase, Pkg, and Type sections, respectively. - posBases []string // position bases (i.e., file names) - pkgs []*types.Package - typs []types.Type - - // laterFns holds functions that need to be invoked at the end of - // import reading. - laterFns []func() - // laterFors is used in case of 'type A B' to ensure that B is processed before A. - laterFors map[types.Type]int - - // ifaces holds a list of constructed Interfaces, which need to have - // Complete called after importing is done. - ifaces []*types.Interface -} - -// later adds a function to be invoked at the end of import reading. -func (pr *pkgReader) later(fn func()) { - pr.laterFns = append(pr.laterFns, fn) -} - -// See cmd/compile/internal/noder.derivedInfo. -type derivedInfo struct { - idx pkgbits.Index - needed bool -} - -// See cmd/compile/internal/noder.typeInfo. -type typeInfo struct { - idx pkgbits.Index - derived bool -} - -func UImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, pkg *types.Package, err error) { - s := string(data) - s = s[:strings.LastIndex(s, "\n$$\n")] - input := pkgbits.NewPkgDecoder(path, s) - pkg = readUnifiedPackage(fset, nil, imports, input) - return -} - -// laterFor adds a function to be invoked at the end of import reading, and records the type that function is finishing. -func (pr *pkgReader) laterFor(t types.Type, fn func()) { - if pr.laterFors == nil { - pr.laterFors = make(map[types.Type]int) - } - pr.laterFors[t] = len(pr.laterFns) - pr.laterFns = append(pr.laterFns, fn) -} - -// readUnifiedPackage reads a package description from the given -// unified IR export data decoder. -func readUnifiedPackage(fset *token.FileSet, ctxt *types.Context, imports map[string]*types.Package, input pkgbits.PkgDecoder) *types.Package { - pr := pkgReader{ - PkgDecoder: input, - - fake: fakeFileSet{ - fset: fset, - files: make(map[string]*fileInfo), - }, - - ctxt: ctxt, - imports: imports, - - posBases: make([]string, input.NumElems(pkgbits.RelocPosBase)), - pkgs: make([]*types.Package, input.NumElems(pkgbits.RelocPkg)), - typs: make([]types.Type, input.NumElems(pkgbits.RelocType)), - } - defer pr.fake.setLines() - - r := pr.newReader(pkgbits.RelocMeta, pkgbits.PublicRootIdx, pkgbits.SyncPublic) - pkg := r.pkg() - r.Bool() // has init - - for i, n := 0, r.Len(); i < n; i++ { - // As if r.obj(), but avoiding the Scope.Lookup call, - // to avoid eager loading of imports. - r.Sync(pkgbits.SyncObject) - assert(!r.Bool()) - r.p.objIdx(r.Reloc(pkgbits.RelocObj)) - assert(r.Len() == 0) - } - - r.Sync(pkgbits.SyncEOF) - - for _, fn := range pr.laterFns { - fn() - } - - for _, iface := range pr.ifaces { - iface.Complete() - } - - pkg.MarkComplete() - return pkg -} - -// A reader holds the state for reading a single unified IR element -// within a package. -type reader struct { - pkgbits.Decoder - - p *pkgReader - - dict *readerDict -} - -// A readerDict holds the state for type parameters that parameterize -// the current unified IR element. -type readerDict struct { - // bounds is a slice of typeInfos corresponding to the underlying - // bounds of the element's type parameters. - bounds []typeInfo - - // tparams is a slice of the constructed TypeParams for the element. - tparams []*types.TypeParam - - // devived is a slice of types derived from tparams, which may be - // instantiated while reading the current element. - derived []derivedInfo - derivedTypes []types.Type // lazily instantiated from derived -} - -func (pr *pkgReader) newReader(k pkgbits.RelocKind, idx pkgbits.Index, marker pkgbits.SyncMarker) *reader { - return &reader{ - Decoder: pr.NewDecoder(k, idx, marker), - p: pr, - } -} - -func (pr *pkgReader) tempReader(k pkgbits.RelocKind, idx pkgbits.Index, marker pkgbits.SyncMarker) *reader { - return &reader{ - Decoder: pr.TempDecoder(k, idx, marker), - p: pr, - } -} - -func (pr *pkgReader) retireReader(r *reader) { - pr.RetireDecoder(&r.Decoder) -} - -// @@@ Positions - -func (r *reader) pos() token.Pos { - r.Sync(pkgbits.SyncPos) - if !r.Bool() { - return token.NoPos - } - - // TODO(mdempsky): Delta encoding. - posBase := r.posBase() - line := r.Uint() - col := r.Uint() - return r.p.fake.pos(posBase, int(line), int(col)) -} - -func (r *reader) posBase() string { - return r.p.posBaseIdx(r.Reloc(pkgbits.RelocPosBase)) -} - -func (pr *pkgReader) posBaseIdx(idx pkgbits.Index) string { - if b := pr.posBases[idx]; b != "" { - return b - } - - var filename string - { - r := pr.tempReader(pkgbits.RelocPosBase, idx, pkgbits.SyncPosBase) - - // Within types2, position bases have a lot more details (e.g., - // keeping track of where //line directives appeared exactly). - // - // For go/types, we just track the file name. - - filename = r.String() - - if r.Bool() { // file base - // Was: "b = token.NewTrimmedFileBase(filename, true)" - } else { // line base - pos := r.pos() - line := r.Uint() - col := r.Uint() - - // Was: "b = token.NewLineBase(pos, filename, true, line, col)" - _, _, _ = pos, line, col - } - pr.retireReader(r) - } - b := filename - pr.posBases[idx] = b - return b -} - -// @@@ Packages - -func (r *reader) pkg() *types.Package { - r.Sync(pkgbits.SyncPkg) - return r.p.pkgIdx(r.Reloc(pkgbits.RelocPkg)) -} - -func (pr *pkgReader) pkgIdx(idx pkgbits.Index) *types.Package { - // TODO(mdempsky): Consider using some non-nil pointer to indicate - // the universe scope, so we don't need to keep re-reading it. - if pkg := pr.pkgs[idx]; pkg != nil { - return pkg - } - - pkg := pr.newReader(pkgbits.RelocPkg, idx, pkgbits.SyncPkgDef).doPkg() - pr.pkgs[idx] = pkg - return pkg -} - -func (r *reader) doPkg() *types.Package { - path := r.String() - switch path { - case "": - path = r.p.PkgPath() - case "builtin": - return nil // universe - case "unsafe": - return types.Unsafe - } - - if pkg := r.p.imports[path]; pkg != nil { - return pkg - } - - name := r.String() - - pkg := types.NewPackage(path, name) - r.p.imports[path] = pkg - - imports := make([]*types.Package, r.Len()) - for i := range imports { - imports[i] = r.pkg() - } - pkg.SetImports(flattenImports(imports)) - - return pkg -} - -// flattenImports returns the transitive closure of all imported -// packages rooted from pkgs. -func flattenImports(pkgs []*types.Package) []*types.Package { - var res []*types.Package - seen := make(map[*types.Package]struct{}) - for _, pkg := range pkgs { - if _, ok := seen[pkg]; ok { - continue - } - seen[pkg] = struct{}{} - res = append(res, pkg) - - // pkg.Imports() is already flattened. - for _, pkg := range pkg.Imports() { - if _, ok := seen[pkg]; ok { - continue - } - seen[pkg] = struct{}{} - res = append(res, pkg) - } - } - return res -} - -// @@@ Types - -func (r *reader) typ() types.Type { - return r.p.typIdx(r.typInfo(), r.dict) -} - -func (r *reader) typInfo() typeInfo { - r.Sync(pkgbits.SyncType) - if r.Bool() { - return typeInfo{idx: pkgbits.Index(r.Len()), derived: true} - } - return typeInfo{idx: r.Reloc(pkgbits.RelocType), derived: false} -} - -func (pr *pkgReader) typIdx(info typeInfo, dict *readerDict) types.Type { - idx := info.idx - var where *types.Type - if info.derived { - where = &dict.derivedTypes[idx] - idx = dict.derived[idx].idx - } else { - where = &pr.typs[idx] - } - - if typ := *where; typ != nil { - return typ - } - - var typ types.Type - { - r := pr.tempReader(pkgbits.RelocType, idx, pkgbits.SyncTypeIdx) - r.dict = dict - - typ = r.doTyp() - assert(typ != nil) - pr.retireReader(r) - } - // See comment in pkgReader.typIdx explaining how this happens. - if prev := *where; prev != nil { - return prev - } - - *where = typ - return typ -} - -func (r *reader) doTyp() (res types.Type) { - switch tag := pkgbits.CodeType(r.Code(pkgbits.SyncType)); tag { - default: - errorf("unhandled type tag: %v", tag) - panic("unreachable") - - case pkgbits.TypeBasic: - return types.Typ[r.Len()] - - case pkgbits.TypeNamed: - obj, targs := r.obj() - name := obj.(*types.TypeName) - if len(targs) != 0 { - t, _ := types.Instantiate(r.p.ctxt, name.Type(), targs, false) - return t - } - return name.Type() - - case pkgbits.TypeTypeParam: - return r.dict.tparams[r.Len()] - - case pkgbits.TypeArray: - len := int64(r.Uint64()) - return types.NewArray(r.typ(), len) - case pkgbits.TypeChan: - dir := types.ChanDir(r.Len()) - return types.NewChan(dir, r.typ()) - case pkgbits.TypeMap: - return types.NewMap(r.typ(), r.typ()) - case pkgbits.TypePointer: - return types.NewPointer(r.typ()) - case pkgbits.TypeSignature: - return r.signature(nil, nil, nil) - case pkgbits.TypeSlice: - return types.NewSlice(r.typ()) - case pkgbits.TypeStruct: - return r.structType() - case pkgbits.TypeInterface: - return r.interfaceType() - case pkgbits.TypeUnion: - return r.unionType() - } -} - -func (r *reader) structType() *types.Struct { - fields := make([]*types.Var, r.Len()) - var tags []string - for i := range fields { - pos := r.pos() - pkg, name := r.selector() - ftyp := r.typ() - tag := r.String() - embedded := r.Bool() - - fields[i] = types.NewField(pos, pkg, name, ftyp, embedded) - if tag != "" { - for len(tags) < i { - tags = append(tags, "") - } - tags = append(tags, tag) - } - } - return types.NewStruct(fields, tags) -} - -func (r *reader) unionType() *types.Union { - terms := make([]*types.Term, r.Len()) - for i := range terms { - terms[i] = types.NewTerm(r.Bool(), r.typ()) - } - return types.NewUnion(terms) -} - -func (r *reader) interfaceType() *types.Interface { - methods := make([]*types.Func, r.Len()) - embeddeds := make([]types.Type, r.Len()) - implicit := len(methods) == 0 && len(embeddeds) == 1 && r.Bool() - - for i := range methods { - pos := r.pos() - pkg, name := r.selector() - mtyp := r.signature(nil, nil, nil) - methods[i] = types.NewFunc(pos, pkg, name, mtyp) - } - - for i := range embeddeds { - embeddeds[i] = r.typ() - } - - iface := types.NewInterfaceType(methods, embeddeds) - if implicit { - iface.MarkImplicit() - } - - // We need to call iface.Complete(), but if there are any embedded - // defined types, then we may not have set their underlying - // interface type yet. So we need to defer calling Complete until - // after we've called SetUnderlying everywhere. - // - // TODO(mdempsky): After CL 424876 lands, it should be safe to call - // iface.Complete() immediately. - r.p.ifaces = append(r.p.ifaces, iface) - - return iface -} - -func (r *reader) signature(recv *types.Var, rtparams, tparams []*types.TypeParam) *types.Signature { - r.Sync(pkgbits.SyncSignature) - - params := r.params() - results := r.params() - variadic := r.Bool() - - return types.NewSignatureType(recv, rtparams, tparams, params, results, variadic) -} - -func (r *reader) params() *types.Tuple { - r.Sync(pkgbits.SyncParams) - - params := make([]*types.Var, r.Len()) - for i := range params { - params[i] = r.param() - } - - return types.NewTuple(params...) -} - -func (r *reader) param() *types.Var { - r.Sync(pkgbits.SyncParam) - - pos := r.pos() - pkg, name := r.localIdent() - typ := r.typ() - - return types.NewParam(pos, pkg, name, typ) -} - -// @@@ Objects - -func (r *reader) obj() (types.Object, []types.Type) { - r.Sync(pkgbits.SyncObject) - - assert(!r.Bool()) - - pkg, name := r.p.objIdx(r.Reloc(pkgbits.RelocObj)) - obj := pkgScope(pkg).Lookup(name) - - targs := make([]types.Type, r.Len()) - for i := range targs { - targs[i] = r.typ() - } - - return obj, targs -} - -func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) { - - var objPkg *types.Package - var objName string - var tag pkgbits.CodeObj - { - rname := pr.tempReader(pkgbits.RelocName, idx, pkgbits.SyncObject1) - - objPkg, objName = rname.qualifiedIdent() - assert(objName != "") - - tag = pkgbits.CodeObj(rname.Code(pkgbits.SyncCodeObj)) - pr.retireReader(rname) - } - - if tag == pkgbits.ObjStub { - assert(objPkg == nil || objPkg == types.Unsafe) - return objPkg, objName - } - - // Ignore local types promoted to global scope (#55110). - if _, suffix := splitVargenSuffix(objName); suffix != "" { - return objPkg, objName - } - - if objPkg.Scope().Lookup(objName) == nil { - dict := pr.objDictIdx(idx) - - r := pr.newReader(pkgbits.RelocObj, idx, pkgbits.SyncObject1) - r.dict = dict - - declare := func(obj types.Object) { - objPkg.Scope().Insert(obj) - } - - switch tag { - default: - panic("weird") - - case pkgbits.ObjAlias: - pos := r.pos() - typ := r.typ() - declare(types.NewTypeName(pos, objPkg, objName, typ)) - - case pkgbits.ObjConst: - pos := r.pos() - typ := r.typ() - val := r.Value() - declare(types.NewConst(pos, objPkg, objName, typ, val)) - - case pkgbits.ObjFunc: - pos := r.pos() - tparams := r.typeParamNames() - sig := r.signature(nil, nil, tparams) - declare(types.NewFunc(pos, objPkg, objName, sig)) - - case pkgbits.ObjType: - pos := r.pos() - - obj := types.NewTypeName(pos, objPkg, objName, nil) - named := types.NewNamed(obj, nil, nil) - declare(obj) - - named.SetTypeParams(r.typeParamNames()) - - setUnderlying := func(underlying types.Type) { - // If the underlying type is an interface, we need to - // duplicate its methods so we can replace the receiver - // parameter's type (#49906). - if iface, ok := underlying.(*types.Interface); ok && iface.NumExplicitMethods() != 0 { - methods := make([]*types.Func, iface.NumExplicitMethods()) - for i := range methods { - fn := iface.ExplicitMethod(i) - sig := fn.Type().(*types.Signature) - - recv := types.NewVar(fn.Pos(), fn.Pkg(), "", named) - methods[i] = types.NewFunc(fn.Pos(), fn.Pkg(), fn.Name(), types.NewSignature(recv, sig.Params(), sig.Results(), sig.Variadic())) - } - - embeds := make([]types.Type, iface.NumEmbeddeds()) - for i := range embeds { - embeds[i] = iface.EmbeddedType(i) - } - - newIface := types.NewInterfaceType(methods, embeds) - r.p.ifaces = append(r.p.ifaces, newIface) - underlying = newIface - } - - named.SetUnderlying(underlying) - } - - // Since go.dev/cl/455279, we can assume rhs.Underlying() will - // always be non-nil. However, to temporarily support users of - // older snapshot releases, we continue to fallback to the old - // behavior for now. - // - // TODO(mdempsky): Remove fallback code and simplify after - // allowing time for snapshot users to upgrade. - rhs := r.typ() - if underlying := rhs.Underlying(); underlying != nil { - setUnderlying(underlying) - } else { - pk := r.p - pk.laterFor(named, func() { - // First be sure that the rhs is initialized, if it needs to be initialized. - delete(pk.laterFors, named) // prevent cycles - if i, ok := pk.laterFors[rhs]; ok { - f := pk.laterFns[i] - pk.laterFns[i] = func() {} // function is running now, so replace it with a no-op - f() // initialize RHS - } - setUnderlying(rhs.Underlying()) - }) - } - - for i, n := 0, r.Len(); i < n; i++ { - named.AddMethod(r.method()) - } - - case pkgbits.ObjVar: - pos := r.pos() - typ := r.typ() - declare(types.NewVar(pos, objPkg, objName, typ)) - } - } - - return objPkg, objName -} - -func (pr *pkgReader) objDictIdx(idx pkgbits.Index) *readerDict { - - var dict readerDict - - { - r := pr.tempReader(pkgbits.RelocObjDict, idx, pkgbits.SyncObject1) - if implicits := r.Len(); implicits != 0 { - errorf("unexpected object with %v implicit type parameter(s)", implicits) - } - - dict.bounds = make([]typeInfo, r.Len()) - for i := range dict.bounds { - dict.bounds[i] = r.typInfo() - } - - dict.derived = make([]derivedInfo, r.Len()) - dict.derivedTypes = make([]types.Type, len(dict.derived)) - for i := range dict.derived { - dict.derived[i] = derivedInfo{r.Reloc(pkgbits.RelocType), r.Bool()} - } - - pr.retireReader(r) - } - // function references follow, but reader doesn't need those - - return &dict -} - -func (r *reader) typeParamNames() []*types.TypeParam { - r.Sync(pkgbits.SyncTypeParamNames) - - // Note: This code assumes it only processes objects without - // implement type parameters. This is currently fine, because - // reader is only used to read in exported declarations, which are - // always package scoped. - - if len(r.dict.bounds) == 0 { - return nil - } - - // Careful: Type parameter lists may have cycles. To allow for this, - // we construct the type parameter list in two passes: first we - // create all the TypeNames and TypeParams, then we construct and - // set the bound type. - - r.dict.tparams = make([]*types.TypeParam, len(r.dict.bounds)) - for i := range r.dict.bounds { - pos := r.pos() - pkg, name := r.localIdent() - - tname := types.NewTypeName(pos, pkg, name, nil) - r.dict.tparams[i] = types.NewTypeParam(tname, nil) - } - - typs := make([]types.Type, len(r.dict.bounds)) - for i, bound := range r.dict.bounds { - typs[i] = r.p.typIdx(bound, r.dict) - } - - // TODO(mdempsky): This is subtle, elaborate further. - // - // We have to save tparams outside of the closure, because - // typeParamNames() can be called multiple times with the same - // dictionary instance. - // - // Also, this needs to happen later to make sure SetUnderlying has - // been called. - // - // TODO(mdempsky): Is it safe to have a single "later" slice or do - // we need to have multiple passes? See comments on CL 386002 and - // go.dev/issue/52104. - tparams := r.dict.tparams - r.p.later(func() { - for i, typ := range typs { - tparams[i].SetConstraint(typ) - } - }) - - return r.dict.tparams -} - -func (r *reader) method() *types.Func { - r.Sync(pkgbits.SyncMethod) - pos := r.pos() - pkg, name := r.selector() - - rparams := r.typeParamNames() - sig := r.signature(r.param(), rparams, nil) - - _ = r.pos() // TODO(mdempsky): Remove; this is a hacker for linker.go. - return types.NewFunc(pos, pkg, name, sig) -} - -func (r *reader) qualifiedIdent() (*types.Package, string) { return r.ident(pkgbits.SyncSym) } -func (r *reader) localIdent() (*types.Package, string) { return r.ident(pkgbits.SyncLocalIdent) } -func (r *reader) selector() (*types.Package, string) { return r.ident(pkgbits.SyncSelector) } - -func (r *reader) ident(marker pkgbits.SyncMarker) (*types.Package, string) { - r.Sync(marker) - return r.pkg(), r.String() -} - -// pkgScope returns pkg.Scope(). -// If pkg is nil, it returns types.Universe instead. -// -// TODO(mdempsky): Remove after x/tools can depend on Go 1.19. -func pkgScope(pkg *types.Package) *types.Scope { - if pkg != nil { - return pkg.Scope() - } - return types.Universe -} diff --git a/vendor/golang.org/x/tools/internal/gocommand/invoke.go b/vendor/golang.org/x/tools/internal/gocommand/invoke.go deleted file mode 100644 index d50551693f3..00000000000 --- a/vendor/golang.org/x/tools/internal/gocommand/invoke.go +++ /dev/null @@ -1,356 +0,0 @@ -// Copyright 2020 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package gocommand is a helper for calling the go command. -package gocommand - -import ( - "bytes" - "context" - "fmt" - "io" - "log" - "os" - "regexp" - "runtime" - "strconv" - "strings" - "sync" - "time" - - exec "golang.org/x/sys/execabs" - - "golang.org/x/tools/internal/event" -) - -// An Runner will run go command invocations and serialize -// them if it sees a concurrency error. -type Runner struct { - // once guards the runner initialization. - once sync.Once - - // inFlight tracks available workers. - inFlight chan struct{} - - // serialized guards the ability to run a go command serially, - // to avoid deadlocks when claiming workers. - serialized chan struct{} -} - -const maxInFlight = 10 - -func (runner *Runner) initialize() { - runner.once.Do(func() { - runner.inFlight = make(chan struct{}, maxInFlight) - runner.serialized = make(chan struct{}, 1) - }) -} - -// 1.13: go: updates to go.mod needed, but contents have changed -// 1.14: go: updating go.mod: existing contents have changed since last read -var modConcurrencyError = regexp.MustCompile(`go:.*go.mod.*contents have changed`) - -// Run is a convenience wrapper around RunRaw. -// It returns only stdout and a "friendly" error. -func (runner *Runner) Run(ctx context.Context, inv Invocation) (*bytes.Buffer, error) { - stdout, _, friendly, _ := runner.RunRaw(ctx, inv) - return stdout, friendly -} - -// RunPiped runs the invocation serially, always waiting for any concurrent -// invocations to complete first. -func (runner *Runner) RunPiped(ctx context.Context, inv Invocation, stdout, stderr io.Writer) error { - _, err := runner.runPiped(ctx, inv, stdout, stderr) - return err -} - -// RunRaw runs the invocation, serializing requests only if they fight over -// go.mod changes. -func (runner *Runner) RunRaw(ctx context.Context, inv Invocation) (*bytes.Buffer, *bytes.Buffer, error, error) { - // Make sure the runner is always initialized. - runner.initialize() - - // First, try to run the go command concurrently. - stdout, stderr, friendlyErr, err := runner.runConcurrent(ctx, inv) - - // If we encounter a load concurrency error, we need to retry serially. - if friendlyErr == nil || !modConcurrencyError.MatchString(friendlyErr.Error()) { - return stdout, stderr, friendlyErr, err - } - event.Error(ctx, "Load concurrency error, will retry serially", err) - - // Run serially by calling runPiped. - stdout.Reset() - stderr.Reset() - friendlyErr, err = runner.runPiped(ctx, inv, stdout, stderr) - return stdout, stderr, friendlyErr, err -} - -func (runner *Runner) runConcurrent(ctx context.Context, inv Invocation) (*bytes.Buffer, *bytes.Buffer, error, error) { - // Wait for 1 worker to become available. - select { - case <-ctx.Done(): - return nil, nil, nil, ctx.Err() - case runner.inFlight <- struct{}{}: - defer func() { <-runner.inFlight }() - } - - stdout, stderr := &bytes.Buffer{}, &bytes.Buffer{} - friendlyErr, err := inv.runWithFriendlyError(ctx, stdout, stderr) - return stdout, stderr, friendlyErr, err -} - -func (runner *Runner) runPiped(ctx context.Context, inv Invocation, stdout, stderr io.Writer) (error, error) { - // Make sure the runner is always initialized. - runner.initialize() - - // Acquire the serialization lock. This avoids deadlocks between two - // runPiped commands. - select { - case <-ctx.Done(): - return nil, ctx.Err() - case runner.serialized <- struct{}{}: - defer func() { <-runner.serialized }() - } - - // Wait for all in-progress go commands to return before proceeding, - // to avoid load concurrency errors. - for i := 0; i < maxInFlight; i++ { - select { - case <-ctx.Done(): - return nil, ctx.Err() - case runner.inFlight <- struct{}{}: - // Make sure we always "return" any workers we took. - defer func() { <-runner.inFlight }() - } - } - - return inv.runWithFriendlyError(ctx, stdout, stderr) -} - -// An Invocation represents a call to the go command. -type Invocation struct { - Verb string - Args []string - BuildFlags []string - - // If ModFlag is set, the go command is invoked with -mod=ModFlag. - ModFlag string - - // If ModFile is set, the go command is invoked with -modfile=ModFile. - ModFile string - - // If Overlay is set, the go command is invoked with -overlay=Overlay. - Overlay string - - // If CleanEnv is set, the invocation will run only with the environment - // in Env, not starting with os.Environ. - CleanEnv bool - Env []string - WorkingDir string - Logf func(format string, args ...interface{}) -} - -func (i *Invocation) runWithFriendlyError(ctx context.Context, stdout, stderr io.Writer) (friendlyError error, rawError error) { - rawError = i.run(ctx, stdout, stderr) - if rawError != nil { - friendlyError = rawError - // Check for 'go' executable not being found. - if ee, ok := rawError.(*exec.Error); ok && ee.Err == exec.ErrNotFound { - friendlyError = fmt.Errorf("go command required, not found: %v", ee) - } - if ctx.Err() != nil { - friendlyError = ctx.Err() - } - friendlyError = fmt.Errorf("err: %v: stderr: %s", friendlyError, stderr) - } - return -} - -func (i *Invocation) run(ctx context.Context, stdout, stderr io.Writer) error { - log := i.Logf - if log == nil { - log = func(string, ...interface{}) {} - } - - goArgs := []string{i.Verb} - - appendModFile := func() { - if i.ModFile != "" { - goArgs = append(goArgs, "-modfile="+i.ModFile) - } - } - appendModFlag := func() { - if i.ModFlag != "" { - goArgs = append(goArgs, "-mod="+i.ModFlag) - } - } - appendOverlayFlag := func() { - if i.Overlay != "" { - goArgs = append(goArgs, "-overlay="+i.Overlay) - } - } - - switch i.Verb { - case "env", "version": - goArgs = append(goArgs, i.Args...) - case "mod": - // mod needs the sub-verb before flags. - goArgs = append(goArgs, i.Args[0]) - appendModFile() - goArgs = append(goArgs, i.Args[1:]...) - case "get": - goArgs = append(goArgs, i.BuildFlags...) - appendModFile() - goArgs = append(goArgs, i.Args...) - - default: // notably list and build. - goArgs = append(goArgs, i.BuildFlags...) - appendModFile() - appendModFlag() - appendOverlayFlag() - goArgs = append(goArgs, i.Args...) - } - cmd := exec.Command("go", goArgs...) - cmd.Stdout = stdout - cmd.Stderr = stderr - // On darwin the cwd gets resolved to the real path, which breaks anything that - // expects the working directory to keep the original path, including the - // go command when dealing with modules. - // The Go stdlib has a special feature where if the cwd and the PWD are the - // same node then it trusts the PWD, so by setting it in the env for the child - // process we fix up all the paths returned by the go command. - if !i.CleanEnv { - cmd.Env = os.Environ() - } - cmd.Env = append(cmd.Env, i.Env...) - if i.WorkingDir != "" { - cmd.Env = append(cmd.Env, "PWD="+i.WorkingDir) - cmd.Dir = i.WorkingDir - } - defer func(start time.Time) { log("%s for %v", time.Since(start), cmdDebugStr(cmd)) }(time.Now()) - - return runCmdContext(ctx, cmd) -} - -// DebugHangingGoCommands may be set by tests to enable additional -// instrumentation (including panics) for debugging hanging Go commands. -// -// See golang/go#54461 for details. -var DebugHangingGoCommands = false - -// runCmdContext is like exec.CommandContext except it sends os.Interrupt -// before os.Kill. -func runCmdContext(ctx context.Context, cmd *exec.Cmd) error { - if err := cmd.Start(); err != nil { - return err - } - resChan := make(chan error, 1) - go func() { - resChan <- cmd.Wait() - }() - - // If we're interested in debugging hanging Go commands, stop waiting after a - // minute and panic with interesting information. - if DebugHangingGoCommands { - select { - case err := <-resChan: - return err - case <-time.After(1 * time.Minute): - HandleHangingGoCommand(cmd.Process) - case <-ctx.Done(): - } - } else { - select { - case err := <-resChan: - return err - case <-ctx.Done(): - } - } - - // Cancelled. Interrupt and see if it ends voluntarily. - cmd.Process.Signal(os.Interrupt) - select { - case err := <-resChan: - return err - case <-time.After(time.Second): - } - - // Didn't shut down in response to interrupt. Kill it hard. - // TODO(rfindley): per advice from bcmills@, it may be better to send SIGQUIT - // on certain platforms, such as unix. - if err := cmd.Process.Kill(); err != nil && DebugHangingGoCommands { - // Don't panic here as this reliably fails on windows with EINVAL. - log.Printf("error killing the Go command: %v", err) - } - - // See above: don't wait indefinitely if we're debugging hanging Go commands. - if DebugHangingGoCommands { - select { - case err := <-resChan: - return err - case <-time.After(10 * time.Second): // a shorter wait as resChan should return quickly following Kill - HandleHangingGoCommand(cmd.Process) - } - } - return <-resChan -} - -func HandleHangingGoCommand(proc *os.Process) { - switch runtime.GOOS { - case "linux", "darwin", "freebsd", "netbsd": - fmt.Fprintln(os.Stderr, `DETECTED A HANGING GO COMMAND - -The gopls test runner has detected a hanging go command. In order to debug -this, the output of ps and lsof/fstat is printed below. - -See golang/go#54461 for more details.`) - - fmt.Fprintln(os.Stderr, "\nps axo ppid,pid,command:") - fmt.Fprintln(os.Stderr, "-------------------------") - psCmd := exec.Command("ps", "axo", "ppid,pid,command") - psCmd.Stdout = os.Stderr - psCmd.Stderr = os.Stderr - if err := psCmd.Run(); err != nil { - panic(fmt.Sprintf("running ps: %v", err)) - } - - listFiles := "lsof" - if runtime.GOOS == "freebsd" || runtime.GOOS == "netbsd" { - listFiles = "fstat" - } - - fmt.Fprintln(os.Stderr, "\n"+listFiles+":") - fmt.Fprintln(os.Stderr, "-----") - listFilesCmd := exec.Command(listFiles) - listFilesCmd.Stdout = os.Stderr - listFilesCmd.Stderr = os.Stderr - if err := listFilesCmd.Run(); err != nil { - panic(fmt.Sprintf("running %s: %v", listFiles, err)) - } - } - panic(fmt.Sprintf("detected hanging go command (pid %d): see golang/go#54461 for more details", proc.Pid)) -} - -func cmdDebugStr(cmd *exec.Cmd) string { - env := make(map[string]string) - for _, kv := range cmd.Env { - split := strings.SplitN(kv, "=", 2) - if len(split) == 2 { - k, v := split[0], split[1] - env[k] = v - } - } - - var args []string - for _, arg := range cmd.Args { - quoted := strconv.Quote(arg) - if quoted[1:len(quoted)-1] != arg || strings.Contains(arg, " ") { - args = append(args, quoted) - } else { - args = append(args, arg) - } - } - return fmt.Sprintf("GOROOT=%v GOPATH=%v GO111MODULE=%v GOPROXY=%v PWD=%v %v", env["GOROOT"], env["GOPATH"], env["GO111MODULE"], env["GOPROXY"], env["PWD"], strings.Join(args, " ")) -} diff --git a/vendor/golang.org/x/tools/internal/gocommand/vendor.go b/vendor/golang.org/x/tools/internal/gocommand/vendor.go deleted file mode 100644 index 2d3d408c0be..00000000000 --- a/vendor/golang.org/x/tools/internal/gocommand/vendor.go +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2020 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package gocommand - -import ( - "bytes" - "context" - "fmt" - "os" - "path/filepath" - "regexp" - "strings" - "time" - - "golang.org/x/mod/semver" -) - -// ModuleJSON holds information about a module. -type ModuleJSON struct { - Path string // module path - Version string // module version - Versions []string // available module versions (with -versions) - Replace *ModuleJSON // replaced by this module - Time *time.Time // time version was created - Update *ModuleJSON // available update, if any (with -u) - Main bool // is this the main module? - Indirect bool // is this module only an indirect dependency of main module? - Dir string // directory holding files for this module, if any - GoMod string // path to go.mod file used when loading this module, if any - GoVersion string // go version used in module -} - -var modFlagRegexp = regexp.MustCompile(`-mod[ =](\w+)`) - -// VendorEnabled reports whether vendoring is enabled. It takes a *Runner to execute Go commands -// with the supplied context.Context and Invocation. The Invocation can contain pre-defined fields, -// of which only Verb and Args are modified to run the appropriate Go command. -// Inspired by setDefaultBuildMod in modload/init.go -func VendorEnabled(ctx context.Context, inv Invocation, r *Runner) (bool, *ModuleJSON, error) { - mainMod, go114, err := getMainModuleAnd114(ctx, inv, r) - if err != nil { - return false, nil, err - } - - // We check the GOFLAGS to see if there is anything overridden or not. - inv.Verb = "env" - inv.Args = []string{"GOFLAGS"} - stdout, err := r.Run(ctx, inv) - if err != nil { - return false, nil, err - } - goflags := string(bytes.TrimSpace(stdout.Bytes())) - matches := modFlagRegexp.FindStringSubmatch(goflags) - var modFlag string - if len(matches) != 0 { - modFlag = matches[1] - } - // Don't override an explicit '-mod=' argument. - if modFlag == "vendor" { - return true, mainMod, nil - } else if modFlag != "" { - return false, nil, nil - } - if mainMod == nil || !go114 { - return false, nil, nil - } - // Check 1.14's automatic vendor mode. - if fi, err := os.Stat(filepath.Join(mainMod.Dir, "vendor")); err == nil && fi.IsDir() { - if mainMod.GoVersion != "" && semver.Compare("v"+mainMod.GoVersion, "v1.14") >= 0 { - // The Go version is at least 1.14, and a vendor directory exists. - // Set -mod=vendor by default. - return true, mainMod, nil - } - } - return false, nil, nil -} - -// getMainModuleAnd114 gets one of the main modules' information and whether the -// go command in use is 1.14+. This is the information needed to figure out -// if vendoring should be enabled. -func getMainModuleAnd114(ctx context.Context, inv Invocation, r *Runner) (*ModuleJSON, bool, error) { - const format = `{{.Path}} -{{.Dir}} -{{.GoMod}} -{{.GoVersion}} -{{range context.ReleaseTags}}{{if eq . "go1.14"}}{{.}}{{end}}{{end}} -` - inv.Verb = "list" - inv.Args = []string{"-m", "-f", format} - stdout, err := r.Run(ctx, inv) - if err != nil { - return nil, false, err - } - - lines := strings.Split(stdout.String(), "\n") - if len(lines) < 5 { - return nil, false, fmt.Errorf("unexpected stdout: %q", stdout.String()) - } - mod := &ModuleJSON{ - Path: lines[0], - Dir: lines[1], - GoMod: lines[2], - GoVersion: lines[3], - Main: true, - } - return mod, lines[4] == "go1.14", nil -} diff --git a/vendor/golang.org/x/tools/internal/gocommand/version.go b/vendor/golang.org/x/tools/internal/gocommand/version.go deleted file mode 100644 index 307a76d474a..00000000000 --- a/vendor/golang.org/x/tools/internal/gocommand/version.go +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2020 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package gocommand - -import ( - "context" - "fmt" - "regexp" - "strings" -) - -// GoVersion reports the minor version number of the highest release -// tag built into the go command on the PATH. -// -// Note that this may be higher than the version of the go tool used -// to build this application, and thus the versions of the standard -// go/{scanner,parser,ast,types} packages that are linked into it. -// In that case, callers should either downgrade to the version of -// go used to build the application, or report an error that the -// application is too old to use the go command on the PATH. -func GoVersion(ctx context.Context, inv Invocation, r *Runner) (int, error) { - inv.Verb = "list" - inv.Args = []string{"-e", "-f", `{{context.ReleaseTags}}`, `--`, `unsafe`} - inv.Env = append(append([]string{}, inv.Env...), "GO111MODULE=off") - // Unset any unneeded flags, and remove them from BuildFlags, if they're - // present. - inv.ModFile = "" - inv.ModFlag = "" - var buildFlags []string - for _, flag := range inv.BuildFlags { - // Flags can be prefixed by one or two dashes. - f := strings.TrimPrefix(strings.TrimPrefix(flag, "-"), "-") - if strings.HasPrefix(f, "mod=") || strings.HasPrefix(f, "modfile=") { - continue - } - buildFlags = append(buildFlags, flag) - } - inv.BuildFlags = buildFlags - stdoutBytes, err := r.Run(ctx, inv) - if err != nil { - return 0, err - } - stdout := stdoutBytes.String() - if len(stdout) < 3 { - return 0, fmt.Errorf("bad ReleaseTags output: %q", stdout) - } - // Split up "[go1.1 go1.15]" and return highest go1.X value. - tags := strings.Fields(stdout[1 : len(stdout)-2]) - for i := len(tags) - 1; i >= 0; i-- { - var version int - if _, err := fmt.Sscanf(tags[i], "go1.%d", &version); err != nil { - continue - } - return version, nil - } - return 0, fmt.Errorf("no parseable ReleaseTags in %v", tags) -} - -// GoVersionOutput returns the complete output of the go version command. -func GoVersionOutput(ctx context.Context, inv Invocation, r *Runner) (string, error) { - inv.Verb = "version" - goVersion, err := r.Run(ctx, inv) - if err != nil { - return "", err - } - return goVersion.String(), nil -} - -// ParseGoVersionOutput extracts the Go version string -// from the output of the "go version" command. -// Given an unrecognized form, it returns an empty string. -func ParseGoVersionOutput(data string) string { - re := regexp.MustCompile(`^go version (go\S+|devel \S+)`) - m := re.FindStringSubmatch(data) - if len(m) != 2 { - return "" // unrecognized version - } - return m[1] -} diff --git a/vendor/golang.org/x/tools/internal/gopathwalk/walk.go b/vendor/golang.org/x/tools/internal/gopathwalk/walk.go deleted file mode 100644 index 16840532268..00000000000 --- a/vendor/golang.org/x/tools/internal/gopathwalk/walk.go +++ /dev/null @@ -1,254 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package gopathwalk is like filepath.Walk but specialized for finding Go -// packages, particularly in $GOPATH and $GOROOT. -package gopathwalk - -import ( - "bufio" - "bytes" - "fmt" - "io/ioutil" - "log" - "os" - "path/filepath" - "strings" - "time" - - "golang.org/x/tools/internal/fastwalk" -) - -// Options controls the behavior of a Walk call. -type Options struct { - // If Logf is non-nil, debug logging is enabled through this function. - Logf func(format string, args ...interface{}) - // Search module caches. Also disables legacy goimports ignore rules. - ModulesEnabled bool -} - -// RootType indicates the type of a Root. -type RootType int - -const ( - RootUnknown RootType = iota - RootGOROOT - RootGOPATH - RootCurrentModule - RootModuleCache - RootOther -) - -// A Root is a starting point for a Walk. -type Root struct { - Path string - Type RootType -} - -// Walk walks Go source directories ($GOROOT, $GOPATH, etc) to find packages. -// For each package found, add will be called (concurrently) with the absolute -// paths of the containing source directory and the package directory. -// add will be called concurrently. -func Walk(roots []Root, add func(root Root, dir string), opts Options) { - WalkSkip(roots, add, func(Root, string) bool { return false }, opts) -} - -// WalkSkip walks Go source directories ($GOROOT, $GOPATH, etc) to find packages. -// For each package found, add will be called (concurrently) with the absolute -// paths of the containing source directory and the package directory. -// For each directory that will be scanned, skip will be called (concurrently) -// with the absolute paths of the containing source directory and the directory. -// If skip returns false on a directory it will be processed. -// add will be called concurrently. -// skip will be called concurrently. -func WalkSkip(roots []Root, add func(root Root, dir string), skip func(root Root, dir string) bool, opts Options) { - for _, root := range roots { - walkDir(root, add, skip, opts) - } -} - -// walkDir creates a walker and starts fastwalk with this walker. -func walkDir(root Root, add func(Root, string), skip func(root Root, dir string) bool, opts Options) { - if _, err := os.Stat(root.Path); os.IsNotExist(err) { - if opts.Logf != nil { - opts.Logf("skipping nonexistent directory: %v", root.Path) - } - return - } - start := time.Now() - if opts.Logf != nil { - opts.Logf("gopathwalk: scanning %s", root.Path) - } - w := &walker{ - root: root, - add: add, - skip: skip, - opts: opts, - } - w.init() - if err := fastwalk.Walk(root.Path, w.walk); err != nil { - log.Printf("gopathwalk: scanning directory %v: %v", root.Path, err) - } - - if opts.Logf != nil { - opts.Logf("gopathwalk: scanned %s in %v", root.Path, time.Since(start)) - } -} - -// walker is the callback for fastwalk.Walk. -type walker struct { - root Root // The source directory to scan. - add func(Root, string) // The callback that will be invoked for every possible Go package dir. - skip func(Root, string) bool // The callback that will be invoked for every dir. dir is skipped if it returns true. - opts Options // Options passed to Walk by the user. - - ignoredDirs []os.FileInfo // The ignored directories, loaded from .goimportsignore files. -} - -// init initializes the walker based on its Options -func (w *walker) init() { - var ignoredPaths []string - if w.root.Type == RootModuleCache { - ignoredPaths = []string{"cache"} - } - if !w.opts.ModulesEnabled && w.root.Type == RootGOPATH { - ignoredPaths = w.getIgnoredDirs(w.root.Path) - ignoredPaths = append(ignoredPaths, "v", "mod") - } - - for _, p := range ignoredPaths { - full := filepath.Join(w.root.Path, p) - if fi, err := os.Stat(full); err == nil { - w.ignoredDirs = append(w.ignoredDirs, fi) - if w.opts.Logf != nil { - w.opts.Logf("Directory added to ignore list: %s", full) - } - } else if w.opts.Logf != nil { - w.opts.Logf("Error statting ignored directory: %v", err) - } - } -} - -// getIgnoredDirs reads an optional config file at /.goimportsignore -// of relative directories to ignore when scanning for go files. -// The provided path is one of the $GOPATH entries with "src" appended. -func (w *walker) getIgnoredDirs(path string) []string { - file := filepath.Join(path, ".goimportsignore") - slurp, err := ioutil.ReadFile(file) - if w.opts.Logf != nil { - if err != nil { - w.opts.Logf("%v", err) - } else { - w.opts.Logf("Read %s", file) - } - } - if err != nil { - return nil - } - - var ignoredDirs []string - bs := bufio.NewScanner(bytes.NewReader(slurp)) - for bs.Scan() { - line := strings.TrimSpace(bs.Text()) - if line == "" || strings.HasPrefix(line, "#") { - continue - } - ignoredDirs = append(ignoredDirs, line) - } - return ignoredDirs -} - -// shouldSkipDir reports whether the file should be skipped or not. -func (w *walker) shouldSkipDir(fi os.FileInfo, dir string) bool { - for _, ignoredDir := range w.ignoredDirs { - if os.SameFile(fi, ignoredDir) { - return true - } - } - if w.skip != nil { - // Check with the user specified callback. - return w.skip(w.root, dir) - } - return false -} - -// walk walks through the given path. -func (w *walker) walk(path string, typ os.FileMode) error { - if typ.IsRegular() { - dir := filepath.Dir(path) - if dir == w.root.Path && (w.root.Type == RootGOROOT || w.root.Type == RootGOPATH) { - // Doesn't make sense to have regular files - // directly in your $GOPATH/src or $GOROOT/src. - return fastwalk.ErrSkipFiles - } - if !strings.HasSuffix(path, ".go") { - return nil - } - - w.add(w.root, dir) - return fastwalk.ErrSkipFiles - } - if typ == os.ModeDir { - base := filepath.Base(path) - if base == "" || base[0] == '.' || base[0] == '_' || - base == "testdata" || - (w.root.Type == RootGOROOT && w.opts.ModulesEnabled && base == "vendor") || - (!w.opts.ModulesEnabled && base == "node_modules") { - return filepath.SkipDir - } - fi, err := os.Lstat(path) - if err == nil && w.shouldSkipDir(fi, path) { - return filepath.SkipDir - } - return nil - } - if typ == os.ModeSymlink { - base := filepath.Base(path) - if strings.HasPrefix(base, ".#") { - // Emacs noise. - return nil - } - if w.shouldTraverse(path) { - return fastwalk.ErrTraverseLink - } - } - return nil -} - -// shouldTraverse reports whether the symlink fi, found in dir, -// should be followed. It makes sure symlinks were never visited -// before to avoid symlink loops. -func (w *walker) shouldTraverse(path string) bool { - ts, err := os.Stat(path) - if err != nil { - fmt.Fprintln(os.Stderr, err) - return false - } - if !ts.IsDir() { - return false - } - if w.shouldSkipDir(ts, filepath.Dir(path)) { - return false - } - // Check for symlink loops by statting each directory component - // and seeing if any are the same file as ts. - for { - parent := filepath.Dir(path) - if parent == path { - // Made it to the root without seeing a cycle. - // Use this symlink. - return true - } - parentInfo, err := os.Stat(parent) - if err != nil { - return false - } - if os.SameFile(ts, parentInfo) { - // Cycle. Don't traverse. - return false - } - path = parent - } - -} diff --git a/vendor/golang.org/x/tools/internal/imports/fix.go b/vendor/golang.org/x/tools/internal/imports/fix.go deleted file mode 100644 index 642a5ac2d75..00000000000 --- a/vendor/golang.org/x/tools/internal/imports/fix.go +++ /dev/null @@ -1,1738 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package imports - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "go/ast" - "go/build" - "go/parser" - "go/token" - "io/ioutil" - "os" - "path" - "path/filepath" - "reflect" - "sort" - "strconv" - "strings" - "sync" - "unicode" - "unicode/utf8" - - "golang.org/x/tools/go/ast/astutil" - "golang.org/x/tools/internal/gocommand" - "golang.org/x/tools/internal/gopathwalk" -) - -// importToGroup is a list of functions which map from an import path to -// a group number. -var importToGroup = []func(localPrefix, importPath string) (num int, ok bool){ - func(localPrefix, importPath string) (num int, ok bool) { - if localPrefix == "" { - return - } - for _, p := range strings.Split(localPrefix, ",") { - if strings.HasPrefix(importPath, p) || strings.TrimSuffix(p, "/") == importPath { - return 3, true - } - } - return - }, - func(_, importPath string) (num int, ok bool) { - if strings.HasPrefix(importPath, "appengine") { - return 2, true - } - return - }, - func(_, importPath string) (num int, ok bool) { - firstComponent := strings.Split(importPath, "/")[0] - if strings.Contains(firstComponent, ".") { - return 1, true - } - return - }, -} - -func importGroup(localPrefix, importPath string) int { - for _, fn := range importToGroup { - if n, ok := fn(localPrefix, importPath); ok { - return n - } - } - return 0 -} - -type ImportFixType int - -const ( - AddImport ImportFixType = iota - DeleteImport - SetImportName -) - -type ImportFix struct { - // StmtInfo represents the import statement this fix will add, remove, or change. - StmtInfo ImportInfo - // IdentName is the identifier that this fix will add or remove. - IdentName string - // FixType is the type of fix this is (AddImport, DeleteImport, SetImportName). - FixType ImportFixType - Relevance float64 // see pkg -} - -// An ImportInfo represents a single import statement. -type ImportInfo struct { - ImportPath string // import path, e.g. "crypto/rand". - Name string // import name, e.g. "crand", or "" if none. -} - -// A packageInfo represents what's known about a package. -type packageInfo struct { - name string // real package name, if known. - exports map[string]bool // known exports. -} - -// parseOtherFiles parses all the Go files in srcDir except filename, including -// test files if filename looks like a test. -func parseOtherFiles(fset *token.FileSet, srcDir, filename string) []*ast.File { - // This could use go/packages but it doesn't buy much, and it fails - // with https://golang.org/issue/26296 in LoadFiles mode in some cases. - considerTests := strings.HasSuffix(filename, "_test.go") - - fileBase := filepath.Base(filename) - packageFileInfos, err := ioutil.ReadDir(srcDir) - if err != nil { - return nil - } - - var files []*ast.File - for _, fi := range packageFileInfos { - if fi.Name() == fileBase || !strings.HasSuffix(fi.Name(), ".go") { - continue - } - if !considerTests && strings.HasSuffix(fi.Name(), "_test.go") { - continue - } - - f, err := parser.ParseFile(fset, filepath.Join(srcDir, fi.Name()), nil, 0) - if err != nil { - continue - } - - files = append(files, f) - } - - return files -} - -// addGlobals puts the names of package vars into the provided map. -func addGlobals(f *ast.File, globals map[string]bool) { - for _, decl := range f.Decls { - genDecl, ok := decl.(*ast.GenDecl) - if !ok { - continue - } - - for _, spec := range genDecl.Specs { - valueSpec, ok := spec.(*ast.ValueSpec) - if !ok { - continue - } - globals[valueSpec.Names[0].Name] = true - } - } -} - -// collectReferences builds a map of selector expressions, from -// left hand side (X) to a set of right hand sides (Sel). -func collectReferences(f *ast.File) references { - refs := references{} - - var visitor visitFn - visitor = func(node ast.Node) ast.Visitor { - if node == nil { - return visitor - } - switch v := node.(type) { - case *ast.SelectorExpr: - xident, ok := v.X.(*ast.Ident) - if !ok { - break - } - if xident.Obj != nil { - // If the parser can resolve it, it's not a package ref. - break - } - if !ast.IsExported(v.Sel.Name) { - // Whatever this is, it's not exported from a package. - break - } - pkgName := xident.Name - r := refs[pkgName] - if r == nil { - r = make(map[string]bool) - refs[pkgName] = r - } - r[v.Sel.Name] = true - } - return visitor - } - ast.Walk(visitor, f) - return refs -} - -// collectImports returns all the imports in f. -// Unnamed imports (., _) and "C" are ignored. -func collectImports(f *ast.File) []*ImportInfo { - var imports []*ImportInfo - for _, imp := range f.Imports { - var name string - if imp.Name != nil { - name = imp.Name.Name - } - if imp.Path.Value == `"C"` || name == "_" || name == "." { - continue - } - path := strings.Trim(imp.Path.Value, `"`) - imports = append(imports, &ImportInfo{ - Name: name, - ImportPath: path, - }) - } - return imports -} - -// findMissingImport searches pass's candidates for an import that provides -// pkg, containing all of syms. -func (p *pass) findMissingImport(pkg string, syms map[string]bool) *ImportInfo { - for _, candidate := range p.candidates { - pkgInfo, ok := p.knownPackages[candidate.ImportPath] - if !ok { - continue - } - if p.importIdentifier(candidate) != pkg { - continue - } - - allFound := true - for right := range syms { - if !pkgInfo.exports[right] { - allFound = false - break - } - } - - if allFound { - return candidate - } - } - return nil -} - -// references is set of references found in a Go file. The first map key is the -// left hand side of a selector expression, the second key is the right hand -// side, and the value should always be true. -type references map[string]map[string]bool - -// A pass contains all the inputs and state necessary to fix a file's imports. -// It can be modified in some ways during use; see comments below. -type pass struct { - // Inputs. These must be set before a call to load, and not modified after. - fset *token.FileSet // fset used to parse f and its siblings. - f *ast.File // the file being fixed. - srcDir string // the directory containing f. - env *ProcessEnv // the environment to use for go commands, etc. - loadRealPackageNames bool // if true, load package names from disk rather than guessing them. - otherFiles []*ast.File // sibling files. - - // Intermediate state, generated by load. - existingImports map[string]*ImportInfo - allRefs references - missingRefs references - - // Inputs to fix. These can be augmented between successive fix calls. - lastTry bool // indicates that this is the last call and fix should clean up as best it can. - candidates []*ImportInfo // candidate imports in priority order. - knownPackages map[string]*packageInfo // information about all known packages. -} - -// loadPackageNames saves the package names for everything referenced by imports. -func (p *pass) loadPackageNames(imports []*ImportInfo) error { - if p.env.Logf != nil { - p.env.Logf("loading package names for %v packages", len(imports)) - defer func() { - p.env.Logf("done loading package names for %v packages", len(imports)) - }() - } - var unknown []string - for _, imp := range imports { - if _, ok := p.knownPackages[imp.ImportPath]; ok { - continue - } - unknown = append(unknown, imp.ImportPath) - } - - resolver, err := p.env.GetResolver() - if err != nil { - return err - } - - names, err := resolver.loadPackageNames(unknown, p.srcDir) - if err != nil { - return err - } - - for path, name := range names { - p.knownPackages[path] = &packageInfo{ - name: name, - exports: map[string]bool{}, - } - } - return nil -} - -// importIdentifier returns the identifier that imp will introduce. It will -// guess if the package name has not been loaded, e.g. because the source -// is not available. -func (p *pass) importIdentifier(imp *ImportInfo) string { - if imp.Name != "" { - return imp.Name - } - known := p.knownPackages[imp.ImportPath] - if known != nil && known.name != "" { - return known.name - } - return ImportPathToAssumedName(imp.ImportPath) -} - -// load reads in everything necessary to run a pass, and reports whether the -// file already has all the imports it needs. It fills in p.missingRefs with the -// file's missing symbols, if any, or removes unused imports if not. -func (p *pass) load() ([]*ImportFix, bool) { - p.knownPackages = map[string]*packageInfo{} - p.missingRefs = references{} - p.existingImports = map[string]*ImportInfo{} - - // Load basic information about the file in question. - p.allRefs = collectReferences(p.f) - - // Load stuff from other files in the same package: - // global variables so we know they don't need resolving, and imports - // that we might want to mimic. - globals := map[string]bool{} - for _, otherFile := range p.otherFiles { - // Don't load globals from files that are in the same directory - // but a different package. Using them to suggest imports is OK. - if p.f.Name.Name == otherFile.Name.Name { - addGlobals(otherFile, globals) - } - p.candidates = append(p.candidates, collectImports(otherFile)...) - } - - // Resolve all the import paths we've seen to package names, and store - // f's imports by the identifier they introduce. - imports := collectImports(p.f) - if p.loadRealPackageNames { - err := p.loadPackageNames(append(imports, p.candidates...)) - if err != nil { - if p.env.Logf != nil { - p.env.Logf("loading package names: %v", err) - } - return nil, false - } - } - for _, imp := range imports { - p.existingImports[p.importIdentifier(imp)] = imp - } - - // Find missing references. - for left, rights := range p.allRefs { - if globals[left] { - continue - } - _, ok := p.existingImports[left] - if !ok { - p.missingRefs[left] = rights - continue - } - } - if len(p.missingRefs) != 0 { - return nil, false - } - - return p.fix() -} - -// fix attempts to satisfy missing imports using p.candidates. If it finds -// everything, or if p.lastTry is true, it updates fixes to add the imports it found, -// delete anything unused, and update import names, and returns true. -func (p *pass) fix() ([]*ImportFix, bool) { - // Find missing imports. - var selected []*ImportInfo - for left, rights := range p.missingRefs { - if imp := p.findMissingImport(left, rights); imp != nil { - selected = append(selected, imp) - } - } - - if !p.lastTry && len(selected) != len(p.missingRefs) { - return nil, false - } - - // Found everything, or giving up. Add the new imports and remove any unused. - var fixes []*ImportFix - for _, imp := range p.existingImports { - // We deliberately ignore globals here, because we can't be sure - // they're in the same package. People do things like put multiple - // main packages in the same directory, and we don't want to - // remove imports if they happen to have the same name as a var in - // a different package. - if _, ok := p.allRefs[p.importIdentifier(imp)]; !ok { - fixes = append(fixes, &ImportFix{ - StmtInfo: *imp, - IdentName: p.importIdentifier(imp), - FixType: DeleteImport, - }) - continue - } - - // An existing import may need to update its import name to be correct. - if name := p.importSpecName(imp); name != imp.Name { - fixes = append(fixes, &ImportFix{ - StmtInfo: ImportInfo{ - Name: name, - ImportPath: imp.ImportPath, - }, - IdentName: p.importIdentifier(imp), - FixType: SetImportName, - }) - } - } - - for _, imp := range selected { - fixes = append(fixes, &ImportFix{ - StmtInfo: ImportInfo{ - Name: p.importSpecName(imp), - ImportPath: imp.ImportPath, - }, - IdentName: p.importIdentifier(imp), - FixType: AddImport, - }) - } - - return fixes, true -} - -// importSpecName gets the import name of imp in the import spec. -// -// When the import identifier matches the assumed import name, the import name does -// not appear in the import spec. -func (p *pass) importSpecName(imp *ImportInfo) string { - // If we did not load the real package names, or the name is already set, - // we just return the existing name. - if !p.loadRealPackageNames || imp.Name != "" { - return imp.Name - } - - ident := p.importIdentifier(imp) - if ident == ImportPathToAssumedName(imp.ImportPath) { - return "" // ident not needed since the assumed and real names are the same. - } - return ident -} - -// apply will perform the fixes on f in order. -func apply(fset *token.FileSet, f *ast.File, fixes []*ImportFix) { - for _, fix := range fixes { - switch fix.FixType { - case DeleteImport: - astutil.DeleteNamedImport(fset, f, fix.StmtInfo.Name, fix.StmtInfo.ImportPath) - case AddImport: - astutil.AddNamedImport(fset, f, fix.StmtInfo.Name, fix.StmtInfo.ImportPath) - case SetImportName: - // Find the matching import path and change the name. - for _, spec := range f.Imports { - path := strings.Trim(spec.Path.Value, `"`) - if path == fix.StmtInfo.ImportPath { - spec.Name = &ast.Ident{ - Name: fix.StmtInfo.Name, - NamePos: spec.Pos(), - } - } - } - } - } -} - -// assumeSiblingImportsValid assumes that siblings' use of packages is valid, -// adding the exports they use. -func (p *pass) assumeSiblingImportsValid() { - for _, f := range p.otherFiles { - refs := collectReferences(f) - imports := collectImports(f) - importsByName := map[string]*ImportInfo{} - for _, imp := range imports { - importsByName[p.importIdentifier(imp)] = imp - } - for left, rights := range refs { - if imp, ok := importsByName[left]; ok { - if m, ok := stdlib[imp.ImportPath]; ok { - // We have the stdlib in memory; no need to guess. - rights = copyExports(m) - } - p.addCandidate(imp, &packageInfo{ - // no name; we already know it. - exports: rights, - }) - } - } - } -} - -// addCandidate adds a candidate import to p, and merges in the information -// in pkg. -func (p *pass) addCandidate(imp *ImportInfo, pkg *packageInfo) { - p.candidates = append(p.candidates, imp) - if existing, ok := p.knownPackages[imp.ImportPath]; ok { - if existing.name == "" { - existing.name = pkg.name - } - for export := range pkg.exports { - existing.exports[export] = true - } - } else { - p.knownPackages[imp.ImportPath] = pkg - } -} - -// fixImports adds and removes imports from f so that all its references are -// satisfied and there are no unused imports. -// -// This is declared as a variable rather than a function so goimports can -// easily be extended by adding a file with an init function. -var fixImports = fixImportsDefault - -func fixImportsDefault(fset *token.FileSet, f *ast.File, filename string, env *ProcessEnv) error { - fixes, err := getFixes(fset, f, filename, env) - if err != nil { - return err - } - apply(fset, f, fixes) - return err -} - -// getFixes gets the import fixes that need to be made to f in order to fix the imports. -// It does not modify the ast. -func getFixes(fset *token.FileSet, f *ast.File, filename string, env *ProcessEnv) ([]*ImportFix, error) { - abs, err := filepath.Abs(filename) - if err != nil { - return nil, err - } - srcDir := filepath.Dir(abs) - if env.Logf != nil { - env.Logf("fixImports(filename=%q), abs=%q, srcDir=%q ...", filename, abs, srcDir) - } - - // First pass: looking only at f, and using the naive algorithm to - // derive package names from import paths, see if the file is already - // complete. We can't add any imports yet, because we don't know - // if missing references are actually package vars. - p := &pass{fset: fset, f: f, srcDir: srcDir, env: env} - if fixes, done := p.load(); done { - return fixes, nil - } - - otherFiles := parseOtherFiles(fset, srcDir, filename) - - // Second pass: add information from other files in the same package, - // like their package vars and imports. - p.otherFiles = otherFiles - if fixes, done := p.load(); done { - return fixes, nil - } - - // Now we can try adding imports from the stdlib. - p.assumeSiblingImportsValid() - addStdlibCandidates(p, p.missingRefs) - if fixes, done := p.fix(); done { - return fixes, nil - } - - // Third pass: get real package names where we had previously used - // the naive algorithm. - p = &pass{fset: fset, f: f, srcDir: srcDir, env: env} - p.loadRealPackageNames = true - p.otherFiles = otherFiles - if fixes, done := p.load(); done { - return fixes, nil - } - - if err := addStdlibCandidates(p, p.missingRefs); err != nil { - return nil, err - } - p.assumeSiblingImportsValid() - if fixes, done := p.fix(); done { - return fixes, nil - } - - // Go look for candidates in $GOPATH, etc. We don't necessarily load - // the real exports of sibling imports, so keep assuming their contents. - if err := addExternalCandidates(p, p.missingRefs, filename); err != nil { - return nil, err - } - - p.lastTry = true - fixes, _ := p.fix() - return fixes, nil -} - -// MaxRelevance is the highest relevance, used for the standard library. -// Chosen arbitrarily to match pre-existing gopls code. -const MaxRelevance = 7.0 - -// getCandidatePkgs works with the passed callback to find all acceptable packages. -// It deduplicates by import path, and uses a cached stdlib rather than reading -// from disk. -func getCandidatePkgs(ctx context.Context, wrappedCallback *scanCallback, filename, filePkg string, env *ProcessEnv) error { - notSelf := func(p *pkg) bool { - return p.packageName != filePkg || p.dir != filepath.Dir(filename) - } - goenv, err := env.goEnv() - if err != nil { - return err - } - - var mu sync.Mutex // to guard asynchronous access to dupCheck - dupCheck := map[string]struct{}{} - - // Start off with the standard library. - for importPath, exports := range stdlib { - p := &pkg{ - dir: filepath.Join(goenv["GOROOT"], "src", importPath), - importPathShort: importPath, - packageName: path.Base(importPath), - relevance: MaxRelevance, - } - dupCheck[importPath] = struct{}{} - if notSelf(p) && wrappedCallback.dirFound(p) && wrappedCallback.packageNameLoaded(p) { - wrappedCallback.exportsLoaded(p, exports) - } - } - - scanFilter := &scanCallback{ - rootFound: func(root gopathwalk.Root) bool { - // Exclude goroot results -- getting them is relatively expensive, not cached, - // and generally redundant with the in-memory version. - return root.Type != gopathwalk.RootGOROOT && wrappedCallback.rootFound(root) - }, - dirFound: wrappedCallback.dirFound, - packageNameLoaded: func(pkg *pkg) bool { - mu.Lock() - defer mu.Unlock() - if _, ok := dupCheck[pkg.importPathShort]; ok { - return false - } - dupCheck[pkg.importPathShort] = struct{}{} - return notSelf(pkg) && wrappedCallback.packageNameLoaded(pkg) - }, - exportsLoaded: func(pkg *pkg, exports []string) { - // If we're an x_test, load the package under test's test variant. - if strings.HasSuffix(filePkg, "_test") && pkg.dir == filepath.Dir(filename) { - var err error - _, exports, err = loadExportsFromFiles(ctx, env, pkg.dir, true) - if err != nil { - return - } - } - wrappedCallback.exportsLoaded(pkg, exports) - }, - } - resolver, err := env.GetResolver() - if err != nil { - return err - } - return resolver.scan(ctx, scanFilter) -} - -func ScoreImportPaths(ctx context.Context, env *ProcessEnv, paths []string) (map[string]float64, error) { - result := make(map[string]float64) - resolver, err := env.GetResolver() - if err != nil { - return nil, err - } - for _, path := range paths { - result[path] = resolver.scoreImportPath(ctx, path) - } - return result, nil -} - -func PrimeCache(ctx context.Context, env *ProcessEnv) error { - // Fully scan the disk for directories, but don't actually read any Go files. - callback := &scanCallback{ - rootFound: func(gopathwalk.Root) bool { - return true - }, - dirFound: func(pkg *pkg) bool { - return false - }, - packageNameLoaded: func(pkg *pkg) bool { - return false - }, - } - return getCandidatePkgs(ctx, callback, "", "", env) -} - -func candidateImportName(pkg *pkg) string { - if ImportPathToAssumedName(pkg.importPathShort) != pkg.packageName { - return pkg.packageName - } - return "" -} - -// GetAllCandidates calls wrapped for each package whose name starts with -// searchPrefix, and can be imported from filename with the package name filePkg. -// -// Beware that the wrapped function may be called multiple times concurrently. -// TODO(adonovan): encapsulate the concurrency. -func GetAllCandidates(ctx context.Context, wrapped func(ImportFix), searchPrefix, filename, filePkg string, env *ProcessEnv) error { - callback := &scanCallback{ - rootFound: func(gopathwalk.Root) bool { - return true - }, - dirFound: func(pkg *pkg) bool { - if !canUse(filename, pkg.dir) { - return false - } - // Try the assumed package name first, then a simpler path match - // in case of packages named vN, which are not uncommon. - return strings.HasPrefix(ImportPathToAssumedName(pkg.importPathShort), searchPrefix) || - strings.HasPrefix(path.Base(pkg.importPathShort), searchPrefix) - }, - packageNameLoaded: func(pkg *pkg) bool { - if !strings.HasPrefix(pkg.packageName, searchPrefix) { - return false - } - wrapped(ImportFix{ - StmtInfo: ImportInfo{ - ImportPath: pkg.importPathShort, - Name: candidateImportName(pkg), - }, - IdentName: pkg.packageName, - FixType: AddImport, - Relevance: pkg.relevance, - }) - return false - }, - } - return getCandidatePkgs(ctx, callback, filename, filePkg, env) -} - -// GetImportPaths calls wrapped for each package whose import path starts with -// searchPrefix, and can be imported from filename with the package name filePkg. -func GetImportPaths(ctx context.Context, wrapped func(ImportFix), searchPrefix, filename, filePkg string, env *ProcessEnv) error { - callback := &scanCallback{ - rootFound: func(gopathwalk.Root) bool { - return true - }, - dirFound: func(pkg *pkg) bool { - if !canUse(filename, pkg.dir) { - return false - } - return strings.HasPrefix(pkg.importPathShort, searchPrefix) - }, - packageNameLoaded: func(pkg *pkg) bool { - wrapped(ImportFix{ - StmtInfo: ImportInfo{ - ImportPath: pkg.importPathShort, - Name: candidateImportName(pkg), - }, - IdentName: pkg.packageName, - FixType: AddImport, - Relevance: pkg.relevance, - }) - return false - }, - } - return getCandidatePkgs(ctx, callback, filename, filePkg, env) -} - -// A PackageExport is a package and its exports. -type PackageExport struct { - Fix *ImportFix - Exports []string -} - -// GetPackageExports returns all known packages with name pkg and their exports. -func GetPackageExports(ctx context.Context, wrapped func(PackageExport), searchPkg, filename, filePkg string, env *ProcessEnv) error { - callback := &scanCallback{ - rootFound: func(gopathwalk.Root) bool { - return true - }, - dirFound: func(pkg *pkg) bool { - return pkgIsCandidate(filename, references{searchPkg: nil}, pkg) - }, - packageNameLoaded: func(pkg *pkg) bool { - return pkg.packageName == searchPkg - }, - exportsLoaded: func(pkg *pkg, exports []string) { - sort.Strings(exports) - wrapped(PackageExport{ - Fix: &ImportFix{ - StmtInfo: ImportInfo{ - ImportPath: pkg.importPathShort, - Name: candidateImportName(pkg), - }, - IdentName: pkg.packageName, - FixType: AddImport, - Relevance: pkg.relevance, - }, - Exports: exports, - }) - }, - } - return getCandidatePkgs(ctx, callback, filename, filePkg, env) -} - -var requiredGoEnvVars = []string{"GO111MODULE", "GOFLAGS", "GOINSECURE", "GOMOD", "GOMODCACHE", "GONOPROXY", "GONOSUMDB", "GOPATH", "GOPROXY", "GOROOT", "GOSUMDB", "GOWORK"} - -// ProcessEnv contains environment variables and settings that affect the use of -// the go command, the go/build package, etc. -type ProcessEnv struct { - GocmdRunner *gocommand.Runner - - BuildFlags []string - ModFlag string - ModFile string - - // SkipPathInScan returns true if the path should be skipped from scans of - // the RootCurrentModule root type. The function argument is a clean, - // absolute path. - SkipPathInScan func(string) bool - - // Env overrides the OS environment, and can be used to specify - // GOPROXY, GO111MODULE, etc. PATH cannot be set here, because - // exec.Command will not honor it. - // Specifying all of RequiredGoEnvVars avoids a call to `go env`. - Env map[string]string - - WorkingDir string - - // If Logf is non-nil, debug logging is enabled through this function. - Logf func(format string, args ...interface{}) - - initialized bool - - resolver Resolver -} - -func (e *ProcessEnv) goEnv() (map[string]string, error) { - if err := e.init(); err != nil { - return nil, err - } - return e.Env, nil -} - -func (e *ProcessEnv) matchFile(dir, name string) (bool, error) { - bctx, err := e.buildContext() - if err != nil { - return false, err - } - return bctx.MatchFile(dir, name) -} - -// CopyConfig copies the env's configuration into a new env. -func (e *ProcessEnv) CopyConfig() *ProcessEnv { - copy := &ProcessEnv{ - GocmdRunner: e.GocmdRunner, - initialized: e.initialized, - BuildFlags: e.BuildFlags, - Logf: e.Logf, - WorkingDir: e.WorkingDir, - resolver: nil, - Env: map[string]string{}, - } - for k, v := range e.Env { - copy.Env[k] = v - } - return copy -} - -func (e *ProcessEnv) init() error { - if e.initialized { - return nil - } - - foundAllRequired := true - for _, k := range requiredGoEnvVars { - if _, ok := e.Env[k]; !ok { - foundAllRequired = false - break - } - } - if foundAllRequired { - e.initialized = true - return nil - } - - if e.Env == nil { - e.Env = map[string]string{} - } - - goEnv := map[string]string{} - stdout, err := e.invokeGo(context.TODO(), "env", append([]string{"-json"}, requiredGoEnvVars...)...) - if err != nil { - return err - } - if err := json.Unmarshal(stdout.Bytes(), &goEnv); err != nil { - return err - } - for k, v := range goEnv { - e.Env[k] = v - } - e.initialized = true - return nil -} - -func (e *ProcessEnv) env() []string { - var env []string // the gocommand package will prepend os.Environ. - for k, v := range e.Env { - env = append(env, k+"="+v) - } - return env -} - -func (e *ProcessEnv) GetResolver() (Resolver, error) { - if e.resolver != nil { - return e.resolver, nil - } - if err := e.init(); err != nil { - return nil, err - } - if len(e.Env["GOMOD"]) == 0 && len(e.Env["GOWORK"]) == 0 { - e.resolver = newGopathResolver(e) - return e.resolver, nil - } - e.resolver = newModuleResolver(e) - return e.resolver, nil -} - -func (e *ProcessEnv) buildContext() (*build.Context, error) { - ctx := build.Default - goenv, err := e.goEnv() - if err != nil { - return nil, err - } - ctx.GOROOT = goenv["GOROOT"] - ctx.GOPATH = goenv["GOPATH"] - - // As of Go 1.14, build.Context has a Dir field - // (see golang.org/issue/34860). - // Populate it only if present. - rc := reflect.ValueOf(&ctx).Elem() - dir := rc.FieldByName("Dir") - if dir.IsValid() && dir.Kind() == reflect.String { - dir.SetString(e.WorkingDir) - } - - // Since Go 1.11, go/build.Context.Import may invoke 'go list' depending on - // the value in GO111MODULE in the process's environment. We always want to - // run in GOPATH mode when calling Import, so we need to prevent this from - // happening. In Go 1.16, GO111MODULE defaults to "on", so this problem comes - // up more frequently. - // - // HACK: setting any of the Context I/O hooks prevents Import from invoking - // 'go list', regardless of GO111MODULE. This is undocumented, but it's - // unlikely to change before GOPATH support is removed. - ctx.ReadDir = ioutil.ReadDir - - return &ctx, nil -} - -func (e *ProcessEnv) invokeGo(ctx context.Context, verb string, args ...string) (*bytes.Buffer, error) { - inv := gocommand.Invocation{ - Verb: verb, - Args: args, - BuildFlags: e.BuildFlags, - Env: e.env(), - Logf: e.Logf, - WorkingDir: e.WorkingDir, - } - return e.GocmdRunner.Run(ctx, inv) -} - -func addStdlibCandidates(pass *pass, refs references) error { - goenv, err := pass.env.goEnv() - if err != nil { - return err - } - add := func(pkg string) { - // Prevent self-imports. - if path.Base(pkg) == pass.f.Name.Name && filepath.Join(goenv["GOROOT"], "src", pkg) == pass.srcDir { - return - } - exports := copyExports(stdlib[pkg]) - pass.addCandidate( - &ImportInfo{ImportPath: pkg}, - &packageInfo{name: path.Base(pkg), exports: exports}) - } - for left := range refs { - if left == "rand" { - // Make sure we try crypto/rand before math/rand. - add("crypto/rand") - add("math/rand") - continue - } - for importPath := range stdlib { - if path.Base(importPath) == left { - add(importPath) - } - } - } - return nil -} - -// A Resolver does the build-system-specific parts of goimports. -type Resolver interface { - // loadPackageNames loads the package names in importPaths. - loadPackageNames(importPaths []string, srcDir string) (map[string]string, error) - // scan works with callback to search for packages. See scanCallback for details. - scan(ctx context.Context, callback *scanCallback) error - // loadExports returns the set of exported symbols in the package at dir. - // loadExports may be called concurrently. - loadExports(ctx context.Context, pkg *pkg, includeTest bool) (string, []string, error) - // scoreImportPath returns the relevance for an import path. - scoreImportPath(ctx context.Context, path string) float64 - - ClearForNewScan() -} - -// A scanCallback controls a call to scan and receives its results. -// In general, minor errors will be silently discarded; a user should not -// expect to receive a full series of calls for everything. -type scanCallback struct { - // rootFound is called before scanning a new root dir. If it returns true, - // the root will be scanned. Returning false will not necessarily prevent - // directories from that root making it to dirFound. - rootFound func(gopathwalk.Root) bool - // dirFound is called when a directory is found that is possibly a Go package. - // pkg will be populated with everything except packageName. - // If it returns true, the package's name will be loaded. - dirFound func(pkg *pkg) bool - // packageNameLoaded is called when a package is found and its name is loaded. - // If it returns true, the package's exports will be loaded. - packageNameLoaded func(pkg *pkg) bool - // exportsLoaded is called when a package's exports have been loaded. - exportsLoaded func(pkg *pkg, exports []string) -} - -func addExternalCandidates(pass *pass, refs references, filename string) error { - var mu sync.Mutex - found := make(map[string][]pkgDistance) - callback := &scanCallback{ - rootFound: func(gopathwalk.Root) bool { - return true // We want everything. - }, - dirFound: func(pkg *pkg) bool { - return pkgIsCandidate(filename, refs, pkg) - }, - packageNameLoaded: func(pkg *pkg) bool { - if _, want := refs[pkg.packageName]; !want { - return false - } - if pkg.dir == pass.srcDir && pass.f.Name.Name == pkg.packageName { - // The candidate is in the same directory and has the - // same package name. Don't try to import ourselves. - return false - } - if !canUse(filename, pkg.dir) { - return false - } - mu.Lock() - defer mu.Unlock() - found[pkg.packageName] = append(found[pkg.packageName], pkgDistance{pkg, distance(pass.srcDir, pkg.dir)}) - return false // We'll do our own loading after we sort. - }, - } - resolver, err := pass.env.GetResolver() - if err != nil { - return err - } - if err = resolver.scan(context.Background(), callback); err != nil { - return err - } - - // Search for imports matching potential package references. - type result struct { - imp *ImportInfo - pkg *packageInfo - } - results := make(chan result, len(refs)) - - ctx, cancel := context.WithCancel(context.TODO()) - var wg sync.WaitGroup - defer func() { - cancel() - wg.Wait() - }() - var ( - firstErr error - firstErrOnce sync.Once - ) - for pkgName, symbols := range refs { - wg.Add(1) - go func(pkgName string, symbols map[string]bool) { - defer wg.Done() - - found, err := findImport(ctx, pass, found[pkgName], pkgName, symbols, filename) - - if err != nil { - firstErrOnce.Do(func() { - firstErr = err - cancel() - }) - return - } - - if found == nil { - return // No matching package. - } - - imp := &ImportInfo{ - ImportPath: found.importPathShort, - } - - pkg := &packageInfo{ - name: pkgName, - exports: symbols, - } - results <- result{imp, pkg} - }(pkgName, symbols) - } - go func() { - wg.Wait() - close(results) - }() - - for result := range results { - pass.addCandidate(result.imp, result.pkg) - } - return firstErr -} - -// notIdentifier reports whether ch is an invalid identifier character. -func notIdentifier(ch rune) bool { - return !('a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || - '0' <= ch && ch <= '9' || - ch == '_' || - ch >= utf8.RuneSelf && (unicode.IsLetter(ch) || unicode.IsDigit(ch))) -} - -// ImportPathToAssumedName returns the assumed package name of an import path. -// It does this using only string parsing of the import path. -// It picks the last element of the path that does not look like a major -// version, and then picks the valid identifier off the start of that element. -// It is used to determine if a local rename should be added to an import for -// clarity. -// This function could be moved to a standard package and exported if we want -// for use in other tools. -func ImportPathToAssumedName(importPath string) string { - base := path.Base(importPath) - if strings.HasPrefix(base, "v") { - if _, err := strconv.Atoi(base[1:]); err == nil { - dir := path.Dir(importPath) - if dir != "." { - base = path.Base(dir) - } - } - } - base = strings.TrimPrefix(base, "go-") - if i := strings.IndexFunc(base, notIdentifier); i >= 0 { - base = base[:i] - } - return base -} - -// gopathResolver implements resolver for GOPATH workspaces. -type gopathResolver struct { - env *ProcessEnv - walked bool - cache *dirInfoCache - scanSema chan struct{} // scanSema prevents concurrent scans. -} - -func newGopathResolver(env *ProcessEnv) *gopathResolver { - r := &gopathResolver{ - env: env, - cache: &dirInfoCache{ - dirs: map[string]*directoryPackageInfo{}, - listeners: map[*int]cacheListener{}, - }, - scanSema: make(chan struct{}, 1), - } - r.scanSema <- struct{}{} - return r -} - -func (r *gopathResolver) ClearForNewScan() { - <-r.scanSema - r.cache = &dirInfoCache{ - dirs: map[string]*directoryPackageInfo{}, - listeners: map[*int]cacheListener{}, - } - r.walked = false - r.scanSema <- struct{}{} -} - -func (r *gopathResolver) loadPackageNames(importPaths []string, srcDir string) (map[string]string, error) { - names := map[string]string{} - bctx, err := r.env.buildContext() - if err != nil { - return nil, err - } - for _, path := range importPaths { - names[path] = importPathToName(bctx, path, srcDir) - } - return names, nil -} - -// importPathToName finds out the actual package name, as declared in its .go files. -func importPathToName(bctx *build.Context, importPath, srcDir string) string { - // Fast path for standard library without going to disk. - if _, ok := stdlib[importPath]; ok { - return path.Base(importPath) // stdlib packages always match their paths. - } - - buildPkg, err := bctx.Import(importPath, srcDir, build.FindOnly) - if err != nil { - return "" - } - pkgName, err := packageDirToName(buildPkg.Dir) - if err != nil { - return "" - } - return pkgName -} - -// packageDirToName is a faster version of build.Import if -// the only thing desired is the package name. Given a directory, -// packageDirToName then only parses one file in the package, -// trusting that the files in the directory are consistent. -func packageDirToName(dir string) (packageName string, err error) { - d, err := os.Open(dir) - if err != nil { - return "", err - } - names, err := d.Readdirnames(-1) - d.Close() - if err != nil { - return "", err - } - sort.Strings(names) // to have predictable behavior - var lastErr error - var nfile int - for _, name := range names { - if !strings.HasSuffix(name, ".go") { - continue - } - if strings.HasSuffix(name, "_test.go") { - continue - } - nfile++ - fullFile := filepath.Join(dir, name) - - fset := token.NewFileSet() - f, err := parser.ParseFile(fset, fullFile, nil, parser.PackageClauseOnly) - if err != nil { - lastErr = err - continue - } - pkgName := f.Name.Name - if pkgName == "documentation" { - // Special case from go/build.ImportDir, not - // handled by ctx.MatchFile. - continue - } - if pkgName == "main" { - // Also skip package main, assuming it's a +build ignore generator or example. - // Since you can't import a package main anyway, there's no harm here. - continue - } - return pkgName, nil - } - if lastErr != nil { - return "", lastErr - } - return "", fmt.Errorf("no importable package found in %d Go files", nfile) -} - -type pkg struct { - dir string // absolute file path to pkg directory ("/usr/lib/go/src/net/http") - importPathShort string // vendorless import path ("net/http", "a/b") - packageName string // package name loaded from source if requested - relevance float64 // a weakly-defined score of how relevant a package is. 0 is most relevant. -} - -type pkgDistance struct { - pkg *pkg - distance int // relative distance to target -} - -// byDistanceOrImportPathShortLength sorts by relative distance breaking ties -// on the short import path length and then the import string itself. -type byDistanceOrImportPathShortLength []pkgDistance - -func (s byDistanceOrImportPathShortLength) Len() int { return len(s) } -func (s byDistanceOrImportPathShortLength) Less(i, j int) bool { - di, dj := s[i].distance, s[j].distance - if di == -1 { - return false - } - if dj == -1 { - return true - } - if di != dj { - return di < dj - } - - vi, vj := s[i].pkg.importPathShort, s[j].pkg.importPathShort - if len(vi) != len(vj) { - return len(vi) < len(vj) - } - return vi < vj -} -func (s byDistanceOrImportPathShortLength) Swap(i, j int) { s[i], s[j] = s[j], s[i] } - -func distance(basepath, targetpath string) int { - p, err := filepath.Rel(basepath, targetpath) - if err != nil { - return -1 - } - if p == "." { - return 0 - } - return strings.Count(p, string(filepath.Separator)) + 1 -} - -func (r *gopathResolver) scan(ctx context.Context, callback *scanCallback) error { - add := func(root gopathwalk.Root, dir string) { - // We assume cached directories have not changed. We can skip them and their - // children. - if _, ok := r.cache.Load(dir); ok { - return - } - - importpath := filepath.ToSlash(dir[len(root.Path)+len("/"):]) - info := directoryPackageInfo{ - status: directoryScanned, - dir: dir, - rootType: root.Type, - nonCanonicalImportPath: VendorlessPath(importpath), - } - r.cache.Store(dir, info) - } - processDir := func(info directoryPackageInfo) { - // Skip this directory if we were not able to get the package information successfully. - if scanned, err := info.reachedStatus(directoryScanned); !scanned || err != nil { - return - } - - p := &pkg{ - importPathShort: info.nonCanonicalImportPath, - dir: info.dir, - relevance: MaxRelevance - 1, - } - if info.rootType == gopathwalk.RootGOROOT { - p.relevance = MaxRelevance - } - - if !callback.dirFound(p) { - return - } - var err error - p.packageName, err = r.cache.CachePackageName(info) - if err != nil { - return - } - - if !callback.packageNameLoaded(p) { - return - } - if _, exports, err := r.loadExports(ctx, p, false); err == nil { - callback.exportsLoaded(p, exports) - } - } - stop := r.cache.ScanAndListen(ctx, processDir) - defer stop() - - goenv, err := r.env.goEnv() - if err != nil { - return err - } - var roots []gopathwalk.Root - roots = append(roots, gopathwalk.Root{Path: filepath.Join(goenv["GOROOT"], "src"), Type: gopathwalk.RootGOROOT}) - for _, p := range filepath.SplitList(goenv["GOPATH"]) { - roots = append(roots, gopathwalk.Root{Path: filepath.Join(p, "src"), Type: gopathwalk.RootGOPATH}) - } - // The callback is not necessarily safe to use in the goroutine below. Process roots eagerly. - roots = filterRoots(roots, callback.rootFound) - // We can't cancel walks, because we need them to finish to have a usable - // cache. Instead, run them in a separate goroutine and detach. - scanDone := make(chan struct{}) - go func() { - select { - case <-ctx.Done(): - return - case <-r.scanSema: - } - defer func() { r.scanSema <- struct{}{} }() - gopathwalk.Walk(roots, add, gopathwalk.Options{Logf: r.env.Logf, ModulesEnabled: false}) - close(scanDone) - }() - select { - case <-ctx.Done(): - case <-scanDone: - } - return nil -} - -func (r *gopathResolver) scoreImportPath(ctx context.Context, path string) float64 { - if _, ok := stdlib[path]; ok { - return MaxRelevance - } - return MaxRelevance - 1 -} - -func filterRoots(roots []gopathwalk.Root, include func(gopathwalk.Root) bool) []gopathwalk.Root { - var result []gopathwalk.Root - for _, root := range roots { - if !include(root) { - continue - } - result = append(result, root) - } - return result -} - -func (r *gopathResolver) loadExports(ctx context.Context, pkg *pkg, includeTest bool) (string, []string, error) { - if info, ok := r.cache.Load(pkg.dir); ok && !includeTest { - return r.cache.CacheExports(ctx, r.env, info) - } - return loadExportsFromFiles(ctx, r.env, pkg.dir, includeTest) -} - -// VendorlessPath returns the devendorized version of the import path ipath. -// For example, VendorlessPath("foo/bar/vendor/a/b") returns "a/b". -func VendorlessPath(ipath string) string { - // Devendorize for use in import statement. - if i := strings.LastIndex(ipath, "/vendor/"); i >= 0 { - return ipath[i+len("/vendor/"):] - } - if strings.HasPrefix(ipath, "vendor/") { - return ipath[len("vendor/"):] - } - return ipath -} - -func loadExportsFromFiles(ctx context.Context, env *ProcessEnv, dir string, includeTest bool) (string, []string, error) { - // Look for non-test, buildable .go files which could provide exports. - all, err := ioutil.ReadDir(dir) - if err != nil { - return "", nil, err - } - var files []os.FileInfo - for _, fi := range all { - name := fi.Name() - if !strings.HasSuffix(name, ".go") || (!includeTest && strings.HasSuffix(name, "_test.go")) { - continue - } - match, err := env.matchFile(dir, fi.Name()) - if err != nil || !match { - continue - } - files = append(files, fi) - } - - if len(files) == 0 { - return "", nil, fmt.Errorf("dir %v contains no buildable, non-test .go files", dir) - } - - var pkgName string - var exports []string - fset := token.NewFileSet() - for _, fi := range files { - select { - case <-ctx.Done(): - return "", nil, ctx.Err() - default: - } - - fullFile := filepath.Join(dir, fi.Name()) - f, err := parser.ParseFile(fset, fullFile, nil, 0) - if err != nil { - if env.Logf != nil { - env.Logf("error parsing %v: %v", fullFile, err) - } - continue - } - if f.Name.Name == "documentation" { - // Special case from go/build.ImportDir, not - // handled by MatchFile above. - continue - } - if includeTest && strings.HasSuffix(f.Name.Name, "_test") { - // x_test package. We want internal test files only. - continue - } - pkgName = f.Name.Name - for name := range f.Scope.Objects { - if ast.IsExported(name) { - exports = append(exports, name) - } - } - } - - if env.Logf != nil { - sortedExports := append([]string(nil), exports...) - sort.Strings(sortedExports) - env.Logf("loaded exports in dir %v (package %v): %v", dir, pkgName, strings.Join(sortedExports, ", ")) - } - return pkgName, exports, nil -} - -// findImport searches for a package with the given symbols. -// If no package is found, findImport returns ("", false, nil) -func findImport(ctx context.Context, pass *pass, candidates []pkgDistance, pkgName string, symbols map[string]bool, filename string) (*pkg, error) { - // Sort the candidates by their import package length, - // assuming that shorter package names are better than long - // ones. Note that this sorts by the de-vendored name, so - // there's no "penalty" for vendoring. - sort.Sort(byDistanceOrImportPathShortLength(candidates)) - if pass.env.Logf != nil { - for i, c := range candidates { - pass.env.Logf("%s candidate %d/%d: %v in %v", pkgName, i+1, len(candidates), c.pkg.importPathShort, c.pkg.dir) - } - } - resolver, err := pass.env.GetResolver() - if err != nil { - return nil, err - } - - // Collect exports for packages with matching names. - rescv := make([]chan *pkg, len(candidates)) - for i := range candidates { - rescv[i] = make(chan *pkg, 1) - } - const maxConcurrentPackageImport = 4 - loadExportsSem := make(chan struct{}, maxConcurrentPackageImport) - - ctx, cancel := context.WithCancel(ctx) - var wg sync.WaitGroup - defer func() { - cancel() - wg.Wait() - }() - - wg.Add(1) - go func() { - defer wg.Done() - for i, c := range candidates { - select { - case loadExportsSem <- struct{}{}: - case <-ctx.Done(): - return - } - - wg.Add(1) - go func(c pkgDistance, resc chan<- *pkg) { - defer func() { - <-loadExportsSem - wg.Done() - }() - - if pass.env.Logf != nil { - pass.env.Logf("loading exports in dir %s (seeking package %s)", c.pkg.dir, pkgName) - } - // If we're an x_test, load the package under test's test variant. - includeTest := strings.HasSuffix(pass.f.Name.Name, "_test") && c.pkg.dir == pass.srcDir - _, exports, err := resolver.loadExports(ctx, c.pkg, includeTest) - if err != nil { - if pass.env.Logf != nil { - pass.env.Logf("loading exports in dir %s (seeking package %s): %v", c.pkg.dir, pkgName, err) - } - resc <- nil - return - } - - exportsMap := make(map[string]bool, len(exports)) - for _, sym := range exports { - exportsMap[sym] = true - } - - // If it doesn't have the right - // symbols, send nil to mean no match. - for symbol := range symbols { - if !exportsMap[symbol] { - resc <- nil - return - } - } - resc <- c.pkg - }(c, rescv[i]) - } - }() - - for _, resc := range rescv { - pkg := <-resc - if pkg == nil { - continue - } - return pkg, nil - } - return nil, nil -} - -// pkgIsCandidate reports whether pkg is a candidate for satisfying the -// finding which package pkgIdent in the file named by filename is trying -// to refer to. -// -// This check is purely lexical and is meant to be as fast as possible -// because it's run over all $GOPATH directories to filter out poor -// candidates in order to limit the CPU and I/O later parsing the -// exports in candidate packages. -// -// filename is the file being formatted. -// pkgIdent is the package being searched for, like "client" (if -// searching for "client.New") -func pkgIsCandidate(filename string, refs references, pkg *pkg) bool { - // Check "internal" and "vendor" visibility: - if !canUse(filename, pkg.dir) { - return false - } - - // Speed optimization to minimize disk I/O: - // the last two components on disk must contain the - // package name somewhere. - // - // This permits mismatch naming like directory - // "go-foo" being package "foo", or "pkg.v3" being "pkg", - // or directory "google.golang.org/api/cloudbilling/v1" - // being package "cloudbilling", but doesn't - // permit a directory "foo" to be package - // "bar", which is strongly discouraged - // anyway. There's no reason goimports needs - // to be slow just to accommodate that. - for pkgIdent := range refs { - lastTwo := lastTwoComponents(pkg.importPathShort) - if strings.Contains(lastTwo, pkgIdent) { - return true - } - if hasHyphenOrUpperASCII(lastTwo) && !hasHyphenOrUpperASCII(pkgIdent) { - lastTwo = lowerASCIIAndRemoveHyphen(lastTwo) - if strings.Contains(lastTwo, pkgIdent) { - return true - } - } - } - return false -} - -func hasHyphenOrUpperASCII(s string) bool { - for i := 0; i < len(s); i++ { - b := s[i] - if b == '-' || ('A' <= b && b <= 'Z') { - return true - } - } - return false -} - -func lowerASCIIAndRemoveHyphen(s string) (ret string) { - buf := make([]byte, 0, len(s)) - for i := 0; i < len(s); i++ { - b := s[i] - switch { - case b == '-': - continue - case 'A' <= b && b <= 'Z': - buf = append(buf, b+('a'-'A')) - default: - buf = append(buf, b) - } - } - return string(buf) -} - -// canUse reports whether the package in dir is usable from filename, -// respecting the Go "internal" and "vendor" visibility rules. -func canUse(filename, dir string) bool { - // Fast path check, before any allocations. If it doesn't contain vendor - // or internal, it's not tricky: - // Note that this can false-negative on directories like "notinternal", - // but we check it correctly below. This is just a fast path. - if !strings.Contains(dir, "vendor") && !strings.Contains(dir, "internal") { - return true - } - - dirSlash := filepath.ToSlash(dir) - if !strings.Contains(dirSlash, "/vendor/") && !strings.Contains(dirSlash, "/internal/") && !strings.HasSuffix(dirSlash, "/internal") { - return true - } - // Vendor or internal directory only visible from children of parent. - // That means the path from the current directory to the target directory - // can contain ../vendor or ../internal but not ../foo/vendor or ../foo/internal - // or bar/vendor or bar/internal. - // After stripping all the leading ../, the only okay place to see vendor or internal - // is at the very beginning of the path. - absfile, err := filepath.Abs(filename) - if err != nil { - return false - } - absdir, err := filepath.Abs(dir) - if err != nil { - return false - } - rel, err := filepath.Rel(absfile, absdir) - if err != nil { - return false - } - relSlash := filepath.ToSlash(rel) - if i := strings.LastIndex(relSlash, "../"); i >= 0 { - relSlash = relSlash[i+len("../"):] - } - return !strings.Contains(relSlash, "/vendor/") && !strings.Contains(relSlash, "/internal/") && !strings.HasSuffix(relSlash, "/internal") -} - -// lastTwoComponents returns at most the last two path components -// of v, using either / or \ as the path separator. -func lastTwoComponents(v string) string { - nslash := 0 - for i := len(v) - 1; i >= 0; i-- { - if v[i] == '/' || v[i] == '\\' { - nslash++ - if nslash == 2 { - return v[i:] - } - } - } - return v -} - -type visitFn func(node ast.Node) ast.Visitor - -func (fn visitFn) Visit(node ast.Node) ast.Visitor { - return fn(node) -} - -func copyExports(pkg []string) map[string]bool { - m := make(map[string]bool, len(pkg)) - for _, v := range pkg { - m[v] = true - } - return m -} diff --git a/vendor/golang.org/x/tools/internal/imports/imports.go b/vendor/golang.org/x/tools/internal/imports/imports.go deleted file mode 100644 index 95a88383a79..00000000000 --- a/vendor/golang.org/x/tools/internal/imports/imports.go +++ /dev/null @@ -1,351 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:generate go run mkstdlib.go - -// Package imports implements a Go pretty-printer (like package "go/format") -// that also adds or removes import statements as necessary. -package imports - -import ( - "bufio" - "bytes" - "fmt" - "go/ast" - "go/format" - "go/parser" - "go/printer" - "go/token" - "io" - "regexp" - "strconv" - "strings" - - "golang.org/x/tools/go/ast/astutil" -) - -// Options is golang.org/x/tools/imports.Options with extra internal-only options. -type Options struct { - Env *ProcessEnv // The environment to use. Note: this contains the cached module and filesystem state. - - // LocalPrefix is a comma-separated string of import path prefixes, which, if - // set, instructs Process to sort the import paths with the given prefixes - // into another group after 3rd-party packages. - LocalPrefix string - - Fragment bool // Accept fragment of a source file (no package statement) - AllErrors bool // Report all errors (not just the first 10 on different lines) - - Comments bool // Print comments (true if nil *Options provided) - TabIndent bool // Use tabs for indent (true if nil *Options provided) - TabWidth int // Tab width (8 if nil *Options provided) - - FormatOnly bool // Disable the insertion and deletion of imports -} - -// Process implements golang.org/x/tools/imports.Process with explicit context in opt.Env. -func Process(filename string, src []byte, opt *Options) (formatted []byte, err error) { - fileSet := token.NewFileSet() - file, adjust, err := parse(fileSet, filename, src, opt) - if err != nil { - return nil, err - } - - if !opt.FormatOnly { - if err := fixImports(fileSet, file, filename, opt.Env); err != nil { - return nil, err - } - } - return formatFile(fileSet, file, src, adjust, opt) -} - -// FixImports returns a list of fixes to the imports that, when applied, -// will leave the imports in the same state as Process. src and opt must -// be specified. -// -// Note that filename's directory influences which imports can be chosen, -// so it is important that filename be accurate. -func FixImports(filename string, src []byte, opt *Options) (fixes []*ImportFix, err error) { - fileSet := token.NewFileSet() - file, _, err := parse(fileSet, filename, src, opt) - if err != nil { - return nil, err - } - - return getFixes(fileSet, file, filename, opt.Env) -} - -// ApplyFixes applies all of the fixes to the file and formats it. extraMode -// is added in when parsing the file. src and opts must be specified, but no -// env is needed. -func ApplyFixes(fixes []*ImportFix, filename string, src []byte, opt *Options, extraMode parser.Mode) (formatted []byte, err error) { - // Don't use parse() -- we don't care about fragments or statement lists - // here, and we need to work with unparseable files. - fileSet := token.NewFileSet() - parserMode := parser.Mode(0) - if opt.Comments { - parserMode |= parser.ParseComments - } - if opt.AllErrors { - parserMode |= parser.AllErrors - } - parserMode |= extraMode - - file, err := parser.ParseFile(fileSet, filename, src, parserMode) - if file == nil { - return nil, err - } - - // Apply the fixes to the file. - apply(fileSet, file, fixes) - - return formatFile(fileSet, file, src, nil, opt) -} - -// formatFile formats the file syntax tree. -// It may mutate the token.FileSet. -// -// If an adjust function is provided, it is called after formatting -// with the original source (formatFile's src parameter) and the -// formatted file, and returns the postpocessed result. -func formatFile(fset *token.FileSet, file *ast.File, src []byte, adjust func(orig []byte, src []byte) []byte, opt *Options) ([]byte, error) { - mergeImports(file) - sortImports(opt.LocalPrefix, fset.File(file.Pos()), file) - var spacesBefore []string // import paths we need spaces before - for _, impSection := range astutil.Imports(fset, file) { - // Within each block of contiguous imports, see if any - // import lines are in different group numbers. If so, - // we'll need to put a space between them so it's - // compatible with gofmt. - lastGroup := -1 - for _, importSpec := range impSection { - importPath, _ := strconv.Unquote(importSpec.Path.Value) - groupNum := importGroup(opt.LocalPrefix, importPath) - if groupNum != lastGroup && lastGroup != -1 { - spacesBefore = append(spacesBefore, importPath) - } - lastGroup = groupNum - } - - } - - printerMode := printer.UseSpaces - if opt.TabIndent { - printerMode |= printer.TabIndent - } - printConfig := &printer.Config{Mode: printerMode, Tabwidth: opt.TabWidth} - - var buf bytes.Buffer - err := printConfig.Fprint(&buf, fset, file) - if err != nil { - return nil, err - } - out := buf.Bytes() - if adjust != nil { - out = adjust(src, out) - } - if len(spacesBefore) > 0 { - out, err = addImportSpaces(bytes.NewReader(out), spacesBefore) - if err != nil { - return nil, err - } - } - - out, err = format.Source(out) - if err != nil { - return nil, err - } - return out, nil -} - -// parse parses src, which was read from filename, -// as a Go source file or statement list. -func parse(fset *token.FileSet, filename string, src []byte, opt *Options) (*ast.File, func(orig, src []byte) []byte, error) { - parserMode := parser.Mode(0) - if opt.Comments { - parserMode |= parser.ParseComments - } - if opt.AllErrors { - parserMode |= parser.AllErrors - } - - // Try as whole source file. - file, err := parser.ParseFile(fset, filename, src, parserMode) - if err == nil { - return file, nil, nil - } - // If the error is that the source file didn't begin with a - // package line and we accept fragmented input, fall through to - // try as a source fragment. Stop and return on any other error. - if !opt.Fragment || !strings.Contains(err.Error(), "expected 'package'") { - return nil, nil, err - } - - // If this is a declaration list, make it a source file - // by inserting a package clause. - // Insert using a ;, not a newline, so that parse errors are on - // the correct line. - const prefix = "package main;" - psrc := append([]byte(prefix), src...) - file, err = parser.ParseFile(fset, filename, psrc, parserMode) - if err == nil { - // Gofmt will turn the ; into a \n. - // Do that ourselves now and update the file contents, - // so that positions and line numbers are correct going forward. - psrc[len(prefix)-1] = '\n' - fset.File(file.Package).SetLinesForContent(psrc) - - // If a main function exists, we will assume this is a main - // package and leave the file. - if containsMainFunc(file) { - return file, nil, nil - } - - adjust := func(orig, src []byte) []byte { - // Remove the package clause. - src = src[len(prefix):] - return matchSpace(orig, src) - } - return file, adjust, nil - } - // If the error is that the source file didn't begin with a - // declaration, fall through to try as a statement list. - // Stop and return on any other error. - if !strings.Contains(err.Error(), "expected declaration") { - return nil, nil, err - } - - // If this is a statement list, make it a source file - // by inserting a package clause and turning the list - // into a function body. This handles expressions too. - // Insert using a ;, not a newline, so that the line numbers - // in fsrc match the ones in src. - fsrc := append(append([]byte("package p; func _() {"), src...), '}') - file, err = parser.ParseFile(fset, filename, fsrc, parserMode) - if err == nil { - adjust := func(orig, src []byte) []byte { - // Remove the wrapping. - // Gofmt has turned the ; into a \n\n. - src = src[len("package p\n\nfunc _() {"):] - src = src[:len(src)-len("}\n")] - // Gofmt has also indented the function body one level. - // Remove that indent. - src = bytes.Replace(src, []byte("\n\t"), []byte("\n"), -1) - return matchSpace(orig, src) - } - return file, adjust, nil - } - - // Failed, and out of options. - return nil, nil, err -} - -// containsMainFunc checks if a file contains a function declaration with the -// function signature 'func main()' -func containsMainFunc(file *ast.File) bool { - for _, decl := range file.Decls { - if f, ok := decl.(*ast.FuncDecl); ok { - if f.Name.Name != "main" { - continue - } - - if len(f.Type.Params.List) != 0 { - continue - } - - if f.Type.Results != nil && len(f.Type.Results.List) != 0 { - continue - } - - return true - } - } - - return false -} - -func cutSpace(b []byte) (before, middle, after []byte) { - i := 0 - for i < len(b) && (b[i] == ' ' || b[i] == '\t' || b[i] == '\n') { - i++ - } - j := len(b) - for j > 0 && (b[j-1] == ' ' || b[j-1] == '\t' || b[j-1] == '\n') { - j-- - } - if i <= j { - return b[:i], b[i:j], b[j:] - } - return nil, nil, b[j:] -} - -// matchSpace reformats src to use the same space context as orig. -// 1. If orig begins with blank lines, matchSpace inserts them at the beginning of src. -// 2. matchSpace copies the indentation of the first non-blank line in orig -// to every non-blank line in src. -// 3. matchSpace copies the trailing space from orig and uses it in place -// of src's trailing space. -func matchSpace(orig []byte, src []byte) []byte { - before, _, after := cutSpace(orig) - i := bytes.LastIndex(before, []byte{'\n'}) - before, indent := before[:i+1], before[i+1:] - - _, src, _ = cutSpace(src) - - var b bytes.Buffer - b.Write(before) - for len(src) > 0 { - line := src - if i := bytes.IndexByte(line, '\n'); i >= 0 { - line, src = line[:i+1], line[i+1:] - } else { - src = nil - } - if len(line) > 0 && line[0] != '\n' { // not blank - b.Write(indent) - } - b.Write(line) - } - b.Write(after) - return b.Bytes() -} - -var impLine = regexp.MustCompile(`^\s+(?:[\w\.]+\s+)?"(.+?)"`) - -func addImportSpaces(r io.Reader, breaks []string) ([]byte, error) { - var out bytes.Buffer - in := bufio.NewReader(r) - inImports := false - done := false - for { - s, err := in.ReadString('\n') - if err == io.EOF { - break - } else if err != nil { - return nil, err - } - - if !inImports && !done && strings.HasPrefix(s, "import") { - inImports = true - } - if inImports && (strings.HasPrefix(s, "var") || - strings.HasPrefix(s, "func") || - strings.HasPrefix(s, "const") || - strings.HasPrefix(s, "type")) { - done = true - inImports = false - } - if inImports && len(breaks) > 0 { - if m := impLine.FindStringSubmatch(s); m != nil { - if m[1] == breaks[0] { - out.WriteByte('\n') - breaks = breaks[1:] - } - } - } - - fmt.Fprint(&out, s) - } - return out.Bytes(), nil -} diff --git a/vendor/golang.org/x/tools/internal/imports/mod.go b/vendor/golang.org/x/tools/internal/imports/mod.go deleted file mode 100644 index 7d99d04ca8a..00000000000 --- a/vendor/golang.org/x/tools/internal/imports/mod.go +++ /dev/null @@ -1,716 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package imports - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "io/ioutil" - "os" - "path" - "path/filepath" - "regexp" - "sort" - "strconv" - "strings" - - "golang.org/x/mod/module" - "golang.org/x/tools/internal/gocommand" - "golang.org/x/tools/internal/gopathwalk" -) - -// ModuleResolver implements resolver for modules using the go command as little -// as feasible. -type ModuleResolver struct { - env *ProcessEnv - moduleCacheDir string - dummyVendorMod *gocommand.ModuleJSON // If vendoring is enabled, the pseudo-module that represents the /vendor directory. - roots []gopathwalk.Root - scanSema chan struct{} // scanSema prevents concurrent scans and guards scannedRoots. - scannedRoots map[gopathwalk.Root]bool - - initialized bool - mains []*gocommand.ModuleJSON - mainByDir map[string]*gocommand.ModuleJSON - modsByModPath []*gocommand.ModuleJSON // All modules, ordered by # of path components in module Path... - modsByDir []*gocommand.ModuleJSON // ...or Dir. - - // moduleCacheCache stores information about the module cache. - moduleCacheCache *dirInfoCache - otherCache *dirInfoCache -} - -func newModuleResolver(e *ProcessEnv) *ModuleResolver { - r := &ModuleResolver{ - env: e, - scanSema: make(chan struct{}, 1), - } - r.scanSema <- struct{}{} - return r -} - -func (r *ModuleResolver) init() error { - if r.initialized { - return nil - } - - goenv, err := r.env.goEnv() - if err != nil { - return err - } - inv := gocommand.Invocation{ - BuildFlags: r.env.BuildFlags, - ModFlag: r.env.ModFlag, - ModFile: r.env.ModFile, - Env: r.env.env(), - Logf: r.env.Logf, - WorkingDir: r.env.WorkingDir, - } - - vendorEnabled := false - var mainModVendor *gocommand.ModuleJSON - - // Module vendor directories are ignored in workspace mode: - // https://go.googlesource.com/proposal/+/master/design/45713-workspace.md - if len(r.env.Env["GOWORK"]) == 0 { - vendorEnabled, mainModVendor, err = gocommand.VendorEnabled(context.TODO(), inv, r.env.GocmdRunner) - if err != nil { - return err - } - } - - if mainModVendor != nil && vendorEnabled { - // Vendor mode is on, so all the non-Main modules are irrelevant, - // and we need to search /vendor for everything. - r.mains = []*gocommand.ModuleJSON{mainModVendor} - r.dummyVendorMod = &gocommand.ModuleJSON{ - Path: "", - Dir: filepath.Join(mainModVendor.Dir, "vendor"), - } - r.modsByModPath = []*gocommand.ModuleJSON{mainModVendor, r.dummyVendorMod} - r.modsByDir = []*gocommand.ModuleJSON{mainModVendor, r.dummyVendorMod} - } else { - // Vendor mode is off, so run go list -m ... to find everything. - err := r.initAllMods() - // We expect an error when running outside of a module with - // GO111MODULE=on. Other errors are fatal. - if err != nil { - if errMsg := err.Error(); !strings.Contains(errMsg, "working directory is not part of a module") && !strings.Contains(errMsg, "go.mod file not found") { - return err - } - } - } - - if gmc := r.env.Env["GOMODCACHE"]; gmc != "" { - r.moduleCacheDir = gmc - } else { - gopaths := filepath.SplitList(goenv["GOPATH"]) - if len(gopaths) == 0 { - return fmt.Errorf("empty GOPATH") - } - r.moduleCacheDir = filepath.Join(gopaths[0], "/pkg/mod") - } - - sort.Slice(r.modsByModPath, func(i, j int) bool { - count := func(x int) int { - return strings.Count(r.modsByModPath[x].Path, "/") - } - return count(j) < count(i) // descending order - }) - sort.Slice(r.modsByDir, func(i, j int) bool { - count := func(x int) int { - return strings.Count(r.modsByDir[x].Dir, "/") - } - return count(j) < count(i) // descending order - }) - - r.roots = []gopathwalk.Root{ - {Path: filepath.Join(goenv["GOROOT"], "/src"), Type: gopathwalk.RootGOROOT}, - } - r.mainByDir = make(map[string]*gocommand.ModuleJSON) - for _, main := range r.mains { - r.roots = append(r.roots, gopathwalk.Root{Path: main.Dir, Type: gopathwalk.RootCurrentModule}) - r.mainByDir[main.Dir] = main - } - if vendorEnabled { - r.roots = append(r.roots, gopathwalk.Root{Path: r.dummyVendorMod.Dir, Type: gopathwalk.RootOther}) - } else { - addDep := func(mod *gocommand.ModuleJSON) { - if mod.Replace == nil { - // This is redundant with the cache, but we'll skip it cheaply enough. - r.roots = append(r.roots, gopathwalk.Root{Path: mod.Dir, Type: gopathwalk.RootModuleCache}) - } else { - r.roots = append(r.roots, gopathwalk.Root{Path: mod.Dir, Type: gopathwalk.RootOther}) - } - } - // Walk dependent modules before scanning the full mod cache, direct deps first. - for _, mod := range r.modsByModPath { - if !mod.Indirect && !mod.Main { - addDep(mod) - } - } - for _, mod := range r.modsByModPath { - if mod.Indirect && !mod.Main { - addDep(mod) - } - } - r.roots = append(r.roots, gopathwalk.Root{Path: r.moduleCacheDir, Type: gopathwalk.RootModuleCache}) - } - - r.scannedRoots = map[gopathwalk.Root]bool{} - if r.moduleCacheCache == nil { - r.moduleCacheCache = &dirInfoCache{ - dirs: map[string]*directoryPackageInfo{}, - listeners: map[*int]cacheListener{}, - } - } - if r.otherCache == nil { - r.otherCache = &dirInfoCache{ - dirs: map[string]*directoryPackageInfo{}, - listeners: map[*int]cacheListener{}, - } - } - r.initialized = true - return nil -} - -func (r *ModuleResolver) initAllMods() error { - stdout, err := r.env.invokeGo(context.TODO(), "list", "-m", "-e", "-json", "...") - if err != nil { - return err - } - for dec := json.NewDecoder(stdout); dec.More(); { - mod := &gocommand.ModuleJSON{} - if err := dec.Decode(mod); err != nil { - return err - } - if mod.Dir == "" { - if r.env.Logf != nil { - r.env.Logf("module %v has not been downloaded and will be ignored", mod.Path) - } - // Can't do anything with a module that's not downloaded. - continue - } - // golang/go#36193: the go command doesn't always clean paths. - mod.Dir = filepath.Clean(mod.Dir) - r.modsByModPath = append(r.modsByModPath, mod) - r.modsByDir = append(r.modsByDir, mod) - if mod.Main { - r.mains = append(r.mains, mod) - } - } - return nil -} - -func (r *ModuleResolver) ClearForNewScan() { - <-r.scanSema - r.scannedRoots = map[gopathwalk.Root]bool{} - r.otherCache = &dirInfoCache{ - dirs: map[string]*directoryPackageInfo{}, - listeners: map[*int]cacheListener{}, - } - r.scanSema <- struct{}{} -} - -func (r *ModuleResolver) ClearForNewMod() { - <-r.scanSema - *r = ModuleResolver{ - env: r.env, - moduleCacheCache: r.moduleCacheCache, - otherCache: r.otherCache, - scanSema: r.scanSema, - } - r.init() - r.scanSema <- struct{}{} -} - -// findPackage returns the module and directory that contains the package at -// the given import path, or returns nil, "" if no module is in scope. -func (r *ModuleResolver) findPackage(importPath string) (*gocommand.ModuleJSON, string) { - // This can't find packages in the stdlib, but that's harmless for all - // the existing code paths. - for _, m := range r.modsByModPath { - if !strings.HasPrefix(importPath, m.Path) { - continue - } - pathInModule := importPath[len(m.Path):] - pkgDir := filepath.Join(m.Dir, pathInModule) - if r.dirIsNestedModule(pkgDir, m) { - continue - } - - if info, ok := r.cacheLoad(pkgDir); ok { - if loaded, err := info.reachedStatus(nameLoaded); loaded { - if err != nil { - continue // No package in this dir. - } - return m, pkgDir - } - if scanned, err := info.reachedStatus(directoryScanned); scanned && err != nil { - continue // Dir is unreadable, etc. - } - // This is slightly wrong: a directory doesn't have to have an - // importable package to count as a package for package-to-module - // resolution. package main or _test files should count but - // don't. - // TODO(heschi): fix this. - if _, err := r.cachePackageName(info); err == nil { - return m, pkgDir - } - } - - // Not cached. Read the filesystem. - pkgFiles, err := ioutil.ReadDir(pkgDir) - if err != nil { - continue - } - // A module only contains a package if it has buildable go - // files in that directory. If not, it could be provided by an - // outer module. See #29736. - for _, fi := range pkgFiles { - if ok, _ := r.env.matchFile(pkgDir, fi.Name()); ok { - return m, pkgDir - } - } - } - return nil, "" -} - -func (r *ModuleResolver) cacheLoad(dir string) (directoryPackageInfo, bool) { - if info, ok := r.moduleCacheCache.Load(dir); ok { - return info, ok - } - return r.otherCache.Load(dir) -} - -func (r *ModuleResolver) cacheStore(info directoryPackageInfo) { - if info.rootType == gopathwalk.RootModuleCache { - r.moduleCacheCache.Store(info.dir, info) - } else { - r.otherCache.Store(info.dir, info) - } -} - -func (r *ModuleResolver) cacheKeys() []string { - return append(r.moduleCacheCache.Keys(), r.otherCache.Keys()...) -} - -// cachePackageName caches the package name for a dir already in the cache. -func (r *ModuleResolver) cachePackageName(info directoryPackageInfo) (string, error) { - if info.rootType == gopathwalk.RootModuleCache { - return r.moduleCacheCache.CachePackageName(info) - } - return r.otherCache.CachePackageName(info) -} - -func (r *ModuleResolver) cacheExports(ctx context.Context, env *ProcessEnv, info directoryPackageInfo) (string, []string, error) { - if info.rootType == gopathwalk.RootModuleCache { - return r.moduleCacheCache.CacheExports(ctx, env, info) - } - return r.otherCache.CacheExports(ctx, env, info) -} - -// findModuleByDir returns the module that contains dir, or nil if no such -// module is in scope. -func (r *ModuleResolver) findModuleByDir(dir string) *gocommand.ModuleJSON { - // This is quite tricky and may not be correct. dir could be: - // - a package in the main module. - // - a replace target underneath the main module's directory. - // - a nested module in the above. - // - a replace target somewhere totally random. - // - a nested module in the above. - // - in the mod cache. - // - in /vendor/ in -mod=vendor mode. - // - nested module? Dunno. - // Rumor has it that replace targets cannot contain other replace targets. - for _, m := range r.modsByDir { - if !strings.HasPrefix(dir, m.Dir) { - continue - } - - if r.dirIsNestedModule(dir, m) { - continue - } - - return m - } - return nil -} - -// dirIsNestedModule reports if dir is contained in a nested module underneath -// mod, not actually in mod. -func (r *ModuleResolver) dirIsNestedModule(dir string, mod *gocommand.ModuleJSON) bool { - if !strings.HasPrefix(dir, mod.Dir) { - return false - } - if r.dirInModuleCache(dir) { - // Nested modules in the module cache are pruned, - // so it cannot be a nested module. - return false - } - if mod != nil && mod == r.dummyVendorMod { - // The /vendor pseudomodule is flattened and doesn't actually count. - return false - } - modDir, _ := r.modInfo(dir) - if modDir == "" { - return false - } - return modDir != mod.Dir -} - -func (r *ModuleResolver) modInfo(dir string) (modDir string, modName string) { - readModName := func(modFile string) string { - modBytes, err := ioutil.ReadFile(modFile) - if err != nil { - return "" - } - return modulePath(modBytes) - } - - if r.dirInModuleCache(dir) { - if matches := modCacheRegexp.FindStringSubmatch(dir); len(matches) == 3 { - index := strings.Index(dir, matches[1]+"@"+matches[2]) - modDir := filepath.Join(dir[:index], matches[1]+"@"+matches[2]) - return modDir, readModName(filepath.Join(modDir, "go.mod")) - } - } - for { - if info, ok := r.cacheLoad(dir); ok { - return info.moduleDir, info.moduleName - } - f := filepath.Join(dir, "go.mod") - info, err := os.Stat(f) - if err == nil && !info.IsDir() { - return dir, readModName(f) - } - - d := filepath.Dir(dir) - if len(d) >= len(dir) { - return "", "" // reached top of file system, no go.mod - } - dir = d - } -} - -func (r *ModuleResolver) dirInModuleCache(dir string) bool { - if r.moduleCacheDir == "" { - return false - } - return strings.HasPrefix(dir, r.moduleCacheDir) -} - -func (r *ModuleResolver) loadPackageNames(importPaths []string, srcDir string) (map[string]string, error) { - if err := r.init(); err != nil { - return nil, err - } - names := map[string]string{} - for _, path := range importPaths { - _, packageDir := r.findPackage(path) - if packageDir == "" { - continue - } - name, err := packageDirToName(packageDir) - if err != nil { - continue - } - names[path] = name - } - return names, nil -} - -func (r *ModuleResolver) scan(ctx context.Context, callback *scanCallback) error { - if err := r.init(); err != nil { - return err - } - - processDir := func(info directoryPackageInfo) { - // Skip this directory if we were not able to get the package information successfully. - if scanned, err := info.reachedStatus(directoryScanned); !scanned || err != nil { - return - } - pkg, err := r.canonicalize(info) - if err != nil { - return - } - - if !callback.dirFound(pkg) { - return - } - pkg.packageName, err = r.cachePackageName(info) - if err != nil { - return - } - - if !callback.packageNameLoaded(pkg) { - return - } - _, exports, err := r.loadExports(ctx, pkg, false) - if err != nil { - return - } - callback.exportsLoaded(pkg, exports) - } - - // Start processing everything in the cache, and listen for the new stuff - // we discover in the walk below. - stop1 := r.moduleCacheCache.ScanAndListen(ctx, processDir) - defer stop1() - stop2 := r.otherCache.ScanAndListen(ctx, processDir) - defer stop2() - - // We assume cached directories are fully cached, including all their - // children, and have not changed. We can skip them. - skip := func(root gopathwalk.Root, dir string) bool { - if r.env.SkipPathInScan != nil && root.Type == gopathwalk.RootCurrentModule { - if root.Path == dir { - return false - } - - if r.env.SkipPathInScan(filepath.Clean(dir)) { - return true - } - } - - info, ok := r.cacheLoad(dir) - if !ok { - return false - } - // This directory can be skipped as long as we have already scanned it. - // Packages with errors will continue to have errors, so there is no need - // to rescan them. - packageScanned, _ := info.reachedStatus(directoryScanned) - return packageScanned - } - - // Add anything new to the cache, and process it if we're still listening. - add := func(root gopathwalk.Root, dir string) { - r.cacheStore(r.scanDirForPackage(root, dir)) - } - - // r.roots and the callback are not necessarily safe to use in the - // goroutine below. Process them eagerly. - roots := filterRoots(r.roots, callback.rootFound) - // We can't cancel walks, because we need them to finish to have a usable - // cache. Instead, run them in a separate goroutine and detach. - scanDone := make(chan struct{}) - go func() { - select { - case <-ctx.Done(): - return - case <-r.scanSema: - } - defer func() { r.scanSema <- struct{}{} }() - // We have the lock on r.scannedRoots, and no other scans can run. - for _, root := range roots { - if ctx.Err() != nil { - return - } - - if r.scannedRoots[root] { - continue - } - gopathwalk.WalkSkip([]gopathwalk.Root{root}, add, skip, gopathwalk.Options{Logf: r.env.Logf, ModulesEnabled: true}) - r.scannedRoots[root] = true - } - close(scanDone) - }() - select { - case <-ctx.Done(): - case <-scanDone: - } - return nil -} - -func (r *ModuleResolver) scoreImportPath(ctx context.Context, path string) float64 { - if _, ok := stdlib[path]; ok { - return MaxRelevance - } - mod, _ := r.findPackage(path) - return modRelevance(mod) -} - -func modRelevance(mod *gocommand.ModuleJSON) float64 { - var relevance float64 - switch { - case mod == nil: // out of scope - return MaxRelevance - 4 - case mod.Indirect: - relevance = MaxRelevance - 3 - case !mod.Main: - relevance = MaxRelevance - 2 - default: - relevance = MaxRelevance - 1 // main module ties with stdlib - } - - _, versionString, ok := module.SplitPathVersion(mod.Path) - if ok { - index := strings.Index(versionString, "v") - if index == -1 { - return relevance - } - if versionNumber, err := strconv.ParseFloat(versionString[index+1:], 64); err == nil { - relevance += versionNumber / 1000 - } - } - - return relevance -} - -// canonicalize gets the result of canonicalizing the packages using the results -// of initializing the resolver from 'go list -m'. -func (r *ModuleResolver) canonicalize(info directoryPackageInfo) (*pkg, error) { - // Packages in GOROOT are already canonical, regardless of the std/cmd modules. - if info.rootType == gopathwalk.RootGOROOT { - return &pkg{ - importPathShort: info.nonCanonicalImportPath, - dir: info.dir, - packageName: path.Base(info.nonCanonicalImportPath), - relevance: MaxRelevance, - }, nil - } - - importPath := info.nonCanonicalImportPath - mod := r.findModuleByDir(info.dir) - // Check if the directory is underneath a module that's in scope. - if mod != nil { - // It is. If dir is the target of a replace directive, - // our guessed import path is wrong. Use the real one. - if mod.Dir == info.dir { - importPath = mod.Path - } else { - dirInMod := info.dir[len(mod.Dir)+len("/"):] - importPath = path.Join(mod.Path, filepath.ToSlash(dirInMod)) - } - } else if !strings.HasPrefix(importPath, info.moduleName) { - // The module's name doesn't match the package's import path. It - // probably needs a replace directive we don't have. - return nil, fmt.Errorf("package in %q is not valid without a replace statement", info.dir) - } - - res := &pkg{ - importPathShort: importPath, - dir: info.dir, - relevance: modRelevance(mod), - } - // We may have discovered a package that has a different version - // in scope already. Canonicalize to that one if possible. - if _, canonicalDir := r.findPackage(importPath); canonicalDir != "" { - res.dir = canonicalDir - } - return res, nil -} - -func (r *ModuleResolver) loadExports(ctx context.Context, pkg *pkg, includeTest bool) (string, []string, error) { - if err := r.init(); err != nil { - return "", nil, err - } - if info, ok := r.cacheLoad(pkg.dir); ok && !includeTest { - return r.cacheExports(ctx, r.env, info) - } - return loadExportsFromFiles(ctx, r.env, pkg.dir, includeTest) -} - -func (r *ModuleResolver) scanDirForPackage(root gopathwalk.Root, dir string) directoryPackageInfo { - subdir := "" - if dir != root.Path { - subdir = dir[len(root.Path)+len("/"):] - } - importPath := filepath.ToSlash(subdir) - if strings.HasPrefix(importPath, "vendor/") { - // Only enter vendor directories if they're explicitly requested as a root. - return directoryPackageInfo{ - status: directoryScanned, - err: fmt.Errorf("unwanted vendor directory"), - } - } - switch root.Type { - case gopathwalk.RootCurrentModule: - importPath = path.Join(r.mainByDir[root.Path].Path, filepath.ToSlash(subdir)) - case gopathwalk.RootModuleCache: - matches := modCacheRegexp.FindStringSubmatch(subdir) - if len(matches) == 0 { - return directoryPackageInfo{ - status: directoryScanned, - err: fmt.Errorf("invalid module cache path: %v", subdir), - } - } - modPath, err := module.UnescapePath(filepath.ToSlash(matches[1])) - if err != nil { - if r.env.Logf != nil { - r.env.Logf("decoding module cache path %q: %v", subdir, err) - } - return directoryPackageInfo{ - status: directoryScanned, - err: fmt.Errorf("decoding module cache path %q: %v", subdir, err), - } - } - importPath = path.Join(modPath, filepath.ToSlash(matches[3])) - } - - modDir, modName := r.modInfo(dir) - result := directoryPackageInfo{ - status: directoryScanned, - dir: dir, - rootType: root.Type, - nonCanonicalImportPath: importPath, - moduleDir: modDir, - moduleName: modName, - } - if root.Type == gopathwalk.RootGOROOT { - // stdlib packages are always in scope, despite the confusing go.mod - return result - } - return result -} - -// modCacheRegexp splits a path in a module cache into module, module version, and package. -var modCacheRegexp = regexp.MustCompile(`(.*)@([^/\\]*)(.*)`) - -var ( - slashSlash = []byte("//") - moduleStr = []byte("module") -) - -// modulePath returns the module path from the gomod file text. -// If it cannot find a module path, it returns an empty string. -// It is tolerant of unrelated problems in the go.mod file. -// -// Copied from cmd/go/internal/modfile. -func modulePath(mod []byte) string { - for len(mod) > 0 { - line := mod - mod = nil - if i := bytes.IndexByte(line, '\n'); i >= 0 { - line, mod = line[:i], line[i+1:] - } - if i := bytes.Index(line, slashSlash); i >= 0 { - line = line[:i] - } - line = bytes.TrimSpace(line) - if !bytes.HasPrefix(line, moduleStr) { - continue - } - line = line[len(moduleStr):] - n := len(line) - line = bytes.TrimSpace(line) - if len(line) == n || len(line) == 0 { - continue - } - - if line[0] == '"' || line[0] == '`' { - p, err := strconv.Unquote(string(line)) - if err != nil { - return "" // malformed quoted string or multiline module path - } - return p - } - - return string(line) - } - return "" // missing module path -} diff --git a/vendor/golang.org/x/tools/internal/imports/mod_cache.go b/vendor/golang.org/x/tools/internal/imports/mod_cache.go deleted file mode 100644 index 18dada495ca..00000000000 --- a/vendor/golang.org/x/tools/internal/imports/mod_cache.go +++ /dev/null @@ -1,236 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package imports - -import ( - "context" - "fmt" - "sync" - - "golang.org/x/tools/internal/gopathwalk" -) - -// To find packages to import, the resolver needs to know about all of the -// the packages that could be imported. This includes packages that are -// already in modules that are in (1) the current module, (2) replace targets, -// and (3) packages in the module cache. Packages in (1) and (2) may change over -// time, as the client may edit the current module and locally replaced modules. -// The module cache (which includes all of the packages in (3)) can only -// ever be added to. -// -// The resolver can thus save state about packages in the module cache -// and guarantee that this will not change over time. To obtain information -// about new modules added to the module cache, the module cache should be -// rescanned. -// -// It is OK to serve information about modules that have been deleted, -// as they do still exist. -// TODO(suzmue): can we share information with the caller about -// what module needs to be downloaded to import this package? - -type directoryPackageStatus int - -const ( - _ directoryPackageStatus = iota - directoryScanned - nameLoaded - exportsLoaded -) - -type directoryPackageInfo struct { - // status indicates the extent to which this struct has been filled in. - status directoryPackageStatus - // err is non-nil when there was an error trying to reach status. - err error - - // Set when status >= directoryScanned. - - // dir is the absolute directory of this package. - dir string - rootType gopathwalk.RootType - // nonCanonicalImportPath is the package's expected import path. It may - // not actually be importable at that path. - nonCanonicalImportPath string - - // Module-related information. - moduleDir string // The directory that is the module root of this dir. - moduleName string // The module name that contains this dir. - - // Set when status >= nameLoaded. - - packageName string // the package name, as declared in the source. - - // Set when status >= exportsLoaded. - - exports []string -} - -// reachedStatus returns true when info has a status at least target and any error associated with -// an attempt to reach target. -func (info *directoryPackageInfo) reachedStatus(target directoryPackageStatus) (bool, error) { - if info.err == nil { - return info.status >= target, nil - } - if info.status == target { - return true, info.err - } - return true, nil -} - -// dirInfoCache is a concurrency safe map for storing information about -// directories that may contain packages. -// -// The information in this cache is built incrementally. Entries are initialized in scan. -// No new keys should be added in any other functions, as all directories containing -// packages are identified in scan. -// -// Other functions, including loadExports and findPackage, may update entries in this cache -// as they discover new things about the directory. -// -// The information in the cache is not expected to change for the cache's -// lifetime, so there is no protection against competing writes. Users should -// take care not to hold the cache across changes to the underlying files. -// -// TODO(suzmue): consider other concurrency strategies and data structures (RWLocks, sync.Map, etc) -type dirInfoCache struct { - mu sync.Mutex - // dirs stores information about packages in directories, keyed by absolute path. - dirs map[string]*directoryPackageInfo - listeners map[*int]cacheListener -} - -type cacheListener func(directoryPackageInfo) - -// ScanAndListen calls listener on all the items in the cache, and on anything -// newly added. The returned stop function waits for all in-flight callbacks to -// finish and blocks new ones. -func (d *dirInfoCache) ScanAndListen(ctx context.Context, listener cacheListener) func() { - ctx, cancel := context.WithCancel(ctx) - - // Flushing out all the callbacks is tricky without knowing how many there - // are going to be. Setting an arbitrary limit makes it much easier. - const maxInFlight = 10 - sema := make(chan struct{}, maxInFlight) - for i := 0; i < maxInFlight; i++ { - sema <- struct{}{} - } - - cookie := new(int) // A unique ID we can use for the listener. - - // We can't hold mu while calling the listener. - d.mu.Lock() - var keys []string - for key := range d.dirs { - keys = append(keys, key) - } - d.listeners[cookie] = func(info directoryPackageInfo) { - select { - case <-ctx.Done(): - return - case <-sema: - } - listener(info) - sema <- struct{}{} - } - d.mu.Unlock() - - stop := func() { - cancel() - d.mu.Lock() - delete(d.listeners, cookie) - d.mu.Unlock() - for i := 0; i < maxInFlight; i++ { - <-sema - } - } - - // Process the pre-existing keys. - for _, k := range keys { - select { - case <-ctx.Done(): - return stop - default: - } - if v, ok := d.Load(k); ok { - listener(v) - } - } - - return stop -} - -// Store stores the package info for dir. -func (d *dirInfoCache) Store(dir string, info directoryPackageInfo) { - d.mu.Lock() - _, old := d.dirs[dir] - d.dirs[dir] = &info - var listeners []cacheListener - for _, l := range d.listeners { - listeners = append(listeners, l) - } - d.mu.Unlock() - - if !old { - for _, l := range listeners { - l(info) - } - } -} - -// Load returns a copy of the directoryPackageInfo for absolute directory dir. -func (d *dirInfoCache) Load(dir string) (directoryPackageInfo, bool) { - d.mu.Lock() - defer d.mu.Unlock() - info, ok := d.dirs[dir] - if !ok { - return directoryPackageInfo{}, false - } - return *info, true -} - -// Keys returns the keys currently present in d. -func (d *dirInfoCache) Keys() (keys []string) { - d.mu.Lock() - defer d.mu.Unlock() - for key := range d.dirs { - keys = append(keys, key) - } - return keys -} - -func (d *dirInfoCache) CachePackageName(info directoryPackageInfo) (string, error) { - if loaded, err := info.reachedStatus(nameLoaded); loaded { - return info.packageName, err - } - if scanned, err := info.reachedStatus(directoryScanned); !scanned || err != nil { - return "", fmt.Errorf("cannot read package name, scan error: %v", err) - } - info.packageName, info.err = packageDirToName(info.dir) - info.status = nameLoaded - d.Store(info.dir, info) - return info.packageName, info.err -} - -func (d *dirInfoCache) CacheExports(ctx context.Context, env *ProcessEnv, info directoryPackageInfo) (string, []string, error) { - if reached, _ := info.reachedStatus(exportsLoaded); reached { - return info.packageName, info.exports, info.err - } - if reached, err := info.reachedStatus(nameLoaded); reached && err != nil { - return "", nil, err - } - info.packageName, info.exports, info.err = loadExportsFromFiles(ctx, env, info.dir, false) - if info.err == context.Canceled || info.err == context.DeadlineExceeded { - return info.packageName, info.exports, info.err - } - // The cache structure wants things to proceed linearly. We can skip a - // step here, but only if we succeed. - if info.status == nameLoaded || info.err == nil { - info.status = exportsLoaded - } else { - info.status = nameLoaded - } - d.Store(info.dir, info) - return info.packageName, info.exports, info.err -} diff --git a/vendor/golang.org/x/tools/internal/imports/sortimports.go b/vendor/golang.org/x/tools/internal/imports/sortimports.go deleted file mode 100644 index 1a0a7ebd9e4..00000000000 --- a/vendor/golang.org/x/tools/internal/imports/sortimports.go +++ /dev/null @@ -1,297 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Hacked up copy of go/ast/import.go -// Modified to use a single token.File in preference to a FileSet. - -package imports - -import ( - "go/ast" - "go/token" - "log" - "sort" - "strconv" -) - -// sortImports sorts runs of consecutive import lines in import blocks in f. -// It also removes duplicate imports when it is possible to do so without data loss. -// -// It may mutate the token.File. -func sortImports(localPrefix string, tokFile *token.File, f *ast.File) { - for i, d := range f.Decls { - d, ok := d.(*ast.GenDecl) - if !ok || d.Tok != token.IMPORT { - // Not an import declaration, so we're done. - // Imports are always first. - break - } - - if len(d.Specs) == 0 { - // Empty import block, remove it. - f.Decls = append(f.Decls[:i], f.Decls[i+1:]...) - } - - if !d.Lparen.IsValid() { - // Not a block: sorted by default. - continue - } - - // Identify and sort runs of specs on successive lines. - i := 0 - specs := d.Specs[:0] - for j, s := range d.Specs { - if j > i && tokFile.Line(s.Pos()) > 1+tokFile.Line(d.Specs[j-1].End()) { - // j begins a new run. End this one. - specs = append(specs, sortSpecs(localPrefix, tokFile, f, d.Specs[i:j])...) - i = j - } - } - specs = append(specs, sortSpecs(localPrefix, tokFile, f, d.Specs[i:])...) - d.Specs = specs - - // Deduping can leave a blank line before the rparen; clean that up. - // Ignore line directives. - if len(d.Specs) > 0 { - lastSpec := d.Specs[len(d.Specs)-1] - lastLine := tokFile.PositionFor(lastSpec.Pos(), false).Line - if rParenLine := tokFile.PositionFor(d.Rparen, false).Line; rParenLine > lastLine+1 { - tokFile.MergeLine(rParenLine - 1) // has side effects! - } - } - } -} - -// mergeImports merges all the import declarations into the first one. -// Taken from golang.org/x/tools/ast/astutil. -// This does not adjust line numbers properly -func mergeImports(f *ast.File) { - if len(f.Decls) <= 1 { - return - } - - // Merge all the import declarations into the first one. - var first *ast.GenDecl - for i := 0; i < len(f.Decls); i++ { - decl := f.Decls[i] - gen, ok := decl.(*ast.GenDecl) - if !ok || gen.Tok != token.IMPORT || declImports(gen, "C") { - continue - } - if first == nil { - first = gen - continue // Don't touch the first one. - } - // We now know there is more than one package in this import - // declaration. Ensure that it ends up parenthesized. - first.Lparen = first.Pos() - // Move the imports of the other import declaration to the first one. - for _, spec := range gen.Specs { - spec.(*ast.ImportSpec).Path.ValuePos = first.Pos() - first.Specs = append(first.Specs, spec) - } - f.Decls = append(f.Decls[:i], f.Decls[i+1:]...) - i-- - } -} - -// declImports reports whether gen contains an import of path. -// Taken from golang.org/x/tools/ast/astutil. -func declImports(gen *ast.GenDecl, path string) bool { - if gen.Tok != token.IMPORT { - return false - } - for _, spec := range gen.Specs { - impspec := spec.(*ast.ImportSpec) - if importPath(impspec) == path { - return true - } - } - return false -} - -func importPath(s ast.Spec) string { - t, err := strconv.Unquote(s.(*ast.ImportSpec).Path.Value) - if err == nil { - return t - } - return "" -} - -func importName(s ast.Spec) string { - n := s.(*ast.ImportSpec).Name - if n == nil { - return "" - } - return n.Name -} - -func importComment(s ast.Spec) string { - c := s.(*ast.ImportSpec).Comment - if c == nil { - return "" - } - return c.Text() -} - -// collapse indicates whether prev may be removed, leaving only next. -func collapse(prev, next ast.Spec) bool { - if importPath(next) != importPath(prev) || importName(next) != importName(prev) { - return false - } - return prev.(*ast.ImportSpec).Comment == nil -} - -type posSpan struct { - Start token.Pos - End token.Pos -} - -// sortSpecs sorts the import specs within each import decl. -// It may mutate the token.File. -func sortSpecs(localPrefix string, tokFile *token.File, f *ast.File, specs []ast.Spec) []ast.Spec { - // Can't short-circuit here even if specs are already sorted, - // since they might yet need deduplication. - // A lone import, however, may be safely ignored. - if len(specs) <= 1 { - return specs - } - - // Record positions for specs. - pos := make([]posSpan, len(specs)) - for i, s := range specs { - pos[i] = posSpan{s.Pos(), s.End()} - } - - // Identify comments in this range. - // Any comment from pos[0].Start to the final line counts. - lastLine := tokFile.Line(pos[len(pos)-1].End) - cstart := len(f.Comments) - cend := len(f.Comments) - for i, g := range f.Comments { - if g.Pos() < pos[0].Start { - continue - } - if i < cstart { - cstart = i - } - if tokFile.Line(g.End()) > lastLine { - cend = i - break - } - } - comments := f.Comments[cstart:cend] - - // Assign each comment to the import spec preceding it. - importComment := map[*ast.ImportSpec][]*ast.CommentGroup{} - specIndex := 0 - for _, g := range comments { - for specIndex+1 < len(specs) && pos[specIndex+1].Start <= g.Pos() { - specIndex++ - } - s := specs[specIndex].(*ast.ImportSpec) - importComment[s] = append(importComment[s], g) - } - - // Sort the import specs by import path. - // Remove duplicates, when possible without data loss. - // Reassign the import paths to have the same position sequence. - // Reassign each comment to abut the end of its spec. - // Sort the comments by new position. - sort.Sort(byImportSpec{localPrefix, specs}) - - // Dedup. Thanks to our sorting, we can just consider - // adjacent pairs of imports. - deduped := specs[:0] - for i, s := range specs { - if i == len(specs)-1 || !collapse(s, specs[i+1]) { - deduped = append(deduped, s) - } else { - p := s.Pos() - tokFile.MergeLine(tokFile.Line(p)) // has side effects! - } - } - specs = deduped - - // Fix up comment positions - for i, s := range specs { - s := s.(*ast.ImportSpec) - if s.Name != nil { - s.Name.NamePos = pos[i].Start - } - s.Path.ValuePos = pos[i].Start - s.EndPos = pos[i].End - nextSpecPos := pos[i].End - - for _, g := range importComment[s] { - for _, c := range g.List { - c.Slash = pos[i].End - nextSpecPos = c.End() - } - } - if i < len(specs)-1 { - pos[i+1].Start = nextSpecPos - pos[i+1].End = nextSpecPos - } - } - - sort.Sort(byCommentPos(comments)) - - // Fixup comments can insert blank lines, because import specs are on different lines. - // We remove those blank lines here by merging import spec to the first import spec line. - firstSpecLine := tokFile.Line(specs[0].Pos()) - for _, s := range specs[1:] { - p := s.Pos() - line := tokFile.Line(p) - for previousLine := line - 1; previousLine >= firstSpecLine; { - // MergeLine can panic. Avoid the panic at the cost of not removing the blank line - // golang/go#50329 - if previousLine > 0 && previousLine < tokFile.LineCount() { - tokFile.MergeLine(previousLine) // has side effects! - previousLine-- - } else { - // try to gather some data to diagnose how this could happen - req := "Please report what the imports section of your go file looked like." - log.Printf("panic avoided: first:%d line:%d previous:%d max:%d. %s", - firstSpecLine, line, previousLine, tokFile.LineCount(), req) - } - } - } - return specs -} - -type byImportSpec struct { - localPrefix string - specs []ast.Spec // slice of *ast.ImportSpec -} - -func (x byImportSpec) Len() int { return len(x.specs) } -func (x byImportSpec) Swap(i, j int) { x.specs[i], x.specs[j] = x.specs[j], x.specs[i] } -func (x byImportSpec) Less(i, j int) bool { - ipath := importPath(x.specs[i]) - jpath := importPath(x.specs[j]) - - igroup := importGroup(x.localPrefix, ipath) - jgroup := importGroup(x.localPrefix, jpath) - if igroup != jgroup { - return igroup < jgroup - } - - if ipath != jpath { - return ipath < jpath - } - iname := importName(x.specs[i]) - jname := importName(x.specs[j]) - - if iname != jname { - return iname < jname - } - return importComment(x.specs[i]) < importComment(x.specs[j]) -} - -type byCommentPos []*ast.CommentGroup - -func (x byCommentPos) Len() int { return len(x) } -func (x byCommentPos) Swap(i, j int) { x[i], x[j] = x[j], x[i] } -func (x byCommentPos) Less(i, j int) bool { return x[i].Pos() < x[j].Pos() } diff --git a/vendor/golang.org/x/tools/internal/imports/zstdlib.go b/vendor/golang.org/x/tools/internal/imports/zstdlib.go deleted file mode 100644 index 31a75949cdc..00000000000 --- a/vendor/golang.org/x/tools/internal/imports/zstdlib.go +++ /dev/null @@ -1,11115 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Code generated by mkstdlib.go. DO NOT EDIT. - -package imports - -var stdlib = map[string][]string{ - "archive/tar": { - "ErrFieldTooLong", - "ErrHeader", - "ErrInsecurePath", - "ErrWriteAfterClose", - "ErrWriteTooLong", - "FileInfoHeader", - "Format", - "FormatGNU", - "FormatPAX", - "FormatUSTAR", - "FormatUnknown", - "Header", - "NewReader", - "NewWriter", - "Reader", - "TypeBlock", - "TypeChar", - "TypeCont", - "TypeDir", - "TypeFifo", - "TypeGNULongLink", - "TypeGNULongName", - "TypeGNUSparse", - "TypeLink", - "TypeReg", - "TypeRegA", - "TypeSymlink", - "TypeXGlobalHeader", - "TypeXHeader", - "Writer", - }, - "archive/zip": { - "Compressor", - "Decompressor", - "Deflate", - "ErrAlgorithm", - "ErrChecksum", - "ErrFormat", - "ErrInsecurePath", - "File", - "FileHeader", - "FileInfoHeader", - "NewReader", - "NewWriter", - "OpenReader", - "ReadCloser", - "Reader", - "RegisterCompressor", - "RegisterDecompressor", - "Store", - "Writer", - }, - "bufio": { - "ErrAdvanceTooFar", - "ErrBadReadCount", - "ErrBufferFull", - "ErrFinalToken", - "ErrInvalidUnreadByte", - "ErrInvalidUnreadRune", - "ErrNegativeAdvance", - "ErrNegativeCount", - "ErrTooLong", - "MaxScanTokenSize", - "NewReadWriter", - "NewReader", - "NewReaderSize", - "NewScanner", - "NewWriter", - "NewWriterSize", - "ReadWriter", - "Reader", - "ScanBytes", - "ScanLines", - "ScanRunes", - "ScanWords", - "Scanner", - "SplitFunc", - "Writer", - }, - "bytes": { - "Buffer", - "Clone", - "Compare", - "Contains", - "ContainsAny", - "ContainsRune", - "Count", - "Cut", - "CutPrefix", - "CutSuffix", - "Equal", - "EqualFold", - "ErrTooLarge", - "Fields", - "FieldsFunc", - "HasPrefix", - "HasSuffix", - "Index", - "IndexAny", - "IndexByte", - "IndexFunc", - "IndexRune", - "Join", - "LastIndex", - "LastIndexAny", - "LastIndexByte", - "LastIndexFunc", - "Map", - "MinRead", - "NewBuffer", - "NewBufferString", - "NewReader", - "Reader", - "Repeat", - "Replace", - "ReplaceAll", - "Runes", - "Split", - "SplitAfter", - "SplitAfterN", - "SplitN", - "Title", - "ToLower", - "ToLowerSpecial", - "ToTitle", - "ToTitleSpecial", - "ToUpper", - "ToUpperSpecial", - "ToValidUTF8", - "Trim", - "TrimFunc", - "TrimLeft", - "TrimLeftFunc", - "TrimPrefix", - "TrimRight", - "TrimRightFunc", - "TrimSpace", - "TrimSuffix", - }, - "compress/bzip2": { - "NewReader", - "StructuralError", - }, - "compress/flate": { - "BestCompression", - "BestSpeed", - "CorruptInputError", - "DefaultCompression", - "HuffmanOnly", - "InternalError", - "NewReader", - "NewReaderDict", - "NewWriter", - "NewWriterDict", - "NoCompression", - "ReadError", - "Reader", - "Resetter", - "WriteError", - "Writer", - }, - "compress/gzip": { - "BestCompression", - "BestSpeed", - "DefaultCompression", - "ErrChecksum", - "ErrHeader", - "Header", - "HuffmanOnly", - "NewReader", - "NewWriter", - "NewWriterLevel", - "NoCompression", - "Reader", - "Writer", - }, - "compress/lzw": { - "LSB", - "MSB", - "NewReader", - "NewWriter", - "Order", - "Reader", - "Writer", - }, - "compress/zlib": { - "BestCompression", - "BestSpeed", - "DefaultCompression", - "ErrChecksum", - "ErrDictionary", - "ErrHeader", - "HuffmanOnly", - "NewReader", - "NewReaderDict", - "NewWriter", - "NewWriterLevel", - "NewWriterLevelDict", - "NoCompression", - "Resetter", - "Writer", - }, - "container/heap": { - "Fix", - "Init", - "Interface", - "Pop", - "Push", - "Remove", - }, - "container/list": { - "Element", - "List", - "New", - }, - "container/ring": { - "New", - "Ring", - }, - "context": { - "Background", - "CancelCauseFunc", - "CancelFunc", - "Canceled", - "Cause", - "Context", - "DeadlineExceeded", - "TODO", - "WithCancel", - "WithCancelCause", - "WithDeadline", - "WithTimeout", - "WithValue", - }, - "crypto": { - "BLAKE2b_256", - "BLAKE2b_384", - "BLAKE2b_512", - "BLAKE2s_256", - "Decrypter", - "DecrypterOpts", - "Hash", - "MD4", - "MD5", - "MD5SHA1", - "PrivateKey", - "PublicKey", - "RIPEMD160", - "RegisterHash", - "SHA1", - "SHA224", - "SHA256", - "SHA384", - "SHA3_224", - "SHA3_256", - "SHA3_384", - "SHA3_512", - "SHA512", - "SHA512_224", - "SHA512_256", - "Signer", - "SignerOpts", - }, - "crypto/aes": { - "BlockSize", - "KeySizeError", - "NewCipher", - }, - "crypto/cipher": { - "AEAD", - "Block", - "BlockMode", - "NewCBCDecrypter", - "NewCBCEncrypter", - "NewCFBDecrypter", - "NewCFBEncrypter", - "NewCTR", - "NewGCM", - "NewGCMWithNonceSize", - "NewGCMWithTagSize", - "NewOFB", - "Stream", - "StreamReader", - "StreamWriter", - }, - "crypto/des": { - "BlockSize", - "KeySizeError", - "NewCipher", - "NewTripleDESCipher", - }, - "crypto/dsa": { - "ErrInvalidPublicKey", - "GenerateKey", - "GenerateParameters", - "L1024N160", - "L2048N224", - "L2048N256", - "L3072N256", - "ParameterSizes", - "Parameters", - "PrivateKey", - "PublicKey", - "Sign", - "Verify", - }, - "crypto/ecdh": { - "Curve", - "P256", - "P384", - "P521", - "PrivateKey", - "PublicKey", - "X25519", - }, - "crypto/ecdsa": { - "GenerateKey", - "PrivateKey", - "PublicKey", - "Sign", - "SignASN1", - "Verify", - "VerifyASN1", - }, - "crypto/ed25519": { - "GenerateKey", - "NewKeyFromSeed", - "Options", - "PrivateKey", - "PrivateKeySize", - "PublicKey", - "PublicKeySize", - "SeedSize", - "Sign", - "SignatureSize", - "Verify", - "VerifyWithOptions", - }, - "crypto/elliptic": { - "Curve", - "CurveParams", - "GenerateKey", - "Marshal", - "MarshalCompressed", - "P224", - "P256", - "P384", - "P521", - "Unmarshal", - "UnmarshalCompressed", - }, - "crypto/hmac": { - "Equal", - "New", - }, - "crypto/md5": { - "BlockSize", - "New", - "Size", - "Sum", - }, - "crypto/rand": { - "Int", - "Prime", - "Read", - "Reader", - }, - "crypto/rc4": { - "Cipher", - "KeySizeError", - "NewCipher", - }, - "crypto/rsa": { - "CRTValue", - "DecryptOAEP", - "DecryptPKCS1v15", - "DecryptPKCS1v15SessionKey", - "EncryptOAEP", - "EncryptPKCS1v15", - "ErrDecryption", - "ErrMessageTooLong", - "ErrVerification", - "GenerateKey", - "GenerateMultiPrimeKey", - "OAEPOptions", - "PKCS1v15DecryptOptions", - "PSSOptions", - "PSSSaltLengthAuto", - "PSSSaltLengthEqualsHash", - "PrecomputedValues", - "PrivateKey", - "PublicKey", - "SignPKCS1v15", - "SignPSS", - "VerifyPKCS1v15", - "VerifyPSS", - }, - "crypto/sha1": { - "BlockSize", - "New", - "Size", - "Sum", - }, - "crypto/sha256": { - "BlockSize", - "New", - "New224", - "Size", - "Size224", - "Sum224", - "Sum256", - }, - "crypto/sha512": { - "BlockSize", - "New", - "New384", - "New512_224", - "New512_256", - "Size", - "Size224", - "Size256", - "Size384", - "Sum384", - "Sum512", - "Sum512_224", - "Sum512_256", - }, - "crypto/subtle": { - "ConstantTimeByteEq", - "ConstantTimeCompare", - "ConstantTimeCopy", - "ConstantTimeEq", - "ConstantTimeLessOrEq", - "ConstantTimeSelect", - "XORBytes", - }, - "crypto/tls": { - "Certificate", - "CertificateRequestInfo", - "CertificateVerificationError", - "CipherSuite", - "CipherSuiteName", - "CipherSuites", - "Client", - "ClientAuthType", - "ClientHelloInfo", - "ClientSessionCache", - "ClientSessionState", - "Config", - "Conn", - "ConnectionState", - "CurveID", - "CurveP256", - "CurveP384", - "CurveP521", - "Dial", - "DialWithDialer", - "Dialer", - "ECDSAWithP256AndSHA256", - "ECDSAWithP384AndSHA384", - "ECDSAWithP521AndSHA512", - "ECDSAWithSHA1", - "Ed25519", - "InsecureCipherSuites", - "Listen", - "LoadX509KeyPair", - "NewLRUClientSessionCache", - "NewListener", - "NoClientCert", - "PKCS1WithSHA1", - "PKCS1WithSHA256", - "PKCS1WithSHA384", - "PKCS1WithSHA512", - "PSSWithSHA256", - "PSSWithSHA384", - "PSSWithSHA512", - "RecordHeaderError", - "RenegotiateFreelyAsClient", - "RenegotiateNever", - "RenegotiateOnceAsClient", - "RenegotiationSupport", - "RequestClientCert", - "RequireAndVerifyClientCert", - "RequireAnyClientCert", - "Server", - "SignatureScheme", - "TLS_AES_128_GCM_SHA256", - "TLS_AES_256_GCM_SHA384", - "TLS_CHACHA20_POLY1305_SHA256", - "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", - "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", - "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", - "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", - "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", - "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", - "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", - "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", - "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", - "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", - "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", - "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", - "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", - "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", - "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", - "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", - "TLS_ECDHE_RSA_WITH_RC4_128_SHA", - "TLS_FALLBACK_SCSV", - "TLS_RSA_WITH_3DES_EDE_CBC_SHA", - "TLS_RSA_WITH_AES_128_CBC_SHA", - "TLS_RSA_WITH_AES_128_CBC_SHA256", - "TLS_RSA_WITH_AES_128_GCM_SHA256", - "TLS_RSA_WITH_AES_256_CBC_SHA", - "TLS_RSA_WITH_AES_256_GCM_SHA384", - "TLS_RSA_WITH_RC4_128_SHA", - "VerifyClientCertIfGiven", - "VersionSSL30", - "VersionTLS10", - "VersionTLS11", - "VersionTLS12", - "VersionTLS13", - "X25519", - "X509KeyPair", - }, - "crypto/x509": { - "CANotAuthorizedForExtKeyUsage", - "CANotAuthorizedForThisName", - "CertPool", - "Certificate", - "CertificateInvalidError", - "CertificateRequest", - "ConstraintViolationError", - "CreateCertificate", - "CreateCertificateRequest", - "CreateRevocationList", - "DSA", - "DSAWithSHA1", - "DSAWithSHA256", - "DecryptPEMBlock", - "ECDSA", - "ECDSAWithSHA1", - "ECDSAWithSHA256", - "ECDSAWithSHA384", - "ECDSAWithSHA512", - "Ed25519", - "EncryptPEMBlock", - "ErrUnsupportedAlgorithm", - "Expired", - "ExtKeyUsage", - "ExtKeyUsageAny", - "ExtKeyUsageClientAuth", - "ExtKeyUsageCodeSigning", - "ExtKeyUsageEmailProtection", - "ExtKeyUsageIPSECEndSystem", - "ExtKeyUsageIPSECTunnel", - "ExtKeyUsageIPSECUser", - "ExtKeyUsageMicrosoftCommercialCodeSigning", - "ExtKeyUsageMicrosoftKernelCodeSigning", - "ExtKeyUsageMicrosoftServerGatedCrypto", - "ExtKeyUsageNetscapeServerGatedCrypto", - "ExtKeyUsageOCSPSigning", - "ExtKeyUsageServerAuth", - "ExtKeyUsageTimeStamping", - "HostnameError", - "IncompatibleUsage", - "IncorrectPasswordError", - "InsecureAlgorithmError", - "InvalidReason", - "IsEncryptedPEMBlock", - "KeyUsage", - "KeyUsageCRLSign", - "KeyUsageCertSign", - "KeyUsageContentCommitment", - "KeyUsageDataEncipherment", - "KeyUsageDecipherOnly", - "KeyUsageDigitalSignature", - "KeyUsageEncipherOnly", - "KeyUsageKeyAgreement", - "KeyUsageKeyEncipherment", - "MD2WithRSA", - "MD5WithRSA", - "MarshalECPrivateKey", - "MarshalPKCS1PrivateKey", - "MarshalPKCS1PublicKey", - "MarshalPKCS8PrivateKey", - "MarshalPKIXPublicKey", - "NameConstraintsWithoutSANs", - "NameMismatch", - "NewCertPool", - "NotAuthorizedToSign", - "PEMCipher", - "PEMCipher3DES", - "PEMCipherAES128", - "PEMCipherAES192", - "PEMCipherAES256", - "PEMCipherDES", - "ParseCRL", - "ParseCertificate", - "ParseCertificateRequest", - "ParseCertificates", - "ParseDERCRL", - "ParseECPrivateKey", - "ParsePKCS1PrivateKey", - "ParsePKCS1PublicKey", - "ParsePKCS8PrivateKey", - "ParsePKIXPublicKey", - "ParseRevocationList", - "PublicKeyAlgorithm", - "PureEd25519", - "RSA", - "RevocationList", - "SHA1WithRSA", - "SHA256WithRSA", - "SHA256WithRSAPSS", - "SHA384WithRSA", - "SHA384WithRSAPSS", - "SHA512WithRSA", - "SHA512WithRSAPSS", - "SetFallbackRoots", - "SignatureAlgorithm", - "SystemCertPool", - "SystemRootsError", - "TooManyConstraints", - "TooManyIntermediates", - "UnconstrainedName", - "UnhandledCriticalExtension", - "UnknownAuthorityError", - "UnknownPublicKeyAlgorithm", - "UnknownSignatureAlgorithm", - "VerifyOptions", - }, - "crypto/x509/pkix": { - "AlgorithmIdentifier", - "AttributeTypeAndValue", - "AttributeTypeAndValueSET", - "CertificateList", - "Extension", - "Name", - "RDNSequence", - "RelativeDistinguishedNameSET", - "RevokedCertificate", - "TBSCertificateList", - }, - "database/sql": { - "ColumnType", - "Conn", - "DB", - "DBStats", - "Drivers", - "ErrConnDone", - "ErrNoRows", - "ErrTxDone", - "IsolationLevel", - "LevelDefault", - "LevelLinearizable", - "LevelReadCommitted", - "LevelReadUncommitted", - "LevelRepeatableRead", - "LevelSerializable", - "LevelSnapshot", - "LevelWriteCommitted", - "Named", - "NamedArg", - "NullBool", - "NullByte", - "NullFloat64", - "NullInt16", - "NullInt32", - "NullInt64", - "NullString", - "NullTime", - "Open", - "OpenDB", - "Out", - "RawBytes", - "Register", - "Result", - "Row", - "Rows", - "Scanner", - "Stmt", - "Tx", - "TxOptions", - }, - "database/sql/driver": { - "Bool", - "ColumnConverter", - "Conn", - "ConnBeginTx", - "ConnPrepareContext", - "Connector", - "DefaultParameterConverter", - "Driver", - "DriverContext", - "ErrBadConn", - "ErrRemoveArgument", - "ErrSkip", - "Execer", - "ExecerContext", - "Int32", - "IsScanValue", - "IsValue", - "IsolationLevel", - "NamedValue", - "NamedValueChecker", - "NotNull", - "Null", - "Pinger", - "Queryer", - "QueryerContext", - "Result", - "ResultNoRows", - "Rows", - "RowsAffected", - "RowsColumnTypeDatabaseTypeName", - "RowsColumnTypeLength", - "RowsColumnTypeNullable", - "RowsColumnTypePrecisionScale", - "RowsColumnTypeScanType", - "RowsNextResultSet", - "SessionResetter", - "Stmt", - "StmtExecContext", - "StmtQueryContext", - "String", - "Tx", - "TxOptions", - "Validator", - "Value", - "ValueConverter", - "Valuer", - }, - "debug/buildinfo": { - "BuildInfo", - "Read", - "ReadFile", - }, - "debug/dwarf": { - "AddrType", - "ArrayType", - "Attr", - "AttrAbstractOrigin", - "AttrAccessibility", - "AttrAddrBase", - "AttrAddrClass", - "AttrAlignment", - "AttrAllocated", - "AttrArtificial", - "AttrAssociated", - "AttrBaseTypes", - "AttrBinaryScale", - "AttrBitOffset", - "AttrBitSize", - "AttrByteSize", - "AttrCallAllCalls", - "AttrCallAllSourceCalls", - "AttrCallAllTailCalls", - "AttrCallColumn", - "AttrCallDataLocation", - "AttrCallDataValue", - "AttrCallFile", - "AttrCallLine", - "AttrCallOrigin", - "AttrCallPC", - "AttrCallParameter", - "AttrCallReturnPC", - "AttrCallTailCall", - "AttrCallTarget", - "AttrCallTargetClobbered", - "AttrCallValue", - "AttrCalling", - "AttrCommonRef", - "AttrCompDir", - "AttrConstExpr", - "AttrConstValue", - "AttrContainingType", - "AttrCount", - "AttrDataBitOffset", - "AttrDataLocation", - "AttrDataMemberLoc", - "AttrDecimalScale", - "AttrDecimalSign", - "AttrDeclColumn", - "AttrDeclFile", - "AttrDeclLine", - "AttrDeclaration", - "AttrDefaultValue", - "AttrDefaulted", - "AttrDeleted", - "AttrDescription", - "AttrDigitCount", - "AttrDiscr", - "AttrDiscrList", - "AttrDiscrValue", - "AttrDwoName", - "AttrElemental", - "AttrEncoding", - "AttrEndianity", - "AttrEntrypc", - "AttrEnumClass", - "AttrExplicit", - "AttrExportSymbols", - "AttrExtension", - "AttrExternal", - "AttrFrameBase", - "AttrFriend", - "AttrHighpc", - "AttrIdentifierCase", - "AttrImport", - "AttrInline", - "AttrIsOptional", - "AttrLanguage", - "AttrLinkageName", - "AttrLocation", - "AttrLoclistsBase", - "AttrLowerBound", - "AttrLowpc", - "AttrMacroInfo", - "AttrMacros", - "AttrMainSubprogram", - "AttrMutable", - "AttrName", - "AttrNamelistItem", - "AttrNoreturn", - "AttrObjectPointer", - "AttrOrdering", - "AttrPictureString", - "AttrPriority", - "AttrProducer", - "AttrPrototyped", - "AttrPure", - "AttrRanges", - "AttrRank", - "AttrRecursive", - "AttrReference", - "AttrReturnAddr", - "AttrRnglistsBase", - "AttrRvalueReference", - "AttrSegment", - "AttrSibling", - "AttrSignature", - "AttrSmall", - "AttrSpecification", - "AttrStartScope", - "AttrStaticLink", - "AttrStmtList", - "AttrStrOffsetsBase", - "AttrStride", - "AttrStrideSize", - "AttrStringLength", - "AttrStringLengthBitSize", - "AttrStringLengthByteSize", - "AttrThreadsScaled", - "AttrTrampoline", - "AttrType", - "AttrUpperBound", - "AttrUseLocation", - "AttrUseUTF8", - "AttrVarParam", - "AttrVirtuality", - "AttrVisibility", - "AttrVtableElemLoc", - "BasicType", - "BoolType", - "CharType", - "Class", - "ClassAddrPtr", - "ClassAddress", - "ClassBlock", - "ClassConstant", - "ClassExprLoc", - "ClassFlag", - "ClassLinePtr", - "ClassLocList", - "ClassLocListPtr", - "ClassMacPtr", - "ClassRangeListPtr", - "ClassReference", - "ClassReferenceAlt", - "ClassReferenceSig", - "ClassRngList", - "ClassRngListsPtr", - "ClassStrOffsetsPtr", - "ClassString", - "ClassStringAlt", - "ClassUnknown", - "CommonType", - "ComplexType", - "Data", - "DecodeError", - "DotDotDotType", - "Entry", - "EnumType", - "EnumValue", - "ErrUnknownPC", - "Field", - "FloatType", - "FuncType", - "IntType", - "LineEntry", - "LineFile", - "LineReader", - "LineReaderPos", - "New", - "Offset", - "PtrType", - "QualType", - "Reader", - "StructField", - "StructType", - "Tag", - "TagAccessDeclaration", - "TagArrayType", - "TagAtomicType", - "TagBaseType", - "TagCallSite", - "TagCallSiteParameter", - "TagCatchDwarfBlock", - "TagClassType", - "TagCoarrayType", - "TagCommonDwarfBlock", - "TagCommonInclusion", - "TagCompileUnit", - "TagCondition", - "TagConstType", - "TagConstant", - "TagDwarfProcedure", - "TagDynamicType", - "TagEntryPoint", - "TagEnumerationType", - "TagEnumerator", - "TagFileType", - "TagFormalParameter", - "TagFriend", - "TagGenericSubrange", - "TagImmutableType", - "TagImportedDeclaration", - "TagImportedModule", - "TagImportedUnit", - "TagInheritance", - "TagInlinedSubroutine", - "TagInterfaceType", - "TagLabel", - "TagLexDwarfBlock", - "TagMember", - "TagModule", - "TagMutableType", - "TagNamelist", - "TagNamelistItem", - "TagNamespace", - "TagPackedType", - "TagPartialUnit", - "TagPointerType", - "TagPtrToMemberType", - "TagReferenceType", - "TagRestrictType", - "TagRvalueReferenceType", - "TagSetType", - "TagSharedType", - "TagSkeletonUnit", - "TagStringType", - "TagStructType", - "TagSubprogram", - "TagSubrangeType", - "TagSubroutineType", - "TagTemplateAlias", - "TagTemplateTypeParameter", - "TagTemplateValueParameter", - "TagThrownType", - "TagTryDwarfBlock", - "TagTypeUnit", - "TagTypedef", - "TagUnionType", - "TagUnspecifiedParameters", - "TagUnspecifiedType", - "TagVariable", - "TagVariant", - "TagVariantPart", - "TagVolatileType", - "TagWithStmt", - "Type", - "TypedefType", - "UcharType", - "UintType", - "UnspecifiedType", - "UnsupportedType", - "VoidType", - }, - "debug/elf": { - "ARM_MAGIC_TRAMP_NUMBER", - "COMPRESS_HIOS", - "COMPRESS_HIPROC", - "COMPRESS_LOOS", - "COMPRESS_LOPROC", - "COMPRESS_ZLIB", - "Chdr32", - "Chdr64", - "Class", - "CompressionType", - "DF_BIND_NOW", - "DF_ORIGIN", - "DF_STATIC_TLS", - "DF_SYMBOLIC", - "DF_TEXTREL", - "DT_ADDRRNGHI", - "DT_ADDRRNGLO", - "DT_AUDIT", - "DT_AUXILIARY", - "DT_BIND_NOW", - "DT_CHECKSUM", - "DT_CONFIG", - "DT_DEBUG", - "DT_DEPAUDIT", - "DT_ENCODING", - "DT_FEATURE", - "DT_FILTER", - "DT_FINI", - "DT_FINI_ARRAY", - "DT_FINI_ARRAYSZ", - "DT_FLAGS", - "DT_FLAGS_1", - "DT_GNU_CONFLICT", - "DT_GNU_CONFLICTSZ", - "DT_GNU_HASH", - "DT_GNU_LIBLIST", - "DT_GNU_LIBLISTSZ", - "DT_GNU_PRELINKED", - "DT_HASH", - "DT_HIOS", - "DT_HIPROC", - "DT_INIT", - "DT_INIT_ARRAY", - "DT_INIT_ARRAYSZ", - "DT_JMPREL", - "DT_LOOS", - "DT_LOPROC", - "DT_MIPS_AUX_DYNAMIC", - "DT_MIPS_BASE_ADDRESS", - "DT_MIPS_COMPACT_SIZE", - "DT_MIPS_CONFLICT", - "DT_MIPS_CONFLICTNO", - "DT_MIPS_CXX_FLAGS", - "DT_MIPS_DELTA_CLASS", - "DT_MIPS_DELTA_CLASSSYM", - "DT_MIPS_DELTA_CLASSSYM_NO", - "DT_MIPS_DELTA_CLASS_NO", - "DT_MIPS_DELTA_INSTANCE", - "DT_MIPS_DELTA_INSTANCE_NO", - "DT_MIPS_DELTA_RELOC", - "DT_MIPS_DELTA_RELOC_NO", - "DT_MIPS_DELTA_SYM", - "DT_MIPS_DELTA_SYM_NO", - "DT_MIPS_DYNSTR_ALIGN", - "DT_MIPS_FLAGS", - "DT_MIPS_GOTSYM", - "DT_MIPS_GP_VALUE", - "DT_MIPS_HIDDEN_GOTIDX", - "DT_MIPS_HIPAGENO", - "DT_MIPS_ICHECKSUM", - "DT_MIPS_INTERFACE", - "DT_MIPS_INTERFACE_SIZE", - "DT_MIPS_IVERSION", - "DT_MIPS_LIBLIST", - "DT_MIPS_LIBLISTNO", - "DT_MIPS_LOCALPAGE_GOTIDX", - "DT_MIPS_LOCAL_GOTIDX", - "DT_MIPS_LOCAL_GOTNO", - "DT_MIPS_MSYM", - "DT_MIPS_OPTIONS", - "DT_MIPS_PERF_SUFFIX", - "DT_MIPS_PIXIE_INIT", - "DT_MIPS_PLTGOT", - "DT_MIPS_PROTECTED_GOTIDX", - "DT_MIPS_RLD_MAP", - "DT_MIPS_RLD_MAP_REL", - "DT_MIPS_RLD_TEXT_RESOLVE_ADDR", - "DT_MIPS_RLD_VERSION", - "DT_MIPS_RWPLT", - "DT_MIPS_SYMBOL_LIB", - "DT_MIPS_SYMTABNO", - "DT_MIPS_TIME_STAMP", - "DT_MIPS_UNREFEXTNO", - "DT_MOVEENT", - "DT_MOVESZ", - "DT_MOVETAB", - "DT_NEEDED", - "DT_NULL", - "DT_PLTGOT", - "DT_PLTPAD", - "DT_PLTPADSZ", - "DT_PLTREL", - "DT_PLTRELSZ", - "DT_POSFLAG_1", - "DT_PPC64_GLINK", - "DT_PPC64_OPD", - "DT_PPC64_OPDSZ", - "DT_PPC64_OPT", - "DT_PPC_GOT", - "DT_PPC_OPT", - "DT_PREINIT_ARRAY", - "DT_PREINIT_ARRAYSZ", - "DT_REL", - "DT_RELA", - "DT_RELACOUNT", - "DT_RELAENT", - "DT_RELASZ", - "DT_RELCOUNT", - "DT_RELENT", - "DT_RELSZ", - "DT_RPATH", - "DT_RUNPATH", - "DT_SONAME", - "DT_SPARC_REGISTER", - "DT_STRSZ", - "DT_STRTAB", - "DT_SYMBOLIC", - "DT_SYMENT", - "DT_SYMINENT", - "DT_SYMINFO", - "DT_SYMINSZ", - "DT_SYMTAB", - "DT_SYMTAB_SHNDX", - "DT_TEXTREL", - "DT_TLSDESC_GOT", - "DT_TLSDESC_PLT", - "DT_USED", - "DT_VALRNGHI", - "DT_VALRNGLO", - "DT_VERDEF", - "DT_VERDEFNUM", - "DT_VERNEED", - "DT_VERNEEDNUM", - "DT_VERSYM", - "Data", - "Dyn32", - "Dyn64", - "DynFlag", - "DynTag", - "EI_ABIVERSION", - "EI_CLASS", - "EI_DATA", - "EI_NIDENT", - "EI_OSABI", - "EI_PAD", - "EI_VERSION", - "ELFCLASS32", - "ELFCLASS64", - "ELFCLASSNONE", - "ELFDATA2LSB", - "ELFDATA2MSB", - "ELFDATANONE", - "ELFMAG", - "ELFOSABI_86OPEN", - "ELFOSABI_AIX", - "ELFOSABI_ARM", - "ELFOSABI_AROS", - "ELFOSABI_CLOUDABI", - "ELFOSABI_FENIXOS", - "ELFOSABI_FREEBSD", - "ELFOSABI_HPUX", - "ELFOSABI_HURD", - "ELFOSABI_IRIX", - "ELFOSABI_LINUX", - "ELFOSABI_MODESTO", - "ELFOSABI_NETBSD", - "ELFOSABI_NONE", - "ELFOSABI_NSK", - "ELFOSABI_OPENBSD", - "ELFOSABI_OPENVMS", - "ELFOSABI_SOLARIS", - "ELFOSABI_STANDALONE", - "ELFOSABI_TRU64", - "EM_386", - "EM_486", - "EM_56800EX", - "EM_68HC05", - "EM_68HC08", - "EM_68HC11", - "EM_68HC12", - "EM_68HC16", - "EM_68K", - "EM_78KOR", - "EM_8051", - "EM_860", - "EM_88K", - "EM_960", - "EM_AARCH64", - "EM_ALPHA", - "EM_ALPHA_STD", - "EM_ALTERA_NIOS2", - "EM_AMDGPU", - "EM_ARC", - "EM_ARCA", - "EM_ARC_COMPACT", - "EM_ARC_COMPACT2", - "EM_ARM", - "EM_AVR", - "EM_AVR32", - "EM_BA1", - "EM_BA2", - "EM_BLACKFIN", - "EM_BPF", - "EM_C166", - "EM_CDP", - "EM_CE", - "EM_CLOUDSHIELD", - "EM_COGE", - "EM_COLDFIRE", - "EM_COOL", - "EM_COREA_1ST", - "EM_COREA_2ND", - "EM_CR", - "EM_CR16", - "EM_CRAYNV2", - "EM_CRIS", - "EM_CRX", - "EM_CSR_KALIMBA", - "EM_CUDA", - "EM_CYPRESS_M8C", - "EM_D10V", - "EM_D30V", - "EM_DSP24", - "EM_DSPIC30F", - "EM_DXP", - "EM_ECOG1", - "EM_ECOG16", - "EM_ECOG1X", - "EM_ECOG2", - "EM_ETPU", - "EM_EXCESS", - "EM_F2MC16", - "EM_FIREPATH", - "EM_FR20", - "EM_FR30", - "EM_FT32", - "EM_FX66", - "EM_H8S", - "EM_H8_300", - "EM_H8_300H", - "EM_H8_500", - "EM_HUANY", - "EM_IA_64", - "EM_INTEL205", - "EM_INTEL206", - "EM_INTEL207", - "EM_INTEL208", - "EM_INTEL209", - "EM_IP2K", - "EM_JAVELIN", - "EM_K10M", - "EM_KM32", - "EM_KMX16", - "EM_KMX32", - "EM_KMX8", - "EM_KVARC", - "EM_L10M", - "EM_LANAI", - "EM_LATTICEMICO32", - "EM_LOONGARCH", - "EM_M16C", - "EM_M32", - "EM_M32C", - "EM_M32R", - "EM_MANIK", - "EM_MAX", - "EM_MAXQ30", - "EM_MCHP_PIC", - "EM_MCST_ELBRUS", - "EM_ME16", - "EM_METAG", - "EM_MICROBLAZE", - "EM_MIPS", - "EM_MIPS_RS3_LE", - "EM_MIPS_RS4_BE", - "EM_MIPS_X", - "EM_MMA", - "EM_MMDSP_PLUS", - "EM_MMIX", - "EM_MN10200", - "EM_MN10300", - "EM_MOXIE", - "EM_MSP430", - "EM_NCPU", - "EM_NDR1", - "EM_NDS32", - "EM_NONE", - "EM_NORC", - "EM_NS32K", - "EM_OPEN8", - "EM_OPENRISC", - "EM_PARISC", - "EM_PCP", - "EM_PDP10", - "EM_PDP11", - "EM_PDSP", - "EM_PJ", - "EM_PPC", - "EM_PPC64", - "EM_PRISM", - "EM_QDSP6", - "EM_R32C", - "EM_RCE", - "EM_RH32", - "EM_RISCV", - "EM_RL78", - "EM_RS08", - "EM_RX", - "EM_S370", - "EM_S390", - "EM_SCORE7", - "EM_SEP", - "EM_SE_C17", - "EM_SE_C33", - "EM_SH", - "EM_SHARC", - "EM_SLE9X", - "EM_SNP1K", - "EM_SPARC", - "EM_SPARC32PLUS", - "EM_SPARCV9", - "EM_ST100", - "EM_ST19", - "EM_ST200", - "EM_ST7", - "EM_ST9PLUS", - "EM_STARCORE", - "EM_STM8", - "EM_STXP7X", - "EM_SVX", - "EM_TILE64", - "EM_TILEGX", - "EM_TILEPRO", - "EM_TINYJ", - "EM_TI_ARP32", - "EM_TI_C2000", - "EM_TI_C5500", - "EM_TI_C6000", - "EM_TI_PRU", - "EM_TMM_GPP", - "EM_TPC", - "EM_TRICORE", - "EM_TRIMEDIA", - "EM_TSK3000", - "EM_UNICORE", - "EM_V800", - "EM_V850", - "EM_VAX", - "EM_VIDEOCORE", - "EM_VIDEOCORE3", - "EM_VIDEOCORE5", - "EM_VISIUM", - "EM_VPP500", - "EM_X86_64", - "EM_XCORE", - "EM_XGATE", - "EM_XIMO16", - "EM_XTENSA", - "EM_Z80", - "EM_ZSP", - "ET_CORE", - "ET_DYN", - "ET_EXEC", - "ET_HIOS", - "ET_HIPROC", - "ET_LOOS", - "ET_LOPROC", - "ET_NONE", - "ET_REL", - "EV_CURRENT", - "EV_NONE", - "ErrNoSymbols", - "File", - "FileHeader", - "FormatError", - "Header32", - "Header64", - "ImportedSymbol", - "Machine", - "NT_FPREGSET", - "NT_PRPSINFO", - "NT_PRSTATUS", - "NType", - "NewFile", - "OSABI", - "Open", - "PF_MASKOS", - "PF_MASKPROC", - "PF_R", - "PF_W", - "PF_X", - "PT_AARCH64_ARCHEXT", - "PT_AARCH64_UNWIND", - "PT_ARM_ARCHEXT", - "PT_ARM_EXIDX", - "PT_DYNAMIC", - "PT_GNU_EH_FRAME", - "PT_GNU_MBIND_HI", - "PT_GNU_MBIND_LO", - "PT_GNU_PROPERTY", - "PT_GNU_RELRO", - "PT_GNU_STACK", - "PT_HIOS", - "PT_HIPROC", - "PT_INTERP", - "PT_LOAD", - "PT_LOOS", - "PT_LOPROC", - "PT_MIPS_ABIFLAGS", - "PT_MIPS_OPTIONS", - "PT_MIPS_REGINFO", - "PT_MIPS_RTPROC", - "PT_NOTE", - "PT_NULL", - "PT_OPENBSD_BOOTDATA", - "PT_OPENBSD_RANDOMIZE", - "PT_OPENBSD_WXNEEDED", - "PT_PAX_FLAGS", - "PT_PHDR", - "PT_S390_PGSTE", - "PT_SHLIB", - "PT_SUNWSTACK", - "PT_SUNW_EH_FRAME", - "PT_TLS", - "Prog", - "Prog32", - "Prog64", - "ProgFlag", - "ProgHeader", - "ProgType", - "R_386", - "R_386_16", - "R_386_32", - "R_386_32PLT", - "R_386_8", - "R_386_COPY", - "R_386_GLOB_DAT", - "R_386_GOT32", - "R_386_GOT32X", - "R_386_GOTOFF", - "R_386_GOTPC", - "R_386_IRELATIVE", - "R_386_JMP_SLOT", - "R_386_NONE", - "R_386_PC16", - "R_386_PC32", - "R_386_PC8", - "R_386_PLT32", - "R_386_RELATIVE", - "R_386_SIZE32", - "R_386_TLS_DESC", - "R_386_TLS_DESC_CALL", - "R_386_TLS_DTPMOD32", - "R_386_TLS_DTPOFF32", - "R_386_TLS_GD", - "R_386_TLS_GD_32", - "R_386_TLS_GD_CALL", - "R_386_TLS_GD_POP", - "R_386_TLS_GD_PUSH", - "R_386_TLS_GOTDESC", - "R_386_TLS_GOTIE", - "R_386_TLS_IE", - "R_386_TLS_IE_32", - "R_386_TLS_LDM", - "R_386_TLS_LDM_32", - "R_386_TLS_LDM_CALL", - "R_386_TLS_LDM_POP", - "R_386_TLS_LDM_PUSH", - "R_386_TLS_LDO_32", - "R_386_TLS_LE", - "R_386_TLS_LE_32", - "R_386_TLS_TPOFF", - "R_386_TLS_TPOFF32", - "R_390", - "R_390_12", - "R_390_16", - "R_390_20", - "R_390_32", - "R_390_64", - "R_390_8", - "R_390_COPY", - "R_390_GLOB_DAT", - "R_390_GOT12", - "R_390_GOT16", - "R_390_GOT20", - "R_390_GOT32", - "R_390_GOT64", - "R_390_GOTENT", - "R_390_GOTOFF", - "R_390_GOTOFF16", - "R_390_GOTOFF64", - "R_390_GOTPC", - "R_390_GOTPCDBL", - "R_390_GOTPLT12", - "R_390_GOTPLT16", - "R_390_GOTPLT20", - "R_390_GOTPLT32", - "R_390_GOTPLT64", - "R_390_GOTPLTENT", - "R_390_GOTPLTOFF16", - "R_390_GOTPLTOFF32", - "R_390_GOTPLTOFF64", - "R_390_JMP_SLOT", - "R_390_NONE", - "R_390_PC16", - "R_390_PC16DBL", - "R_390_PC32", - "R_390_PC32DBL", - "R_390_PC64", - "R_390_PLT16DBL", - "R_390_PLT32", - "R_390_PLT32DBL", - "R_390_PLT64", - "R_390_RELATIVE", - "R_390_TLS_DTPMOD", - "R_390_TLS_DTPOFF", - "R_390_TLS_GD32", - "R_390_TLS_GD64", - "R_390_TLS_GDCALL", - "R_390_TLS_GOTIE12", - "R_390_TLS_GOTIE20", - "R_390_TLS_GOTIE32", - "R_390_TLS_GOTIE64", - "R_390_TLS_IE32", - "R_390_TLS_IE64", - "R_390_TLS_IEENT", - "R_390_TLS_LDCALL", - "R_390_TLS_LDM32", - "R_390_TLS_LDM64", - "R_390_TLS_LDO32", - "R_390_TLS_LDO64", - "R_390_TLS_LE32", - "R_390_TLS_LE64", - "R_390_TLS_LOAD", - "R_390_TLS_TPOFF", - "R_AARCH64", - "R_AARCH64_ABS16", - "R_AARCH64_ABS32", - "R_AARCH64_ABS64", - "R_AARCH64_ADD_ABS_LO12_NC", - "R_AARCH64_ADR_GOT_PAGE", - "R_AARCH64_ADR_PREL_LO21", - "R_AARCH64_ADR_PREL_PG_HI21", - "R_AARCH64_ADR_PREL_PG_HI21_NC", - "R_AARCH64_CALL26", - "R_AARCH64_CONDBR19", - "R_AARCH64_COPY", - "R_AARCH64_GLOB_DAT", - "R_AARCH64_GOT_LD_PREL19", - "R_AARCH64_IRELATIVE", - "R_AARCH64_JUMP26", - "R_AARCH64_JUMP_SLOT", - "R_AARCH64_LD64_GOTOFF_LO15", - "R_AARCH64_LD64_GOTPAGE_LO15", - "R_AARCH64_LD64_GOT_LO12_NC", - "R_AARCH64_LDST128_ABS_LO12_NC", - "R_AARCH64_LDST16_ABS_LO12_NC", - "R_AARCH64_LDST32_ABS_LO12_NC", - "R_AARCH64_LDST64_ABS_LO12_NC", - "R_AARCH64_LDST8_ABS_LO12_NC", - "R_AARCH64_LD_PREL_LO19", - "R_AARCH64_MOVW_SABS_G0", - "R_AARCH64_MOVW_SABS_G1", - "R_AARCH64_MOVW_SABS_G2", - "R_AARCH64_MOVW_UABS_G0", - "R_AARCH64_MOVW_UABS_G0_NC", - "R_AARCH64_MOVW_UABS_G1", - "R_AARCH64_MOVW_UABS_G1_NC", - "R_AARCH64_MOVW_UABS_G2", - "R_AARCH64_MOVW_UABS_G2_NC", - "R_AARCH64_MOVW_UABS_G3", - "R_AARCH64_NONE", - "R_AARCH64_NULL", - "R_AARCH64_P32_ABS16", - "R_AARCH64_P32_ABS32", - "R_AARCH64_P32_ADD_ABS_LO12_NC", - "R_AARCH64_P32_ADR_GOT_PAGE", - "R_AARCH64_P32_ADR_PREL_LO21", - "R_AARCH64_P32_ADR_PREL_PG_HI21", - "R_AARCH64_P32_CALL26", - "R_AARCH64_P32_CONDBR19", - "R_AARCH64_P32_COPY", - "R_AARCH64_P32_GLOB_DAT", - "R_AARCH64_P32_GOT_LD_PREL19", - "R_AARCH64_P32_IRELATIVE", - "R_AARCH64_P32_JUMP26", - "R_AARCH64_P32_JUMP_SLOT", - "R_AARCH64_P32_LD32_GOT_LO12_NC", - "R_AARCH64_P32_LDST128_ABS_LO12_NC", - "R_AARCH64_P32_LDST16_ABS_LO12_NC", - "R_AARCH64_P32_LDST32_ABS_LO12_NC", - "R_AARCH64_P32_LDST64_ABS_LO12_NC", - "R_AARCH64_P32_LDST8_ABS_LO12_NC", - "R_AARCH64_P32_LD_PREL_LO19", - "R_AARCH64_P32_MOVW_SABS_G0", - "R_AARCH64_P32_MOVW_UABS_G0", - "R_AARCH64_P32_MOVW_UABS_G0_NC", - "R_AARCH64_P32_MOVW_UABS_G1", - "R_AARCH64_P32_PREL16", - "R_AARCH64_P32_PREL32", - "R_AARCH64_P32_RELATIVE", - "R_AARCH64_P32_TLSDESC", - "R_AARCH64_P32_TLSDESC_ADD_LO12_NC", - "R_AARCH64_P32_TLSDESC_ADR_PAGE21", - "R_AARCH64_P32_TLSDESC_ADR_PREL21", - "R_AARCH64_P32_TLSDESC_CALL", - "R_AARCH64_P32_TLSDESC_LD32_LO12_NC", - "R_AARCH64_P32_TLSDESC_LD_PREL19", - "R_AARCH64_P32_TLSGD_ADD_LO12_NC", - "R_AARCH64_P32_TLSGD_ADR_PAGE21", - "R_AARCH64_P32_TLSIE_ADR_GOTTPREL_PAGE21", - "R_AARCH64_P32_TLSIE_LD32_GOTTPREL_LO12_NC", - "R_AARCH64_P32_TLSIE_LD_GOTTPREL_PREL19", - "R_AARCH64_P32_TLSLE_ADD_TPREL_HI12", - "R_AARCH64_P32_TLSLE_ADD_TPREL_LO12", - "R_AARCH64_P32_TLSLE_ADD_TPREL_LO12_NC", - "R_AARCH64_P32_TLSLE_MOVW_TPREL_G0", - "R_AARCH64_P32_TLSLE_MOVW_TPREL_G0_NC", - "R_AARCH64_P32_TLSLE_MOVW_TPREL_G1", - "R_AARCH64_P32_TLS_DTPMOD", - "R_AARCH64_P32_TLS_DTPREL", - "R_AARCH64_P32_TLS_TPREL", - "R_AARCH64_P32_TSTBR14", - "R_AARCH64_PREL16", - "R_AARCH64_PREL32", - "R_AARCH64_PREL64", - "R_AARCH64_RELATIVE", - "R_AARCH64_TLSDESC", - "R_AARCH64_TLSDESC_ADD", - "R_AARCH64_TLSDESC_ADD_LO12_NC", - "R_AARCH64_TLSDESC_ADR_PAGE21", - "R_AARCH64_TLSDESC_ADR_PREL21", - "R_AARCH64_TLSDESC_CALL", - "R_AARCH64_TLSDESC_LD64_LO12_NC", - "R_AARCH64_TLSDESC_LDR", - "R_AARCH64_TLSDESC_LD_PREL19", - "R_AARCH64_TLSDESC_OFF_G0_NC", - "R_AARCH64_TLSDESC_OFF_G1", - "R_AARCH64_TLSGD_ADD_LO12_NC", - "R_AARCH64_TLSGD_ADR_PAGE21", - "R_AARCH64_TLSGD_ADR_PREL21", - "R_AARCH64_TLSGD_MOVW_G0_NC", - "R_AARCH64_TLSGD_MOVW_G1", - "R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21", - "R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC", - "R_AARCH64_TLSIE_LD_GOTTPREL_PREL19", - "R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC", - "R_AARCH64_TLSIE_MOVW_GOTTPREL_G1", - "R_AARCH64_TLSLD_ADR_PAGE21", - "R_AARCH64_TLSLD_ADR_PREL21", - "R_AARCH64_TLSLD_LDST128_DTPREL_LO12", - "R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC", - "R_AARCH64_TLSLE_ADD_TPREL_HI12", - "R_AARCH64_TLSLE_ADD_TPREL_LO12", - "R_AARCH64_TLSLE_ADD_TPREL_LO12_NC", - "R_AARCH64_TLSLE_LDST128_TPREL_LO12", - "R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC", - "R_AARCH64_TLSLE_MOVW_TPREL_G0", - "R_AARCH64_TLSLE_MOVW_TPREL_G0_NC", - "R_AARCH64_TLSLE_MOVW_TPREL_G1", - "R_AARCH64_TLSLE_MOVW_TPREL_G1_NC", - "R_AARCH64_TLSLE_MOVW_TPREL_G2", - "R_AARCH64_TLS_DTPMOD64", - "R_AARCH64_TLS_DTPREL64", - "R_AARCH64_TLS_TPREL64", - "R_AARCH64_TSTBR14", - "R_ALPHA", - "R_ALPHA_BRADDR", - "R_ALPHA_COPY", - "R_ALPHA_GLOB_DAT", - "R_ALPHA_GPDISP", - "R_ALPHA_GPREL32", - "R_ALPHA_GPRELHIGH", - "R_ALPHA_GPRELLOW", - "R_ALPHA_GPVALUE", - "R_ALPHA_HINT", - "R_ALPHA_IMMED_BR_HI32", - "R_ALPHA_IMMED_GP_16", - "R_ALPHA_IMMED_GP_HI32", - "R_ALPHA_IMMED_LO32", - "R_ALPHA_IMMED_SCN_HI32", - "R_ALPHA_JMP_SLOT", - "R_ALPHA_LITERAL", - "R_ALPHA_LITUSE", - "R_ALPHA_NONE", - "R_ALPHA_OP_PRSHIFT", - "R_ALPHA_OP_PSUB", - "R_ALPHA_OP_PUSH", - "R_ALPHA_OP_STORE", - "R_ALPHA_REFLONG", - "R_ALPHA_REFQUAD", - "R_ALPHA_RELATIVE", - "R_ALPHA_SREL16", - "R_ALPHA_SREL32", - "R_ALPHA_SREL64", - "R_ARM", - "R_ARM_ABS12", - "R_ARM_ABS16", - "R_ARM_ABS32", - "R_ARM_ABS32_NOI", - "R_ARM_ABS8", - "R_ARM_ALU_PCREL_15_8", - "R_ARM_ALU_PCREL_23_15", - "R_ARM_ALU_PCREL_7_0", - "R_ARM_ALU_PC_G0", - "R_ARM_ALU_PC_G0_NC", - "R_ARM_ALU_PC_G1", - "R_ARM_ALU_PC_G1_NC", - "R_ARM_ALU_PC_G2", - "R_ARM_ALU_SBREL_19_12_NC", - "R_ARM_ALU_SBREL_27_20_CK", - "R_ARM_ALU_SB_G0", - "R_ARM_ALU_SB_G0_NC", - "R_ARM_ALU_SB_G1", - "R_ARM_ALU_SB_G1_NC", - "R_ARM_ALU_SB_G2", - "R_ARM_AMP_VCALL9", - "R_ARM_BASE_ABS", - "R_ARM_CALL", - "R_ARM_COPY", - "R_ARM_GLOB_DAT", - "R_ARM_GNU_VTENTRY", - "R_ARM_GNU_VTINHERIT", - "R_ARM_GOT32", - "R_ARM_GOTOFF", - "R_ARM_GOTOFF12", - "R_ARM_GOTPC", - "R_ARM_GOTRELAX", - "R_ARM_GOT_ABS", - "R_ARM_GOT_BREL12", - "R_ARM_GOT_PREL", - "R_ARM_IRELATIVE", - "R_ARM_JUMP24", - "R_ARM_JUMP_SLOT", - "R_ARM_LDC_PC_G0", - "R_ARM_LDC_PC_G1", - "R_ARM_LDC_PC_G2", - "R_ARM_LDC_SB_G0", - "R_ARM_LDC_SB_G1", - "R_ARM_LDC_SB_G2", - "R_ARM_LDRS_PC_G0", - "R_ARM_LDRS_PC_G1", - "R_ARM_LDRS_PC_G2", - "R_ARM_LDRS_SB_G0", - "R_ARM_LDRS_SB_G1", - "R_ARM_LDRS_SB_G2", - "R_ARM_LDR_PC_G1", - "R_ARM_LDR_PC_G2", - "R_ARM_LDR_SBREL_11_10_NC", - "R_ARM_LDR_SB_G0", - "R_ARM_LDR_SB_G1", - "R_ARM_LDR_SB_G2", - "R_ARM_ME_TOO", - "R_ARM_MOVT_ABS", - "R_ARM_MOVT_BREL", - "R_ARM_MOVT_PREL", - "R_ARM_MOVW_ABS_NC", - "R_ARM_MOVW_BREL", - "R_ARM_MOVW_BREL_NC", - "R_ARM_MOVW_PREL_NC", - "R_ARM_NONE", - "R_ARM_PC13", - "R_ARM_PC24", - "R_ARM_PLT32", - "R_ARM_PLT32_ABS", - "R_ARM_PREL31", - "R_ARM_PRIVATE_0", - "R_ARM_PRIVATE_1", - "R_ARM_PRIVATE_10", - "R_ARM_PRIVATE_11", - "R_ARM_PRIVATE_12", - "R_ARM_PRIVATE_13", - "R_ARM_PRIVATE_14", - "R_ARM_PRIVATE_15", - "R_ARM_PRIVATE_2", - "R_ARM_PRIVATE_3", - "R_ARM_PRIVATE_4", - "R_ARM_PRIVATE_5", - "R_ARM_PRIVATE_6", - "R_ARM_PRIVATE_7", - "R_ARM_PRIVATE_8", - "R_ARM_PRIVATE_9", - "R_ARM_RABS32", - "R_ARM_RBASE", - "R_ARM_REL32", - "R_ARM_REL32_NOI", - "R_ARM_RELATIVE", - "R_ARM_RPC24", - "R_ARM_RREL32", - "R_ARM_RSBREL32", - "R_ARM_RXPC25", - "R_ARM_SBREL31", - "R_ARM_SBREL32", - "R_ARM_SWI24", - "R_ARM_TARGET1", - "R_ARM_TARGET2", - "R_ARM_THM_ABS5", - "R_ARM_THM_ALU_ABS_G0_NC", - "R_ARM_THM_ALU_ABS_G1_NC", - "R_ARM_THM_ALU_ABS_G2_NC", - "R_ARM_THM_ALU_ABS_G3", - "R_ARM_THM_ALU_PREL_11_0", - "R_ARM_THM_GOT_BREL12", - "R_ARM_THM_JUMP11", - "R_ARM_THM_JUMP19", - "R_ARM_THM_JUMP24", - "R_ARM_THM_JUMP6", - "R_ARM_THM_JUMP8", - "R_ARM_THM_MOVT_ABS", - "R_ARM_THM_MOVT_BREL", - "R_ARM_THM_MOVT_PREL", - "R_ARM_THM_MOVW_ABS_NC", - "R_ARM_THM_MOVW_BREL", - "R_ARM_THM_MOVW_BREL_NC", - "R_ARM_THM_MOVW_PREL_NC", - "R_ARM_THM_PC12", - "R_ARM_THM_PC22", - "R_ARM_THM_PC8", - "R_ARM_THM_RPC22", - "R_ARM_THM_SWI8", - "R_ARM_THM_TLS_CALL", - "R_ARM_THM_TLS_DESCSEQ16", - "R_ARM_THM_TLS_DESCSEQ32", - "R_ARM_THM_XPC22", - "R_ARM_TLS_CALL", - "R_ARM_TLS_DESCSEQ", - "R_ARM_TLS_DTPMOD32", - "R_ARM_TLS_DTPOFF32", - "R_ARM_TLS_GD32", - "R_ARM_TLS_GOTDESC", - "R_ARM_TLS_IE12GP", - "R_ARM_TLS_IE32", - "R_ARM_TLS_LDM32", - "R_ARM_TLS_LDO12", - "R_ARM_TLS_LDO32", - "R_ARM_TLS_LE12", - "R_ARM_TLS_LE32", - "R_ARM_TLS_TPOFF32", - "R_ARM_V4BX", - "R_ARM_XPC25", - "R_INFO", - "R_INFO32", - "R_LARCH", - "R_LARCH_32", - "R_LARCH_32_PCREL", - "R_LARCH_64", - "R_LARCH_ABS64_HI12", - "R_LARCH_ABS64_LO20", - "R_LARCH_ABS_HI20", - "R_LARCH_ABS_LO12", - "R_LARCH_ADD16", - "R_LARCH_ADD24", - "R_LARCH_ADD32", - "R_LARCH_ADD64", - "R_LARCH_ADD8", - "R_LARCH_B16", - "R_LARCH_B21", - "R_LARCH_B26", - "R_LARCH_COPY", - "R_LARCH_GNU_VTENTRY", - "R_LARCH_GNU_VTINHERIT", - "R_LARCH_GOT64_HI12", - "R_LARCH_GOT64_LO20", - "R_LARCH_GOT64_PC_HI12", - "R_LARCH_GOT64_PC_LO20", - "R_LARCH_GOT_HI20", - "R_LARCH_GOT_LO12", - "R_LARCH_GOT_PC_HI20", - "R_LARCH_GOT_PC_LO12", - "R_LARCH_IRELATIVE", - "R_LARCH_JUMP_SLOT", - "R_LARCH_MARK_LA", - "R_LARCH_MARK_PCREL", - "R_LARCH_NONE", - "R_LARCH_PCALA64_HI12", - "R_LARCH_PCALA64_LO20", - "R_LARCH_PCALA_HI20", - "R_LARCH_PCALA_LO12", - "R_LARCH_RELATIVE", - "R_LARCH_RELAX", - "R_LARCH_SOP_ADD", - "R_LARCH_SOP_AND", - "R_LARCH_SOP_ASSERT", - "R_LARCH_SOP_IF_ELSE", - "R_LARCH_SOP_NOT", - "R_LARCH_SOP_POP_32_S_0_10_10_16_S2", - "R_LARCH_SOP_POP_32_S_0_5_10_16_S2", - "R_LARCH_SOP_POP_32_S_10_12", - "R_LARCH_SOP_POP_32_S_10_16", - "R_LARCH_SOP_POP_32_S_10_16_S2", - "R_LARCH_SOP_POP_32_S_10_5", - "R_LARCH_SOP_POP_32_S_5_20", - "R_LARCH_SOP_POP_32_U", - "R_LARCH_SOP_POP_32_U_10_12", - "R_LARCH_SOP_PUSH_ABSOLUTE", - "R_LARCH_SOP_PUSH_DUP", - "R_LARCH_SOP_PUSH_GPREL", - "R_LARCH_SOP_PUSH_PCREL", - "R_LARCH_SOP_PUSH_PLT_PCREL", - "R_LARCH_SOP_PUSH_TLS_GD", - "R_LARCH_SOP_PUSH_TLS_GOT", - "R_LARCH_SOP_PUSH_TLS_TPREL", - "R_LARCH_SOP_SL", - "R_LARCH_SOP_SR", - "R_LARCH_SOP_SUB", - "R_LARCH_SUB16", - "R_LARCH_SUB24", - "R_LARCH_SUB32", - "R_LARCH_SUB64", - "R_LARCH_SUB8", - "R_LARCH_TLS_DTPMOD32", - "R_LARCH_TLS_DTPMOD64", - "R_LARCH_TLS_DTPREL32", - "R_LARCH_TLS_DTPREL64", - "R_LARCH_TLS_GD_HI20", - "R_LARCH_TLS_GD_PC_HI20", - "R_LARCH_TLS_IE64_HI12", - "R_LARCH_TLS_IE64_LO20", - "R_LARCH_TLS_IE64_PC_HI12", - "R_LARCH_TLS_IE64_PC_LO20", - "R_LARCH_TLS_IE_HI20", - "R_LARCH_TLS_IE_LO12", - "R_LARCH_TLS_IE_PC_HI20", - "R_LARCH_TLS_IE_PC_LO12", - "R_LARCH_TLS_LD_HI20", - "R_LARCH_TLS_LD_PC_HI20", - "R_LARCH_TLS_LE64_HI12", - "R_LARCH_TLS_LE64_LO20", - "R_LARCH_TLS_LE_HI20", - "R_LARCH_TLS_LE_LO12", - "R_LARCH_TLS_TPREL32", - "R_LARCH_TLS_TPREL64", - "R_MIPS", - "R_MIPS_16", - "R_MIPS_26", - "R_MIPS_32", - "R_MIPS_64", - "R_MIPS_ADD_IMMEDIATE", - "R_MIPS_CALL16", - "R_MIPS_CALL_HI16", - "R_MIPS_CALL_LO16", - "R_MIPS_DELETE", - "R_MIPS_GOT16", - "R_MIPS_GOT_DISP", - "R_MIPS_GOT_HI16", - "R_MIPS_GOT_LO16", - "R_MIPS_GOT_OFST", - "R_MIPS_GOT_PAGE", - "R_MIPS_GPREL16", - "R_MIPS_GPREL32", - "R_MIPS_HI16", - "R_MIPS_HIGHER", - "R_MIPS_HIGHEST", - "R_MIPS_INSERT_A", - "R_MIPS_INSERT_B", - "R_MIPS_JALR", - "R_MIPS_LITERAL", - "R_MIPS_LO16", - "R_MIPS_NONE", - "R_MIPS_PC16", - "R_MIPS_PJUMP", - "R_MIPS_REL16", - "R_MIPS_REL32", - "R_MIPS_RELGOT", - "R_MIPS_SCN_DISP", - "R_MIPS_SHIFT5", - "R_MIPS_SHIFT6", - "R_MIPS_SUB", - "R_MIPS_TLS_DTPMOD32", - "R_MIPS_TLS_DTPMOD64", - "R_MIPS_TLS_DTPREL32", - "R_MIPS_TLS_DTPREL64", - "R_MIPS_TLS_DTPREL_HI16", - "R_MIPS_TLS_DTPREL_LO16", - "R_MIPS_TLS_GD", - "R_MIPS_TLS_GOTTPREL", - "R_MIPS_TLS_LDM", - "R_MIPS_TLS_TPREL32", - "R_MIPS_TLS_TPREL64", - "R_MIPS_TLS_TPREL_HI16", - "R_MIPS_TLS_TPREL_LO16", - "R_PPC", - "R_PPC64", - "R_PPC64_ADDR14", - "R_PPC64_ADDR14_BRNTAKEN", - "R_PPC64_ADDR14_BRTAKEN", - "R_PPC64_ADDR16", - "R_PPC64_ADDR16_DS", - "R_PPC64_ADDR16_HA", - "R_PPC64_ADDR16_HI", - "R_PPC64_ADDR16_HIGH", - "R_PPC64_ADDR16_HIGHA", - "R_PPC64_ADDR16_HIGHER", - "R_PPC64_ADDR16_HIGHER34", - "R_PPC64_ADDR16_HIGHERA", - "R_PPC64_ADDR16_HIGHERA34", - "R_PPC64_ADDR16_HIGHEST", - "R_PPC64_ADDR16_HIGHEST34", - "R_PPC64_ADDR16_HIGHESTA", - "R_PPC64_ADDR16_HIGHESTA34", - "R_PPC64_ADDR16_LO", - "R_PPC64_ADDR16_LO_DS", - "R_PPC64_ADDR24", - "R_PPC64_ADDR32", - "R_PPC64_ADDR64", - "R_PPC64_ADDR64_LOCAL", - "R_PPC64_COPY", - "R_PPC64_D28", - "R_PPC64_D34", - "R_PPC64_D34_HA30", - "R_PPC64_D34_HI30", - "R_PPC64_D34_LO", - "R_PPC64_DTPMOD64", - "R_PPC64_DTPREL16", - "R_PPC64_DTPREL16_DS", - "R_PPC64_DTPREL16_HA", - "R_PPC64_DTPREL16_HI", - "R_PPC64_DTPREL16_HIGH", - "R_PPC64_DTPREL16_HIGHA", - "R_PPC64_DTPREL16_HIGHER", - "R_PPC64_DTPREL16_HIGHERA", - "R_PPC64_DTPREL16_HIGHEST", - "R_PPC64_DTPREL16_HIGHESTA", - "R_PPC64_DTPREL16_LO", - "R_PPC64_DTPREL16_LO_DS", - "R_PPC64_DTPREL34", - "R_PPC64_DTPREL64", - "R_PPC64_ENTRY", - "R_PPC64_GLOB_DAT", - "R_PPC64_GNU_VTENTRY", - "R_PPC64_GNU_VTINHERIT", - "R_PPC64_GOT16", - "R_PPC64_GOT16_DS", - "R_PPC64_GOT16_HA", - "R_PPC64_GOT16_HI", - "R_PPC64_GOT16_LO", - "R_PPC64_GOT16_LO_DS", - "R_PPC64_GOT_DTPREL16_DS", - "R_PPC64_GOT_DTPREL16_HA", - "R_PPC64_GOT_DTPREL16_HI", - "R_PPC64_GOT_DTPREL16_LO_DS", - "R_PPC64_GOT_DTPREL_PCREL34", - "R_PPC64_GOT_PCREL34", - "R_PPC64_GOT_TLSGD16", - "R_PPC64_GOT_TLSGD16_HA", - "R_PPC64_GOT_TLSGD16_HI", - "R_PPC64_GOT_TLSGD16_LO", - "R_PPC64_GOT_TLSGD_PCREL34", - "R_PPC64_GOT_TLSLD16", - "R_PPC64_GOT_TLSLD16_HA", - "R_PPC64_GOT_TLSLD16_HI", - "R_PPC64_GOT_TLSLD16_LO", - "R_PPC64_GOT_TLSLD_PCREL34", - "R_PPC64_GOT_TPREL16_DS", - "R_PPC64_GOT_TPREL16_HA", - "R_PPC64_GOT_TPREL16_HI", - "R_PPC64_GOT_TPREL16_LO_DS", - "R_PPC64_GOT_TPREL_PCREL34", - "R_PPC64_IRELATIVE", - "R_PPC64_JMP_IREL", - "R_PPC64_JMP_SLOT", - "R_PPC64_NONE", - "R_PPC64_PCREL28", - "R_PPC64_PCREL34", - "R_PPC64_PCREL_OPT", - "R_PPC64_PLT16_HA", - "R_PPC64_PLT16_HI", - "R_PPC64_PLT16_LO", - "R_PPC64_PLT16_LO_DS", - "R_PPC64_PLT32", - "R_PPC64_PLT64", - "R_PPC64_PLTCALL", - "R_PPC64_PLTCALL_NOTOC", - "R_PPC64_PLTGOT16", - "R_PPC64_PLTGOT16_DS", - "R_PPC64_PLTGOT16_HA", - "R_PPC64_PLTGOT16_HI", - "R_PPC64_PLTGOT16_LO", - "R_PPC64_PLTGOT_LO_DS", - "R_PPC64_PLTREL32", - "R_PPC64_PLTREL64", - "R_PPC64_PLTSEQ", - "R_PPC64_PLTSEQ_NOTOC", - "R_PPC64_PLT_PCREL34", - "R_PPC64_PLT_PCREL34_NOTOC", - "R_PPC64_REL14", - "R_PPC64_REL14_BRNTAKEN", - "R_PPC64_REL14_BRTAKEN", - "R_PPC64_REL16", - "R_PPC64_REL16DX_HA", - "R_PPC64_REL16_HA", - "R_PPC64_REL16_HI", - "R_PPC64_REL16_HIGH", - "R_PPC64_REL16_HIGHA", - "R_PPC64_REL16_HIGHER", - "R_PPC64_REL16_HIGHER34", - "R_PPC64_REL16_HIGHERA", - "R_PPC64_REL16_HIGHERA34", - "R_PPC64_REL16_HIGHEST", - "R_PPC64_REL16_HIGHEST34", - "R_PPC64_REL16_HIGHESTA", - "R_PPC64_REL16_HIGHESTA34", - "R_PPC64_REL16_LO", - "R_PPC64_REL24", - "R_PPC64_REL24_NOTOC", - "R_PPC64_REL30", - "R_PPC64_REL32", - "R_PPC64_REL64", - "R_PPC64_RELATIVE", - "R_PPC64_SECTOFF", - "R_PPC64_SECTOFF_DS", - "R_PPC64_SECTOFF_HA", - "R_PPC64_SECTOFF_HI", - "R_PPC64_SECTOFF_LO", - "R_PPC64_SECTOFF_LO_DS", - "R_PPC64_TLS", - "R_PPC64_TLSGD", - "R_PPC64_TLSLD", - "R_PPC64_TOC", - "R_PPC64_TOC16", - "R_PPC64_TOC16_DS", - "R_PPC64_TOC16_HA", - "R_PPC64_TOC16_HI", - "R_PPC64_TOC16_LO", - "R_PPC64_TOC16_LO_DS", - "R_PPC64_TOCSAVE", - "R_PPC64_TPREL16", - "R_PPC64_TPREL16_DS", - "R_PPC64_TPREL16_HA", - "R_PPC64_TPREL16_HI", - "R_PPC64_TPREL16_HIGH", - "R_PPC64_TPREL16_HIGHA", - "R_PPC64_TPREL16_HIGHER", - "R_PPC64_TPREL16_HIGHERA", - "R_PPC64_TPREL16_HIGHEST", - "R_PPC64_TPREL16_HIGHESTA", - "R_PPC64_TPREL16_LO", - "R_PPC64_TPREL16_LO_DS", - "R_PPC64_TPREL34", - "R_PPC64_TPREL64", - "R_PPC64_UADDR16", - "R_PPC64_UADDR32", - "R_PPC64_UADDR64", - "R_PPC_ADDR14", - "R_PPC_ADDR14_BRNTAKEN", - "R_PPC_ADDR14_BRTAKEN", - "R_PPC_ADDR16", - "R_PPC_ADDR16_HA", - "R_PPC_ADDR16_HI", - "R_PPC_ADDR16_LO", - "R_PPC_ADDR24", - "R_PPC_ADDR32", - "R_PPC_COPY", - "R_PPC_DTPMOD32", - "R_PPC_DTPREL16", - "R_PPC_DTPREL16_HA", - "R_PPC_DTPREL16_HI", - "R_PPC_DTPREL16_LO", - "R_PPC_DTPREL32", - "R_PPC_EMB_BIT_FLD", - "R_PPC_EMB_MRKREF", - "R_PPC_EMB_NADDR16", - "R_PPC_EMB_NADDR16_HA", - "R_PPC_EMB_NADDR16_HI", - "R_PPC_EMB_NADDR16_LO", - "R_PPC_EMB_NADDR32", - "R_PPC_EMB_RELSDA", - "R_PPC_EMB_RELSEC16", - "R_PPC_EMB_RELST_HA", - "R_PPC_EMB_RELST_HI", - "R_PPC_EMB_RELST_LO", - "R_PPC_EMB_SDA21", - "R_PPC_EMB_SDA2I16", - "R_PPC_EMB_SDA2REL", - "R_PPC_EMB_SDAI16", - "R_PPC_GLOB_DAT", - "R_PPC_GOT16", - "R_PPC_GOT16_HA", - "R_PPC_GOT16_HI", - "R_PPC_GOT16_LO", - "R_PPC_GOT_TLSGD16", - "R_PPC_GOT_TLSGD16_HA", - "R_PPC_GOT_TLSGD16_HI", - "R_PPC_GOT_TLSGD16_LO", - "R_PPC_GOT_TLSLD16", - "R_PPC_GOT_TLSLD16_HA", - "R_PPC_GOT_TLSLD16_HI", - "R_PPC_GOT_TLSLD16_LO", - "R_PPC_GOT_TPREL16", - "R_PPC_GOT_TPREL16_HA", - "R_PPC_GOT_TPREL16_HI", - "R_PPC_GOT_TPREL16_LO", - "R_PPC_JMP_SLOT", - "R_PPC_LOCAL24PC", - "R_PPC_NONE", - "R_PPC_PLT16_HA", - "R_PPC_PLT16_HI", - "R_PPC_PLT16_LO", - "R_PPC_PLT32", - "R_PPC_PLTREL24", - "R_PPC_PLTREL32", - "R_PPC_REL14", - "R_PPC_REL14_BRNTAKEN", - "R_PPC_REL14_BRTAKEN", - "R_PPC_REL24", - "R_PPC_REL32", - "R_PPC_RELATIVE", - "R_PPC_SDAREL16", - "R_PPC_SECTOFF", - "R_PPC_SECTOFF_HA", - "R_PPC_SECTOFF_HI", - "R_PPC_SECTOFF_LO", - "R_PPC_TLS", - "R_PPC_TPREL16", - "R_PPC_TPREL16_HA", - "R_PPC_TPREL16_HI", - "R_PPC_TPREL16_LO", - "R_PPC_TPREL32", - "R_PPC_UADDR16", - "R_PPC_UADDR32", - "R_RISCV", - "R_RISCV_32", - "R_RISCV_32_PCREL", - "R_RISCV_64", - "R_RISCV_ADD16", - "R_RISCV_ADD32", - "R_RISCV_ADD64", - "R_RISCV_ADD8", - "R_RISCV_ALIGN", - "R_RISCV_BRANCH", - "R_RISCV_CALL", - "R_RISCV_CALL_PLT", - "R_RISCV_COPY", - "R_RISCV_GNU_VTENTRY", - "R_RISCV_GNU_VTINHERIT", - "R_RISCV_GOT_HI20", - "R_RISCV_GPREL_I", - "R_RISCV_GPREL_S", - "R_RISCV_HI20", - "R_RISCV_JAL", - "R_RISCV_JUMP_SLOT", - "R_RISCV_LO12_I", - "R_RISCV_LO12_S", - "R_RISCV_NONE", - "R_RISCV_PCREL_HI20", - "R_RISCV_PCREL_LO12_I", - "R_RISCV_PCREL_LO12_S", - "R_RISCV_RELATIVE", - "R_RISCV_RELAX", - "R_RISCV_RVC_BRANCH", - "R_RISCV_RVC_JUMP", - "R_RISCV_RVC_LUI", - "R_RISCV_SET16", - "R_RISCV_SET32", - "R_RISCV_SET6", - "R_RISCV_SET8", - "R_RISCV_SUB16", - "R_RISCV_SUB32", - "R_RISCV_SUB6", - "R_RISCV_SUB64", - "R_RISCV_SUB8", - "R_RISCV_TLS_DTPMOD32", - "R_RISCV_TLS_DTPMOD64", - "R_RISCV_TLS_DTPREL32", - "R_RISCV_TLS_DTPREL64", - "R_RISCV_TLS_GD_HI20", - "R_RISCV_TLS_GOT_HI20", - "R_RISCV_TLS_TPREL32", - "R_RISCV_TLS_TPREL64", - "R_RISCV_TPREL_ADD", - "R_RISCV_TPREL_HI20", - "R_RISCV_TPREL_I", - "R_RISCV_TPREL_LO12_I", - "R_RISCV_TPREL_LO12_S", - "R_RISCV_TPREL_S", - "R_SPARC", - "R_SPARC_10", - "R_SPARC_11", - "R_SPARC_13", - "R_SPARC_16", - "R_SPARC_22", - "R_SPARC_32", - "R_SPARC_5", - "R_SPARC_6", - "R_SPARC_64", - "R_SPARC_7", - "R_SPARC_8", - "R_SPARC_COPY", - "R_SPARC_DISP16", - "R_SPARC_DISP32", - "R_SPARC_DISP64", - "R_SPARC_DISP8", - "R_SPARC_GLOB_DAT", - "R_SPARC_GLOB_JMP", - "R_SPARC_GOT10", - "R_SPARC_GOT13", - "R_SPARC_GOT22", - "R_SPARC_H44", - "R_SPARC_HH22", - "R_SPARC_HI22", - "R_SPARC_HIPLT22", - "R_SPARC_HIX22", - "R_SPARC_HM10", - "R_SPARC_JMP_SLOT", - "R_SPARC_L44", - "R_SPARC_LM22", - "R_SPARC_LO10", - "R_SPARC_LOPLT10", - "R_SPARC_LOX10", - "R_SPARC_M44", - "R_SPARC_NONE", - "R_SPARC_OLO10", - "R_SPARC_PC10", - "R_SPARC_PC22", - "R_SPARC_PCPLT10", - "R_SPARC_PCPLT22", - "R_SPARC_PCPLT32", - "R_SPARC_PC_HH22", - "R_SPARC_PC_HM10", - "R_SPARC_PC_LM22", - "R_SPARC_PLT32", - "R_SPARC_PLT64", - "R_SPARC_REGISTER", - "R_SPARC_RELATIVE", - "R_SPARC_UA16", - "R_SPARC_UA32", - "R_SPARC_UA64", - "R_SPARC_WDISP16", - "R_SPARC_WDISP19", - "R_SPARC_WDISP22", - "R_SPARC_WDISP30", - "R_SPARC_WPLT30", - "R_SYM32", - "R_SYM64", - "R_TYPE32", - "R_TYPE64", - "R_X86_64", - "R_X86_64_16", - "R_X86_64_32", - "R_X86_64_32S", - "R_X86_64_64", - "R_X86_64_8", - "R_X86_64_COPY", - "R_X86_64_DTPMOD64", - "R_X86_64_DTPOFF32", - "R_X86_64_DTPOFF64", - "R_X86_64_GLOB_DAT", - "R_X86_64_GOT32", - "R_X86_64_GOT64", - "R_X86_64_GOTOFF64", - "R_X86_64_GOTPC32", - "R_X86_64_GOTPC32_TLSDESC", - "R_X86_64_GOTPC64", - "R_X86_64_GOTPCREL", - "R_X86_64_GOTPCREL64", - "R_X86_64_GOTPCRELX", - "R_X86_64_GOTPLT64", - "R_X86_64_GOTTPOFF", - "R_X86_64_IRELATIVE", - "R_X86_64_JMP_SLOT", - "R_X86_64_NONE", - "R_X86_64_PC16", - "R_X86_64_PC32", - "R_X86_64_PC32_BND", - "R_X86_64_PC64", - "R_X86_64_PC8", - "R_X86_64_PLT32", - "R_X86_64_PLT32_BND", - "R_X86_64_PLTOFF64", - "R_X86_64_RELATIVE", - "R_X86_64_RELATIVE64", - "R_X86_64_REX_GOTPCRELX", - "R_X86_64_SIZE32", - "R_X86_64_SIZE64", - "R_X86_64_TLSDESC", - "R_X86_64_TLSDESC_CALL", - "R_X86_64_TLSGD", - "R_X86_64_TLSLD", - "R_X86_64_TPOFF32", - "R_X86_64_TPOFF64", - "Rel32", - "Rel64", - "Rela32", - "Rela64", - "SHF_ALLOC", - "SHF_COMPRESSED", - "SHF_EXECINSTR", - "SHF_GROUP", - "SHF_INFO_LINK", - "SHF_LINK_ORDER", - "SHF_MASKOS", - "SHF_MASKPROC", - "SHF_MERGE", - "SHF_OS_NONCONFORMING", - "SHF_STRINGS", - "SHF_TLS", - "SHF_WRITE", - "SHN_ABS", - "SHN_COMMON", - "SHN_HIOS", - "SHN_HIPROC", - "SHN_HIRESERVE", - "SHN_LOOS", - "SHN_LOPROC", - "SHN_LORESERVE", - "SHN_UNDEF", - "SHN_XINDEX", - "SHT_DYNAMIC", - "SHT_DYNSYM", - "SHT_FINI_ARRAY", - "SHT_GNU_ATTRIBUTES", - "SHT_GNU_HASH", - "SHT_GNU_LIBLIST", - "SHT_GNU_VERDEF", - "SHT_GNU_VERNEED", - "SHT_GNU_VERSYM", - "SHT_GROUP", - "SHT_HASH", - "SHT_HIOS", - "SHT_HIPROC", - "SHT_HIUSER", - "SHT_INIT_ARRAY", - "SHT_LOOS", - "SHT_LOPROC", - "SHT_LOUSER", - "SHT_MIPS_ABIFLAGS", - "SHT_NOBITS", - "SHT_NOTE", - "SHT_NULL", - "SHT_PREINIT_ARRAY", - "SHT_PROGBITS", - "SHT_REL", - "SHT_RELA", - "SHT_SHLIB", - "SHT_STRTAB", - "SHT_SYMTAB", - "SHT_SYMTAB_SHNDX", - "STB_GLOBAL", - "STB_HIOS", - "STB_HIPROC", - "STB_LOCAL", - "STB_LOOS", - "STB_LOPROC", - "STB_WEAK", - "STT_COMMON", - "STT_FILE", - "STT_FUNC", - "STT_HIOS", - "STT_HIPROC", - "STT_LOOS", - "STT_LOPROC", - "STT_NOTYPE", - "STT_OBJECT", - "STT_SECTION", - "STT_TLS", - "STV_DEFAULT", - "STV_HIDDEN", - "STV_INTERNAL", - "STV_PROTECTED", - "ST_BIND", - "ST_INFO", - "ST_TYPE", - "ST_VISIBILITY", - "Section", - "Section32", - "Section64", - "SectionFlag", - "SectionHeader", - "SectionIndex", - "SectionType", - "Sym32", - "Sym32Size", - "Sym64", - "Sym64Size", - "SymBind", - "SymType", - "SymVis", - "Symbol", - "Type", - "Version", - }, - "debug/gosym": { - "DecodingError", - "Func", - "LineTable", - "NewLineTable", - "NewTable", - "Obj", - "Sym", - "Table", - "UnknownFileError", - "UnknownLineError", - }, - "debug/macho": { - "ARM64_RELOC_ADDEND", - "ARM64_RELOC_BRANCH26", - "ARM64_RELOC_GOT_LOAD_PAGE21", - "ARM64_RELOC_GOT_LOAD_PAGEOFF12", - "ARM64_RELOC_PAGE21", - "ARM64_RELOC_PAGEOFF12", - "ARM64_RELOC_POINTER_TO_GOT", - "ARM64_RELOC_SUBTRACTOR", - "ARM64_RELOC_TLVP_LOAD_PAGE21", - "ARM64_RELOC_TLVP_LOAD_PAGEOFF12", - "ARM64_RELOC_UNSIGNED", - "ARM_RELOC_BR24", - "ARM_RELOC_HALF", - "ARM_RELOC_HALF_SECTDIFF", - "ARM_RELOC_LOCAL_SECTDIFF", - "ARM_RELOC_PAIR", - "ARM_RELOC_PB_LA_PTR", - "ARM_RELOC_SECTDIFF", - "ARM_RELOC_VANILLA", - "ARM_THUMB_32BIT_BRANCH", - "ARM_THUMB_RELOC_BR22", - "Cpu", - "Cpu386", - "CpuAmd64", - "CpuArm", - "CpuArm64", - "CpuPpc", - "CpuPpc64", - "Dylib", - "DylibCmd", - "Dysymtab", - "DysymtabCmd", - "ErrNotFat", - "FatArch", - "FatArchHeader", - "FatFile", - "File", - "FileHeader", - "FlagAllModsBound", - "FlagAllowStackExecution", - "FlagAppExtensionSafe", - "FlagBindAtLoad", - "FlagBindsToWeak", - "FlagCanonical", - "FlagDeadStrippableDylib", - "FlagDyldLink", - "FlagForceFlat", - "FlagHasTLVDescriptors", - "FlagIncrLink", - "FlagLazyInit", - "FlagNoFixPrebinding", - "FlagNoHeapExecution", - "FlagNoMultiDefs", - "FlagNoReexportedDylibs", - "FlagNoUndefs", - "FlagPIE", - "FlagPrebindable", - "FlagPrebound", - "FlagRootSafe", - "FlagSetuidSafe", - "FlagSplitSegs", - "FlagSubsectionsViaSymbols", - "FlagTwoLevel", - "FlagWeakDefines", - "FormatError", - "GENERIC_RELOC_LOCAL_SECTDIFF", - "GENERIC_RELOC_PAIR", - "GENERIC_RELOC_PB_LA_PTR", - "GENERIC_RELOC_SECTDIFF", - "GENERIC_RELOC_TLV", - "GENERIC_RELOC_VANILLA", - "Load", - "LoadBytes", - "LoadCmd", - "LoadCmdDylib", - "LoadCmdDylinker", - "LoadCmdDysymtab", - "LoadCmdRpath", - "LoadCmdSegment", - "LoadCmdSegment64", - "LoadCmdSymtab", - "LoadCmdThread", - "LoadCmdUnixThread", - "Magic32", - "Magic64", - "MagicFat", - "NewFatFile", - "NewFile", - "Nlist32", - "Nlist64", - "Open", - "OpenFat", - "Regs386", - "RegsAMD64", - "Reloc", - "RelocTypeARM", - "RelocTypeARM64", - "RelocTypeGeneric", - "RelocTypeX86_64", - "Rpath", - "RpathCmd", - "Section", - "Section32", - "Section64", - "SectionHeader", - "Segment", - "Segment32", - "Segment64", - "SegmentHeader", - "Symbol", - "Symtab", - "SymtabCmd", - "Thread", - "Type", - "TypeBundle", - "TypeDylib", - "TypeExec", - "TypeObj", - "X86_64_RELOC_BRANCH", - "X86_64_RELOC_GOT", - "X86_64_RELOC_GOT_LOAD", - "X86_64_RELOC_SIGNED", - "X86_64_RELOC_SIGNED_1", - "X86_64_RELOC_SIGNED_2", - "X86_64_RELOC_SIGNED_4", - "X86_64_RELOC_SUBTRACTOR", - "X86_64_RELOC_TLV", - "X86_64_RELOC_UNSIGNED", - }, - "debug/pe": { - "COFFSymbol", - "COFFSymbolAuxFormat5", - "COFFSymbolSize", - "DataDirectory", - "File", - "FileHeader", - "FormatError", - "IMAGE_COMDAT_SELECT_ANY", - "IMAGE_COMDAT_SELECT_ASSOCIATIVE", - "IMAGE_COMDAT_SELECT_EXACT_MATCH", - "IMAGE_COMDAT_SELECT_LARGEST", - "IMAGE_COMDAT_SELECT_NODUPLICATES", - "IMAGE_COMDAT_SELECT_SAME_SIZE", - "IMAGE_DIRECTORY_ENTRY_ARCHITECTURE", - "IMAGE_DIRECTORY_ENTRY_BASERELOC", - "IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT", - "IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR", - "IMAGE_DIRECTORY_ENTRY_DEBUG", - "IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT", - "IMAGE_DIRECTORY_ENTRY_EXCEPTION", - "IMAGE_DIRECTORY_ENTRY_EXPORT", - "IMAGE_DIRECTORY_ENTRY_GLOBALPTR", - "IMAGE_DIRECTORY_ENTRY_IAT", - "IMAGE_DIRECTORY_ENTRY_IMPORT", - "IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG", - "IMAGE_DIRECTORY_ENTRY_RESOURCE", - "IMAGE_DIRECTORY_ENTRY_SECURITY", - "IMAGE_DIRECTORY_ENTRY_TLS", - "IMAGE_DLLCHARACTERISTICS_APPCONTAINER", - "IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE", - "IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY", - "IMAGE_DLLCHARACTERISTICS_GUARD_CF", - "IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA", - "IMAGE_DLLCHARACTERISTICS_NO_BIND", - "IMAGE_DLLCHARACTERISTICS_NO_ISOLATION", - "IMAGE_DLLCHARACTERISTICS_NO_SEH", - "IMAGE_DLLCHARACTERISTICS_NX_COMPAT", - "IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE", - "IMAGE_DLLCHARACTERISTICS_WDM_DRIVER", - "IMAGE_FILE_32BIT_MACHINE", - "IMAGE_FILE_AGGRESIVE_WS_TRIM", - "IMAGE_FILE_BYTES_REVERSED_HI", - "IMAGE_FILE_BYTES_REVERSED_LO", - "IMAGE_FILE_DEBUG_STRIPPED", - "IMAGE_FILE_DLL", - "IMAGE_FILE_EXECUTABLE_IMAGE", - "IMAGE_FILE_LARGE_ADDRESS_AWARE", - "IMAGE_FILE_LINE_NUMS_STRIPPED", - "IMAGE_FILE_LOCAL_SYMS_STRIPPED", - "IMAGE_FILE_MACHINE_AM33", - "IMAGE_FILE_MACHINE_AMD64", - "IMAGE_FILE_MACHINE_ARM", - "IMAGE_FILE_MACHINE_ARM64", - "IMAGE_FILE_MACHINE_ARMNT", - "IMAGE_FILE_MACHINE_EBC", - "IMAGE_FILE_MACHINE_I386", - "IMAGE_FILE_MACHINE_IA64", - "IMAGE_FILE_MACHINE_LOONGARCH32", - "IMAGE_FILE_MACHINE_LOONGARCH64", - "IMAGE_FILE_MACHINE_M32R", - "IMAGE_FILE_MACHINE_MIPS16", - "IMAGE_FILE_MACHINE_MIPSFPU", - "IMAGE_FILE_MACHINE_MIPSFPU16", - "IMAGE_FILE_MACHINE_POWERPC", - "IMAGE_FILE_MACHINE_POWERPCFP", - "IMAGE_FILE_MACHINE_R4000", - "IMAGE_FILE_MACHINE_RISCV128", - "IMAGE_FILE_MACHINE_RISCV32", - "IMAGE_FILE_MACHINE_RISCV64", - "IMAGE_FILE_MACHINE_SH3", - "IMAGE_FILE_MACHINE_SH3DSP", - "IMAGE_FILE_MACHINE_SH4", - "IMAGE_FILE_MACHINE_SH5", - "IMAGE_FILE_MACHINE_THUMB", - "IMAGE_FILE_MACHINE_UNKNOWN", - "IMAGE_FILE_MACHINE_WCEMIPSV2", - "IMAGE_FILE_NET_RUN_FROM_SWAP", - "IMAGE_FILE_RELOCS_STRIPPED", - "IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP", - "IMAGE_FILE_SYSTEM", - "IMAGE_FILE_UP_SYSTEM_ONLY", - "IMAGE_SCN_CNT_CODE", - "IMAGE_SCN_CNT_INITIALIZED_DATA", - "IMAGE_SCN_CNT_UNINITIALIZED_DATA", - "IMAGE_SCN_LNK_COMDAT", - "IMAGE_SCN_MEM_DISCARDABLE", - "IMAGE_SCN_MEM_EXECUTE", - "IMAGE_SCN_MEM_READ", - "IMAGE_SCN_MEM_WRITE", - "IMAGE_SUBSYSTEM_EFI_APPLICATION", - "IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER", - "IMAGE_SUBSYSTEM_EFI_ROM", - "IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER", - "IMAGE_SUBSYSTEM_NATIVE", - "IMAGE_SUBSYSTEM_NATIVE_WINDOWS", - "IMAGE_SUBSYSTEM_OS2_CUI", - "IMAGE_SUBSYSTEM_POSIX_CUI", - "IMAGE_SUBSYSTEM_UNKNOWN", - "IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION", - "IMAGE_SUBSYSTEM_WINDOWS_CE_GUI", - "IMAGE_SUBSYSTEM_WINDOWS_CUI", - "IMAGE_SUBSYSTEM_WINDOWS_GUI", - "IMAGE_SUBSYSTEM_XBOX", - "ImportDirectory", - "NewFile", - "Open", - "OptionalHeader32", - "OptionalHeader64", - "Reloc", - "Section", - "SectionHeader", - "SectionHeader32", - "StringTable", - "Symbol", - }, - "debug/plan9obj": { - "ErrNoSymbols", - "File", - "FileHeader", - "Magic386", - "Magic64", - "MagicAMD64", - "MagicARM", - "NewFile", - "Open", - "Section", - "SectionHeader", - "Sym", - }, - "embed": { - "FS", - }, - "encoding": { - "BinaryMarshaler", - "BinaryUnmarshaler", - "TextMarshaler", - "TextUnmarshaler", - }, - "encoding/ascii85": { - "CorruptInputError", - "Decode", - "Encode", - "MaxEncodedLen", - "NewDecoder", - "NewEncoder", - }, - "encoding/asn1": { - "BitString", - "ClassApplication", - "ClassContextSpecific", - "ClassPrivate", - "ClassUniversal", - "Enumerated", - "Flag", - "Marshal", - "MarshalWithParams", - "NullBytes", - "NullRawValue", - "ObjectIdentifier", - "RawContent", - "RawValue", - "StructuralError", - "SyntaxError", - "TagBMPString", - "TagBitString", - "TagBoolean", - "TagEnum", - "TagGeneralString", - "TagGeneralizedTime", - "TagIA5String", - "TagInteger", - "TagNull", - "TagNumericString", - "TagOID", - "TagOctetString", - "TagPrintableString", - "TagSequence", - "TagSet", - "TagT61String", - "TagUTCTime", - "TagUTF8String", - "Unmarshal", - "UnmarshalWithParams", - }, - "encoding/base32": { - "CorruptInputError", - "Encoding", - "HexEncoding", - "NewDecoder", - "NewEncoder", - "NewEncoding", - "NoPadding", - "StdEncoding", - "StdPadding", - }, - "encoding/base64": { - "CorruptInputError", - "Encoding", - "NewDecoder", - "NewEncoder", - "NewEncoding", - "NoPadding", - "RawStdEncoding", - "RawURLEncoding", - "StdEncoding", - "StdPadding", - "URLEncoding", - }, - "encoding/binary": { - "AppendByteOrder", - "AppendUvarint", - "AppendVarint", - "BigEndian", - "ByteOrder", - "LittleEndian", - "MaxVarintLen16", - "MaxVarintLen32", - "MaxVarintLen64", - "PutUvarint", - "PutVarint", - "Read", - "ReadUvarint", - "ReadVarint", - "Size", - "Uvarint", - "Varint", - "Write", - }, - "encoding/csv": { - "ErrBareQuote", - "ErrFieldCount", - "ErrQuote", - "ErrTrailingComma", - "NewReader", - "NewWriter", - "ParseError", - "Reader", - "Writer", - }, - "encoding/gob": { - "CommonType", - "Decoder", - "Encoder", - "GobDecoder", - "GobEncoder", - "NewDecoder", - "NewEncoder", - "Register", - "RegisterName", - }, - "encoding/hex": { - "Decode", - "DecodeString", - "DecodedLen", - "Dump", - "Dumper", - "Encode", - "EncodeToString", - "EncodedLen", - "ErrLength", - "InvalidByteError", - "NewDecoder", - "NewEncoder", - }, - "encoding/json": { - "Compact", - "Decoder", - "Delim", - "Encoder", - "HTMLEscape", - "Indent", - "InvalidUTF8Error", - "InvalidUnmarshalError", - "Marshal", - "MarshalIndent", - "Marshaler", - "MarshalerError", - "NewDecoder", - "NewEncoder", - "Number", - "RawMessage", - "SyntaxError", - "Token", - "Unmarshal", - "UnmarshalFieldError", - "UnmarshalTypeError", - "Unmarshaler", - "UnsupportedTypeError", - "UnsupportedValueError", - "Valid", - }, - "encoding/pem": { - "Block", - "Decode", - "Encode", - "EncodeToMemory", - }, - "encoding/xml": { - "Attr", - "CharData", - "Comment", - "CopyToken", - "Decoder", - "Directive", - "Encoder", - "EndElement", - "Escape", - "EscapeText", - "HTMLAutoClose", - "HTMLEntity", - "Header", - "Marshal", - "MarshalIndent", - "Marshaler", - "MarshalerAttr", - "Name", - "NewDecoder", - "NewEncoder", - "NewTokenDecoder", - "ProcInst", - "StartElement", - "SyntaxError", - "TagPathError", - "Token", - "TokenReader", - "Unmarshal", - "UnmarshalError", - "Unmarshaler", - "UnmarshalerAttr", - "UnsupportedTypeError", - }, - "errors": { - "As", - "Is", - "Join", - "New", - "Unwrap", - }, - "expvar": { - "Do", - "Float", - "Func", - "Get", - "Handler", - "Int", - "KeyValue", - "Map", - "NewFloat", - "NewInt", - "NewMap", - "NewString", - "Publish", - "String", - "Var", - }, - "flag": { - "Arg", - "Args", - "Bool", - "BoolVar", - "CommandLine", - "ContinueOnError", - "Duration", - "DurationVar", - "ErrHelp", - "ErrorHandling", - "ExitOnError", - "Flag", - "FlagSet", - "Float64", - "Float64Var", - "Func", - "Getter", - "Int", - "Int64", - "Int64Var", - "IntVar", - "Lookup", - "NArg", - "NFlag", - "NewFlagSet", - "PanicOnError", - "Parse", - "Parsed", - "PrintDefaults", - "Set", - "String", - "StringVar", - "TextVar", - "Uint", - "Uint64", - "Uint64Var", - "UintVar", - "UnquoteUsage", - "Usage", - "Value", - "Var", - "Visit", - "VisitAll", - }, - "fmt": { - "Append", - "Appendf", - "Appendln", - "Errorf", - "FormatString", - "Formatter", - "Fprint", - "Fprintf", - "Fprintln", - "Fscan", - "Fscanf", - "Fscanln", - "GoStringer", - "Print", - "Printf", - "Println", - "Scan", - "ScanState", - "Scanf", - "Scanln", - "Scanner", - "Sprint", - "Sprintf", - "Sprintln", - "Sscan", - "Sscanf", - "Sscanln", - "State", - "Stringer", - }, - "go/ast": { - "ArrayType", - "AssignStmt", - "Bad", - "BadDecl", - "BadExpr", - "BadStmt", - "BasicLit", - "BinaryExpr", - "BlockStmt", - "BranchStmt", - "CallExpr", - "CaseClause", - "ChanDir", - "ChanType", - "CommClause", - "Comment", - "CommentGroup", - "CommentMap", - "CompositeLit", - "Con", - "Decl", - "DeclStmt", - "DeferStmt", - "Ellipsis", - "EmptyStmt", - "Expr", - "ExprStmt", - "Field", - "FieldFilter", - "FieldList", - "File", - "FileExports", - "Filter", - "FilterDecl", - "FilterFile", - "FilterFuncDuplicates", - "FilterImportDuplicates", - "FilterPackage", - "FilterUnassociatedComments", - "ForStmt", - "Fprint", - "Fun", - "FuncDecl", - "FuncLit", - "FuncType", - "GenDecl", - "GoStmt", - "Ident", - "IfStmt", - "ImportSpec", - "Importer", - "IncDecStmt", - "IndexExpr", - "IndexListExpr", - "Inspect", - "InterfaceType", - "IsExported", - "KeyValueExpr", - "LabeledStmt", - "Lbl", - "MapType", - "MergeMode", - "MergePackageFiles", - "NewCommentMap", - "NewIdent", - "NewObj", - "NewPackage", - "NewScope", - "Node", - "NotNilFilter", - "ObjKind", - "Object", - "Package", - "PackageExports", - "ParenExpr", - "Pkg", - "Print", - "RECV", - "RangeStmt", - "ReturnStmt", - "SEND", - "Scope", - "SelectStmt", - "SelectorExpr", - "SendStmt", - "SliceExpr", - "SortImports", - "Spec", - "StarExpr", - "Stmt", - "StructType", - "SwitchStmt", - "Typ", - "TypeAssertExpr", - "TypeSpec", - "TypeSwitchStmt", - "UnaryExpr", - "ValueSpec", - "Var", - "Visitor", - "Walk", - }, - "go/build": { - "AllowBinary", - "ArchChar", - "Context", - "Default", - "FindOnly", - "IgnoreVendor", - "Import", - "ImportComment", - "ImportDir", - "ImportMode", - "IsLocalImport", - "MultiplePackageError", - "NoGoError", - "Package", - "ToolDir", - }, - "go/build/constraint": { - "AndExpr", - "Expr", - "IsGoBuild", - "IsPlusBuild", - "NotExpr", - "OrExpr", - "Parse", - "PlusBuildLines", - "SyntaxError", - "TagExpr", - }, - "go/constant": { - "BinaryOp", - "BitLen", - "Bool", - "BoolVal", - "Bytes", - "Compare", - "Complex", - "Denom", - "Float", - "Float32Val", - "Float64Val", - "Imag", - "Int", - "Int64Val", - "Kind", - "Make", - "MakeBool", - "MakeFloat64", - "MakeFromBytes", - "MakeFromLiteral", - "MakeImag", - "MakeInt64", - "MakeString", - "MakeUint64", - "MakeUnknown", - "Num", - "Real", - "Shift", - "Sign", - "String", - "StringVal", - "ToComplex", - "ToFloat", - "ToInt", - "Uint64Val", - "UnaryOp", - "Unknown", - "Val", - "Value", - }, - "go/doc": { - "AllDecls", - "AllMethods", - "Example", - "Examples", - "Filter", - "Func", - "IllegalPrefixes", - "IsPredeclared", - "Mode", - "New", - "NewFromFiles", - "Note", - "Package", - "PreserveAST", - "Synopsis", - "ToHTML", - "ToText", - "Type", - "Value", - }, - "go/doc/comment": { - "Block", - "Code", - "DefaultLookupPackage", - "Doc", - "DocLink", - "Heading", - "Italic", - "Link", - "LinkDef", - "List", - "ListItem", - "Paragraph", - "Parser", - "Plain", - "Printer", - "Text", - }, - "go/format": { - "Node", - "Source", - }, - "go/importer": { - "Default", - "For", - "ForCompiler", - "Lookup", - }, - "go/parser": { - "AllErrors", - "DeclarationErrors", - "ImportsOnly", - "Mode", - "PackageClauseOnly", - "ParseComments", - "ParseDir", - "ParseExpr", - "ParseExprFrom", - "ParseFile", - "SkipObjectResolution", - "SpuriousErrors", - "Trace", - }, - "go/printer": { - "CommentedNode", - "Config", - "Fprint", - "Mode", - "RawFormat", - "SourcePos", - "TabIndent", - "UseSpaces", - }, - "go/scanner": { - "Error", - "ErrorHandler", - "ErrorList", - "Mode", - "PrintError", - "ScanComments", - "Scanner", - }, - "go/token": { - "ADD", - "ADD_ASSIGN", - "AND", - "AND_ASSIGN", - "AND_NOT", - "AND_NOT_ASSIGN", - "ARROW", - "ASSIGN", - "BREAK", - "CASE", - "CHAN", - "CHAR", - "COLON", - "COMMA", - "COMMENT", - "CONST", - "CONTINUE", - "DEC", - "DEFAULT", - "DEFER", - "DEFINE", - "ELLIPSIS", - "ELSE", - "EOF", - "EQL", - "FALLTHROUGH", - "FLOAT", - "FOR", - "FUNC", - "File", - "FileSet", - "GEQ", - "GO", - "GOTO", - "GTR", - "HighestPrec", - "IDENT", - "IF", - "ILLEGAL", - "IMAG", - "IMPORT", - "INC", - "INT", - "INTERFACE", - "IsExported", - "IsIdentifier", - "IsKeyword", - "LAND", - "LBRACE", - "LBRACK", - "LEQ", - "LOR", - "LPAREN", - "LSS", - "Lookup", - "LowestPrec", - "MAP", - "MUL", - "MUL_ASSIGN", - "NEQ", - "NOT", - "NewFileSet", - "NoPos", - "OR", - "OR_ASSIGN", - "PACKAGE", - "PERIOD", - "Pos", - "Position", - "QUO", - "QUO_ASSIGN", - "RANGE", - "RBRACE", - "RBRACK", - "REM", - "REM_ASSIGN", - "RETURN", - "RPAREN", - "SELECT", - "SEMICOLON", - "SHL", - "SHL_ASSIGN", - "SHR", - "SHR_ASSIGN", - "STRING", - "STRUCT", - "SUB", - "SUB_ASSIGN", - "SWITCH", - "TILDE", - "TYPE", - "Token", - "UnaryPrec", - "VAR", - "XOR", - "XOR_ASSIGN", - }, - "go/types": { - "ArgumentError", - "Array", - "AssertableTo", - "AssignableTo", - "Basic", - "BasicInfo", - "BasicKind", - "Bool", - "Builtin", - "Byte", - "Chan", - "ChanDir", - "CheckExpr", - "Checker", - "Comparable", - "Complex128", - "Complex64", - "Config", - "Const", - "Context", - "ConvertibleTo", - "DefPredeclaredTestFuncs", - "Default", - "Error", - "Eval", - "ExprString", - "FieldVal", - "Float32", - "Float64", - "Func", - "Id", - "Identical", - "IdenticalIgnoreTags", - "Implements", - "ImportMode", - "Importer", - "ImporterFrom", - "Info", - "Initializer", - "Instance", - "Instantiate", - "Int", - "Int16", - "Int32", - "Int64", - "Int8", - "Interface", - "Invalid", - "IsBoolean", - "IsComplex", - "IsConstType", - "IsFloat", - "IsInteger", - "IsInterface", - "IsNumeric", - "IsOrdered", - "IsString", - "IsUnsigned", - "IsUntyped", - "Label", - "LookupFieldOrMethod", - "Map", - "MethodExpr", - "MethodSet", - "MethodVal", - "MissingMethod", - "Named", - "NewArray", - "NewChan", - "NewChecker", - "NewConst", - "NewContext", - "NewField", - "NewFunc", - "NewInterface", - "NewInterfaceType", - "NewLabel", - "NewMap", - "NewMethodSet", - "NewNamed", - "NewPackage", - "NewParam", - "NewPkgName", - "NewPointer", - "NewScope", - "NewSignature", - "NewSignatureType", - "NewSlice", - "NewStruct", - "NewTerm", - "NewTuple", - "NewTypeName", - "NewTypeParam", - "NewUnion", - "NewVar", - "Nil", - "Object", - "ObjectString", - "Package", - "PkgName", - "Pointer", - "Qualifier", - "RecvOnly", - "RelativeTo", - "Rune", - "Satisfies", - "Scope", - "Selection", - "SelectionKind", - "SelectionString", - "SendOnly", - "SendRecv", - "Signature", - "Sizes", - "SizesFor", - "Slice", - "StdSizes", - "String", - "Struct", - "Term", - "Tuple", - "Typ", - "Type", - "TypeAndValue", - "TypeList", - "TypeName", - "TypeParam", - "TypeParamList", - "TypeString", - "Uint", - "Uint16", - "Uint32", - "Uint64", - "Uint8", - "Uintptr", - "Union", - "Universe", - "Unsafe", - "UnsafePointer", - "UntypedBool", - "UntypedComplex", - "UntypedFloat", - "UntypedInt", - "UntypedNil", - "UntypedRune", - "UntypedString", - "Var", - "WriteExpr", - "WriteSignature", - "WriteType", - }, - "hash": { - "Hash", - "Hash32", - "Hash64", - }, - "hash/adler32": { - "Checksum", - "New", - "Size", - }, - "hash/crc32": { - "Castagnoli", - "Checksum", - "ChecksumIEEE", - "IEEE", - "IEEETable", - "Koopman", - "MakeTable", - "New", - "NewIEEE", - "Size", - "Table", - "Update", - }, - "hash/crc64": { - "Checksum", - "ECMA", - "ISO", - "MakeTable", - "New", - "Size", - "Table", - "Update", - }, - "hash/fnv": { - "New128", - "New128a", - "New32", - "New32a", - "New64", - "New64a", - }, - "hash/maphash": { - "Bytes", - "Hash", - "MakeSeed", - "Seed", - "String", - }, - "html": { - "EscapeString", - "UnescapeString", - }, - "html/template": { - "CSS", - "ErrAmbigContext", - "ErrBadHTML", - "ErrBranchEnd", - "ErrEndContext", - "ErrNoSuchTemplate", - "ErrOutputContext", - "ErrPartialCharset", - "ErrPartialEscape", - "ErrPredefinedEscaper", - "ErrRangeLoopReentry", - "ErrSlashAmbig", - "Error", - "ErrorCode", - "FuncMap", - "HTML", - "HTMLAttr", - "HTMLEscape", - "HTMLEscapeString", - "HTMLEscaper", - "IsTrue", - "JS", - "JSEscape", - "JSEscapeString", - "JSEscaper", - "JSStr", - "Must", - "New", - "OK", - "ParseFS", - "ParseFiles", - "ParseGlob", - "Srcset", - "Template", - "URL", - "URLQueryEscaper", - }, - "image": { - "Alpha", - "Alpha16", - "Black", - "CMYK", - "Config", - "Decode", - "DecodeConfig", - "ErrFormat", - "Gray", - "Gray16", - "Image", - "NRGBA", - "NRGBA64", - "NYCbCrA", - "NewAlpha", - "NewAlpha16", - "NewCMYK", - "NewGray", - "NewGray16", - "NewNRGBA", - "NewNRGBA64", - "NewNYCbCrA", - "NewPaletted", - "NewRGBA", - "NewRGBA64", - "NewUniform", - "NewYCbCr", - "Opaque", - "Paletted", - "PalettedImage", - "Point", - "Pt", - "RGBA", - "RGBA64", - "RGBA64Image", - "Rect", - "Rectangle", - "RegisterFormat", - "Transparent", - "Uniform", - "White", - "YCbCr", - "YCbCrSubsampleRatio", - "YCbCrSubsampleRatio410", - "YCbCrSubsampleRatio411", - "YCbCrSubsampleRatio420", - "YCbCrSubsampleRatio422", - "YCbCrSubsampleRatio440", - "YCbCrSubsampleRatio444", - "ZP", - "ZR", - }, - "image/color": { - "Alpha", - "Alpha16", - "Alpha16Model", - "AlphaModel", - "Black", - "CMYK", - "CMYKModel", - "CMYKToRGB", - "Color", - "Gray", - "Gray16", - "Gray16Model", - "GrayModel", - "Model", - "ModelFunc", - "NRGBA", - "NRGBA64", - "NRGBA64Model", - "NRGBAModel", - "NYCbCrA", - "NYCbCrAModel", - "Opaque", - "Palette", - "RGBA", - "RGBA64", - "RGBA64Model", - "RGBAModel", - "RGBToCMYK", - "RGBToYCbCr", - "Transparent", - "White", - "YCbCr", - "YCbCrModel", - "YCbCrToRGB", - }, - "image/color/palette": { - "Plan9", - "WebSafe", - }, - "image/draw": { - "Draw", - "DrawMask", - "Drawer", - "FloydSteinberg", - "Image", - "Op", - "Over", - "Quantizer", - "RGBA64Image", - "Src", - }, - "image/gif": { - "Decode", - "DecodeAll", - "DecodeConfig", - "DisposalBackground", - "DisposalNone", - "DisposalPrevious", - "Encode", - "EncodeAll", - "GIF", - "Options", - }, - "image/jpeg": { - "Decode", - "DecodeConfig", - "DefaultQuality", - "Encode", - "FormatError", - "Options", - "Reader", - "UnsupportedError", - }, - "image/png": { - "BestCompression", - "BestSpeed", - "CompressionLevel", - "Decode", - "DecodeConfig", - "DefaultCompression", - "Encode", - "Encoder", - "EncoderBuffer", - "EncoderBufferPool", - "FormatError", - "NoCompression", - "UnsupportedError", - }, - "index/suffixarray": { - "Index", - "New", - }, - "io": { - "ByteReader", - "ByteScanner", - "ByteWriter", - "Closer", - "Copy", - "CopyBuffer", - "CopyN", - "Discard", - "EOF", - "ErrClosedPipe", - "ErrNoProgress", - "ErrShortBuffer", - "ErrShortWrite", - "ErrUnexpectedEOF", - "LimitReader", - "LimitedReader", - "MultiReader", - "MultiWriter", - "NewOffsetWriter", - "NewSectionReader", - "NopCloser", - "OffsetWriter", - "Pipe", - "PipeReader", - "PipeWriter", - "ReadAll", - "ReadAtLeast", - "ReadCloser", - "ReadFull", - "ReadSeekCloser", - "ReadSeeker", - "ReadWriteCloser", - "ReadWriteSeeker", - "ReadWriter", - "Reader", - "ReaderAt", - "ReaderFrom", - "RuneReader", - "RuneScanner", - "SectionReader", - "SeekCurrent", - "SeekEnd", - "SeekStart", - "Seeker", - "StringWriter", - "TeeReader", - "WriteCloser", - "WriteSeeker", - "WriteString", - "Writer", - "WriterAt", - "WriterTo", - }, - "io/fs": { - "DirEntry", - "ErrClosed", - "ErrExist", - "ErrInvalid", - "ErrNotExist", - "ErrPermission", - "FS", - "File", - "FileInfo", - "FileInfoToDirEntry", - "FileMode", - "Glob", - "GlobFS", - "ModeAppend", - "ModeCharDevice", - "ModeDevice", - "ModeDir", - "ModeExclusive", - "ModeIrregular", - "ModeNamedPipe", - "ModePerm", - "ModeSetgid", - "ModeSetuid", - "ModeSocket", - "ModeSticky", - "ModeSymlink", - "ModeTemporary", - "ModeType", - "PathError", - "ReadDir", - "ReadDirFS", - "ReadDirFile", - "ReadFile", - "ReadFileFS", - "SkipAll", - "SkipDir", - "Stat", - "StatFS", - "Sub", - "SubFS", - "ValidPath", - "WalkDir", - "WalkDirFunc", - }, - "io/ioutil": { - "Discard", - "NopCloser", - "ReadAll", - "ReadDir", - "ReadFile", - "TempDir", - "TempFile", - "WriteFile", - }, - "log": { - "Default", - "Fatal", - "Fatalf", - "Fatalln", - "Flags", - "LUTC", - "Ldate", - "Llongfile", - "Lmicroseconds", - "Lmsgprefix", - "Logger", - "Lshortfile", - "LstdFlags", - "Ltime", - "New", - "Output", - "Panic", - "Panicf", - "Panicln", - "Prefix", - "Print", - "Printf", - "Println", - "SetFlags", - "SetOutput", - "SetPrefix", - "Writer", - }, - "log/syslog": { - "Dial", - "LOG_ALERT", - "LOG_AUTH", - "LOG_AUTHPRIV", - "LOG_CRIT", - "LOG_CRON", - "LOG_DAEMON", - "LOG_DEBUG", - "LOG_EMERG", - "LOG_ERR", - "LOG_FTP", - "LOG_INFO", - "LOG_KERN", - "LOG_LOCAL0", - "LOG_LOCAL1", - "LOG_LOCAL2", - "LOG_LOCAL3", - "LOG_LOCAL4", - "LOG_LOCAL5", - "LOG_LOCAL6", - "LOG_LOCAL7", - "LOG_LPR", - "LOG_MAIL", - "LOG_NEWS", - "LOG_NOTICE", - "LOG_SYSLOG", - "LOG_USER", - "LOG_UUCP", - "LOG_WARNING", - "New", - "NewLogger", - "Priority", - "Writer", - }, - "math": { - "Abs", - "Acos", - "Acosh", - "Asin", - "Asinh", - "Atan", - "Atan2", - "Atanh", - "Cbrt", - "Ceil", - "Copysign", - "Cos", - "Cosh", - "Dim", - "E", - "Erf", - "Erfc", - "Erfcinv", - "Erfinv", - "Exp", - "Exp2", - "Expm1", - "FMA", - "Float32bits", - "Float32frombits", - "Float64bits", - "Float64frombits", - "Floor", - "Frexp", - "Gamma", - "Hypot", - "Ilogb", - "Inf", - "IsInf", - "IsNaN", - "J0", - "J1", - "Jn", - "Ldexp", - "Lgamma", - "Ln10", - "Ln2", - "Log", - "Log10", - "Log10E", - "Log1p", - "Log2", - "Log2E", - "Logb", - "Max", - "MaxFloat32", - "MaxFloat64", - "MaxInt", - "MaxInt16", - "MaxInt32", - "MaxInt64", - "MaxInt8", - "MaxUint", - "MaxUint16", - "MaxUint32", - "MaxUint64", - "MaxUint8", - "Min", - "MinInt", - "MinInt16", - "MinInt32", - "MinInt64", - "MinInt8", - "Mod", - "Modf", - "NaN", - "Nextafter", - "Nextafter32", - "Phi", - "Pi", - "Pow", - "Pow10", - "Remainder", - "Round", - "RoundToEven", - "Signbit", - "Sin", - "Sincos", - "Sinh", - "SmallestNonzeroFloat32", - "SmallestNonzeroFloat64", - "Sqrt", - "Sqrt2", - "SqrtE", - "SqrtPhi", - "SqrtPi", - "Tan", - "Tanh", - "Trunc", - "Y0", - "Y1", - "Yn", - }, - "math/big": { - "Above", - "Accuracy", - "AwayFromZero", - "Below", - "ErrNaN", - "Exact", - "Float", - "Int", - "Jacobi", - "MaxBase", - "MaxExp", - "MaxPrec", - "MinExp", - "NewFloat", - "NewInt", - "NewRat", - "ParseFloat", - "Rat", - "RoundingMode", - "ToNearestAway", - "ToNearestEven", - "ToNegativeInf", - "ToPositiveInf", - "ToZero", - "Word", - }, - "math/bits": { - "Add", - "Add32", - "Add64", - "Div", - "Div32", - "Div64", - "LeadingZeros", - "LeadingZeros16", - "LeadingZeros32", - "LeadingZeros64", - "LeadingZeros8", - "Len", - "Len16", - "Len32", - "Len64", - "Len8", - "Mul", - "Mul32", - "Mul64", - "OnesCount", - "OnesCount16", - "OnesCount32", - "OnesCount64", - "OnesCount8", - "Rem", - "Rem32", - "Rem64", - "Reverse", - "Reverse16", - "Reverse32", - "Reverse64", - "Reverse8", - "ReverseBytes", - "ReverseBytes16", - "ReverseBytes32", - "ReverseBytes64", - "RotateLeft", - "RotateLeft16", - "RotateLeft32", - "RotateLeft64", - "RotateLeft8", - "Sub", - "Sub32", - "Sub64", - "TrailingZeros", - "TrailingZeros16", - "TrailingZeros32", - "TrailingZeros64", - "TrailingZeros8", - "UintSize", - }, - "math/cmplx": { - "Abs", - "Acos", - "Acosh", - "Asin", - "Asinh", - "Atan", - "Atanh", - "Conj", - "Cos", - "Cosh", - "Cot", - "Exp", - "Inf", - "IsInf", - "IsNaN", - "Log", - "Log10", - "NaN", - "Phase", - "Polar", - "Pow", - "Rect", - "Sin", - "Sinh", - "Sqrt", - "Tan", - "Tanh", - }, - "math/rand": { - "ExpFloat64", - "Float32", - "Float64", - "Int", - "Int31", - "Int31n", - "Int63", - "Int63n", - "Intn", - "New", - "NewSource", - "NewZipf", - "NormFloat64", - "Perm", - "Rand", - "Read", - "Seed", - "Shuffle", - "Source", - "Source64", - "Uint32", - "Uint64", - "Zipf", - }, - "mime": { - "AddExtensionType", - "BEncoding", - "ErrInvalidMediaParameter", - "ExtensionsByType", - "FormatMediaType", - "ParseMediaType", - "QEncoding", - "TypeByExtension", - "WordDecoder", - "WordEncoder", - }, - "mime/multipart": { - "ErrMessageTooLarge", - "File", - "FileHeader", - "Form", - "NewReader", - "NewWriter", - "Part", - "Reader", - "Writer", - }, - "mime/quotedprintable": { - "NewReader", - "NewWriter", - "Reader", - "Writer", - }, - "net": { - "Addr", - "AddrError", - "Buffers", - "CIDRMask", - "Conn", - "DNSConfigError", - "DNSError", - "DefaultResolver", - "Dial", - "DialIP", - "DialTCP", - "DialTimeout", - "DialUDP", - "DialUnix", - "Dialer", - "ErrClosed", - "ErrWriteToConnected", - "Error", - "FileConn", - "FileListener", - "FilePacketConn", - "FlagBroadcast", - "FlagLoopback", - "FlagMulticast", - "FlagPointToPoint", - "FlagRunning", - "FlagUp", - "Flags", - "HardwareAddr", - "IP", - "IPAddr", - "IPConn", - "IPMask", - "IPNet", - "IPv4", - "IPv4Mask", - "IPv4allrouter", - "IPv4allsys", - "IPv4bcast", - "IPv4len", - "IPv4zero", - "IPv6interfacelocalallnodes", - "IPv6len", - "IPv6linklocalallnodes", - "IPv6linklocalallrouters", - "IPv6loopback", - "IPv6unspecified", - "IPv6zero", - "Interface", - "InterfaceAddrs", - "InterfaceByIndex", - "InterfaceByName", - "Interfaces", - "InvalidAddrError", - "JoinHostPort", - "Listen", - "ListenConfig", - "ListenIP", - "ListenMulticastUDP", - "ListenPacket", - "ListenTCP", - "ListenUDP", - "ListenUnix", - "ListenUnixgram", - "Listener", - "LookupAddr", - "LookupCNAME", - "LookupHost", - "LookupIP", - "LookupMX", - "LookupNS", - "LookupPort", - "LookupSRV", - "LookupTXT", - "MX", - "NS", - "OpError", - "PacketConn", - "ParseCIDR", - "ParseError", - "ParseIP", - "ParseMAC", - "Pipe", - "ResolveIPAddr", - "ResolveTCPAddr", - "ResolveUDPAddr", - "ResolveUnixAddr", - "Resolver", - "SRV", - "SplitHostPort", - "TCPAddr", - "TCPAddrFromAddrPort", - "TCPConn", - "TCPListener", - "UDPAddr", - "UDPAddrFromAddrPort", - "UDPConn", - "UnixAddr", - "UnixConn", - "UnixListener", - "UnknownNetworkError", - }, - "net/http": { - "AllowQuerySemicolons", - "CanonicalHeaderKey", - "Client", - "CloseNotifier", - "ConnState", - "Cookie", - "CookieJar", - "DefaultClient", - "DefaultMaxHeaderBytes", - "DefaultMaxIdleConnsPerHost", - "DefaultServeMux", - "DefaultTransport", - "DetectContentType", - "Dir", - "ErrAbortHandler", - "ErrBodyNotAllowed", - "ErrBodyReadAfterClose", - "ErrContentLength", - "ErrHandlerTimeout", - "ErrHeaderTooLong", - "ErrHijacked", - "ErrLineTooLong", - "ErrMissingBoundary", - "ErrMissingContentLength", - "ErrMissingFile", - "ErrNoCookie", - "ErrNoLocation", - "ErrNotMultipart", - "ErrNotSupported", - "ErrServerClosed", - "ErrShortBody", - "ErrSkipAltProtocol", - "ErrUnexpectedTrailer", - "ErrUseLastResponse", - "ErrWriteAfterFlush", - "Error", - "FS", - "File", - "FileServer", - "FileSystem", - "Flusher", - "Get", - "Handle", - "HandleFunc", - "Handler", - "HandlerFunc", - "Head", - "Header", - "Hijacker", - "ListenAndServe", - "ListenAndServeTLS", - "LocalAddrContextKey", - "MaxBytesError", - "MaxBytesHandler", - "MaxBytesReader", - "MethodConnect", - "MethodDelete", - "MethodGet", - "MethodHead", - "MethodOptions", - "MethodPatch", - "MethodPost", - "MethodPut", - "MethodTrace", - "NewFileTransport", - "NewRequest", - "NewRequestWithContext", - "NewResponseController", - "NewServeMux", - "NoBody", - "NotFound", - "NotFoundHandler", - "ParseHTTPVersion", - "ParseTime", - "Post", - "PostForm", - "ProtocolError", - "ProxyFromEnvironment", - "ProxyURL", - "PushOptions", - "Pusher", - "ReadRequest", - "ReadResponse", - "Redirect", - "RedirectHandler", - "Request", - "Response", - "ResponseController", - "ResponseWriter", - "RoundTripper", - "SameSite", - "SameSiteDefaultMode", - "SameSiteLaxMode", - "SameSiteNoneMode", - "SameSiteStrictMode", - "Serve", - "ServeContent", - "ServeFile", - "ServeMux", - "ServeTLS", - "Server", - "ServerContextKey", - "SetCookie", - "StateActive", - "StateClosed", - "StateHijacked", - "StateIdle", - "StateNew", - "StatusAccepted", - "StatusAlreadyReported", - "StatusBadGateway", - "StatusBadRequest", - "StatusConflict", - "StatusContinue", - "StatusCreated", - "StatusEarlyHints", - "StatusExpectationFailed", - "StatusFailedDependency", - "StatusForbidden", - "StatusFound", - "StatusGatewayTimeout", - "StatusGone", - "StatusHTTPVersionNotSupported", - "StatusIMUsed", - "StatusInsufficientStorage", - "StatusInternalServerError", - "StatusLengthRequired", - "StatusLocked", - "StatusLoopDetected", - "StatusMethodNotAllowed", - "StatusMisdirectedRequest", - "StatusMovedPermanently", - "StatusMultiStatus", - "StatusMultipleChoices", - "StatusNetworkAuthenticationRequired", - "StatusNoContent", - "StatusNonAuthoritativeInfo", - "StatusNotAcceptable", - "StatusNotExtended", - "StatusNotFound", - "StatusNotImplemented", - "StatusNotModified", - "StatusOK", - "StatusPartialContent", - "StatusPaymentRequired", - "StatusPermanentRedirect", - "StatusPreconditionFailed", - "StatusPreconditionRequired", - "StatusProcessing", - "StatusProxyAuthRequired", - "StatusRequestEntityTooLarge", - "StatusRequestHeaderFieldsTooLarge", - "StatusRequestTimeout", - "StatusRequestURITooLong", - "StatusRequestedRangeNotSatisfiable", - "StatusResetContent", - "StatusSeeOther", - "StatusServiceUnavailable", - "StatusSwitchingProtocols", - "StatusTeapot", - "StatusTemporaryRedirect", - "StatusText", - "StatusTooEarly", - "StatusTooManyRequests", - "StatusUnauthorized", - "StatusUnavailableForLegalReasons", - "StatusUnprocessableEntity", - "StatusUnsupportedMediaType", - "StatusUpgradeRequired", - "StatusUseProxy", - "StatusVariantAlsoNegotiates", - "StripPrefix", - "TimeFormat", - "TimeoutHandler", - "TrailerPrefix", - "Transport", - }, - "net/http/cgi": { - "Handler", - "Request", - "RequestFromMap", - "Serve", - }, - "net/http/cookiejar": { - "Jar", - "New", - "Options", - "PublicSuffixList", - }, - "net/http/fcgi": { - "ErrConnClosed", - "ErrRequestAborted", - "ProcessEnv", - "Serve", - }, - "net/http/httptest": { - "DefaultRemoteAddr", - "NewRecorder", - "NewRequest", - "NewServer", - "NewTLSServer", - "NewUnstartedServer", - "ResponseRecorder", - "Server", - }, - "net/http/httptrace": { - "ClientTrace", - "ContextClientTrace", - "DNSDoneInfo", - "DNSStartInfo", - "GotConnInfo", - "WithClientTrace", - "WroteRequestInfo", - }, - "net/http/httputil": { - "BufferPool", - "ClientConn", - "DumpRequest", - "DumpRequestOut", - "DumpResponse", - "ErrClosed", - "ErrLineTooLong", - "ErrPersistEOF", - "ErrPipeline", - "NewChunkedReader", - "NewChunkedWriter", - "NewClientConn", - "NewProxyClientConn", - "NewServerConn", - "NewSingleHostReverseProxy", - "ProxyRequest", - "ReverseProxy", - "ServerConn", - }, - "net/http/pprof": { - "Cmdline", - "Handler", - "Index", - "Profile", - "Symbol", - "Trace", - }, - "net/mail": { - "Address", - "AddressParser", - "ErrHeaderNotPresent", - "Header", - "Message", - "ParseAddress", - "ParseAddressList", - "ParseDate", - "ReadMessage", - }, - "net/netip": { - "Addr", - "AddrFrom16", - "AddrFrom4", - "AddrFromSlice", - "AddrPort", - "AddrPortFrom", - "IPv4Unspecified", - "IPv6LinkLocalAllNodes", - "IPv6LinkLocalAllRouters", - "IPv6Loopback", - "IPv6Unspecified", - "MustParseAddr", - "MustParseAddrPort", - "MustParsePrefix", - "ParseAddr", - "ParseAddrPort", - "ParsePrefix", - "Prefix", - "PrefixFrom", - }, - "net/rpc": { - "Accept", - "Call", - "Client", - "ClientCodec", - "DefaultDebugPath", - "DefaultRPCPath", - "DefaultServer", - "Dial", - "DialHTTP", - "DialHTTPPath", - "ErrShutdown", - "HandleHTTP", - "NewClient", - "NewClientWithCodec", - "NewServer", - "Register", - "RegisterName", - "Request", - "Response", - "ServeCodec", - "ServeConn", - "ServeRequest", - "Server", - "ServerCodec", - "ServerError", - }, - "net/rpc/jsonrpc": { - "Dial", - "NewClient", - "NewClientCodec", - "NewServerCodec", - "ServeConn", - }, - "net/smtp": { - "Auth", - "CRAMMD5Auth", - "Client", - "Dial", - "NewClient", - "PlainAuth", - "SendMail", - "ServerInfo", - }, - "net/textproto": { - "CanonicalMIMEHeaderKey", - "Conn", - "Dial", - "Error", - "MIMEHeader", - "NewConn", - "NewReader", - "NewWriter", - "Pipeline", - "ProtocolError", - "Reader", - "TrimBytes", - "TrimString", - "Writer", - }, - "net/url": { - "Error", - "EscapeError", - "InvalidHostError", - "JoinPath", - "Parse", - "ParseQuery", - "ParseRequestURI", - "PathEscape", - "PathUnescape", - "QueryEscape", - "QueryUnescape", - "URL", - "User", - "UserPassword", - "Userinfo", - "Values", - }, - "os": { - "Args", - "Chdir", - "Chmod", - "Chown", - "Chtimes", - "Clearenv", - "Create", - "CreateTemp", - "DevNull", - "DirEntry", - "DirFS", - "Environ", - "ErrClosed", - "ErrDeadlineExceeded", - "ErrExist", - "ErrInvalid", - "ErrNoDeadline", - "ErrNotExist", - "ErrPermission", - "ErrProcessDone", - "Executable", - "Exit", - "Expand", - "ExpandEnv", - "File", - "FileInfo", - "FileMode", - "FindProcess", - "Getegid", - "Getenv", - "Geteuid", - "Getgid", - "Getgroups", - "Getpagesize", - "Getpid", - "Getppid", - "Getuid", - "Getwd", - "Hostname", - "Interrupt", - "IsExist", - "IsNotExist", - "IsPathSeparator", - "IsPermission", - "IsTimeout", - "Kill", - "Lchown", - "Link", - "LinkError", - "LookupEnv", - "Lstat", - "Mkdir", - "MkdirAll", - "MkdirTemp", - "ModeAppend", - "ModeCharDevice", - "ModeDevice", - "ModeDir", - "ModeExclusive", - "ModeIrregular", - "ModeNamedPipe", - "ModePerm", - "ModeSetgid", - "ModeSetuid", - "ModeSocket", - "ModeSticky", - "ModeSymlink", - "ModeTemporary", - "ModeType", - "NewFile", - "NewSyscallError", - "O_APPEND", - "O_CREATE", - "O_EXCL", - "O_RDONLY", - "O_RDWR", - "O_SYNC", - "O_TRUNC", - "O_WRONLY", - "Open", - "OpenFile", - "PathError", - "PathListSeparator", - "PathSeparator", - "Pipe", - "ProcAttr", - "Process", - "ProcessState", - "ReadDir", - "ReadFile", - "Readlink", - "Remove", - "RemoveAll", - "Rename", - "SEEK_CUR", - "SEEK_END", - "SEEK_SET", - "SameFile", - "Setenv", - "Signal", - "StartProcess", - "Stat", - "Stderr", - "Stdin", - "Stdout", - "Symlink", - "SyscallError", - "TempDir", - "Truncate", - "Unsetenv", - "UserCacheDir", - "UserConfigDir", - "UserHomeDir", - "WriteFile", - }, - "os/exec": { - "Cmd", - "Command", - "CommandContext", - "ErrDot", - "ErrNotFound", - "ErrWaitDelay", - "Error", - "ExitError", - "LookPath", - }, - "os/signal": { - "Ignore", - "Ignored", - "Notify", - "NotifyContext", - "Reset", - "Stop", - }, - "os/user": { - "Current", - "Group", - "Lookup", - "LookupGroup", - "LookupGroupId", - "LookupId", - "UnknownGroupError", - "UnknownGroupIdError", - "UnknownUserError", - "UnknownUserIdError", - "User", - }, - "path": { - "Base", - "Clean", - "Dir", - "ErrBadPattern", - "Ext", - "IsAbs", - "Join", - "Match", - "Split", - }, - "path/filepath": { - "Abs", - "Base", - "Clean", - "Dir", - "ErrBadPattern", - "EvalSymlinks", - "Ext", - "FromSlash", - "Glob", - "HasPrefix", - "IsAbs", - "IsLocal", - "Join", - "ListSeparator", - "Match", - "Rel", - "Separator", - "SkipAll", - "SkipDir", - "Split", - "SplitList", - "ToSlash", - "VolumeName", - "Walk", - "WalkDir", - "WalkFunc", - }, - "plugin": { - "Open", - "Plugin", - "Symbol", - }, - "reflect": { - "Append", - "AppendSlice", - "Array", - "ArrayOf", - "Bool", - "BothDir", - "Chan", - "ChanDir", - "ChanOf", - "Complex128", - "Complex64", - "Copy", - "DeepEqual", - "Float32", - "Float64", - "Func", - "FuncOf", - "Indirect", - "Int", - "Int16", - "Int32", - "Int64", - "Int8", - "Interface", - "Invalid", - "Kind", - "MakeChan", - "MakeFunc", - "MakeMap", - "MakeMapWithSize", - "MakeSlice", - "Map", - "MapIter", - "MapOf", - "Method", - "New", - "NewAt", - "Pointer", - "PointerTo", - "Ptr", - "PtrTo", - "RecvDir", - "Select", - "SelectCase", - "SelectDefault", - "SelectDir", - "SelectRecv", - "SelectSend", - "SendDir", - "Slice", - "SliceHeader", - "SliceOf", - "String", - "StringHeader", - "Struct", - "StructField", - "StructOf", - "StructTag", - "Swapper", - "Type", - "TypeOf", - "Uint", - "Uint16", - "Uint32", - "Uint64", - "Uint8", - "Uintptr", - "UnsafePointer", - "Value", - "ValueError", - "ValueOf", - "VisibleFields", - "Zero", - }, - "regexp": { - "Compile", - "CompilePOSIX", - "Match", - "MatchReader", - "MatchString", - "MustCompile", - "MustCompilePOSIX", - "QuoteMeta", - "Regexp", - }, - "regexp/syntax": { - "ClassNL", - "Compile", - "DotNL", - "EmptyBeginLine", - "EmptyBeginText", - "EmptyEndLine", - "EmptyEndText", - "EmptyNoWordBoundary", - "EmptyOp", - "EmptyOpContext", - "EmptyWordBoundary", - "ErrInternalError", - "ErrInvalidCharClass", - "ErrInvalidCharRange", - "ErrInvalidEscape", - "ErrInvalidNamedCapture", - "ErrInvalidPerlOp", - "ErrInvalidRepeatOp", - "ErrInvalidRepeatSize", - "ErrInvalidUTF8", - "ErrLarge", - "ErrMissingBracket", - "ErrMissingParen", - "ErrMissingRepeatArgument", - "ErrNestingDepth", - "ErrTrailingBackslash", - "ErrUnexpectedParen", - "Error", - "ErrorCode", - "Flags", - "FoldCase", - "Inst", - "InstAlt", - "InstAltMatch", - "InstCapture", - "InstEmptyWidth", - "InstFail", - "InstMatch", - "InstNop", - "InstOp", - "InstRune", - "InstRune1", - "InstRuneAny", - "InstRuneAnyNotNL", - "IsWordChar", - "Literal", - "MatchNL", - "NonGreedy", - "OneLine", - "Op", - "OpAlternate", - "OpAnyChar", - "OpAnyCharNotNL", - "OpBeginLine", - "OpBeginText", - "OpCapture", - "OpCharClass", - "OpConcat", - "OpEmptyMatch", - "OpEndLine", - "OpEndText", - "OpLiteral", - "OpNoMatch", - "OpNoWordBoundary", - "OpPlus", - "OpQuest", - "OpRepeat", - "OpStar", - "OpWordBoundary", - "POSIX", - "Parse", - "Perl", - "PerlX", - "Prog", - "Regexp", - "Simple", - "UnicodeGroups", - "WasDollar", - }, - "runtime": { - "BlockProfile", - "BlockProfileRecord", - "Breakpoint", - "CPUProfile", - "Caller", - "Callers", - "CallersFrames", - "Compiler", - "Error", - "Frame", - "Frames", - "Func", - "FuncForPC", - "GC", - "GOARCH", - "GOMAXPROCS", - "GOOS", - "GOROOT", - "Goexit", - "GoroutineProfile", - "Gosched", - "KeepAlive", - "LockOSThread", - "MemProfile", - "MemProfileRate", - "MemProfileRecord", - "MemStats", - "MutexProfile", - "NumCPU", - "NumCgoCall", - "NumGoroutine", - "ReadMemStats", - "ReadTrace", - "SetBlockProfileRate", - "SetCPUProfileRate", - "SetCgoTraceback", - "SetFinalizer", - "SetMutexProfileFraction", - "Stack", - "StackRecord", - "StartTrace", - "StopTrace", - "ThreadCreateProfile", - "TypeAssertionError", - "UnlockOSThread", - "Version", - }, - "runtime/cgo": { - "Handle", - "Incomplete", - "NewHandle", - }, - "runtime/coverage": { - "ClearCounters", - "WriteCounters", - "WriteCountersDir", - "WriteMeta", - "WriteMetaDir", - }, - "runtime/debug": { - "BuildInfo", - "BuildSetting", - "FreeOSMemory", - "GCStats", - "Module", - "ParseBuildInfo", - "PrintStack", - "ReadBuildInfo", - "ReadGCStats", - "SetGCPercent", - "SetMaxStack", - "SetMaxThreads", - "SetMemoryLimit", - "SetPanicOnFault", - "SetTraceback", - "Stack", - "WriteHeapDump", - }, - "runtime/metrics": { - "All", - "Description", - "Float64Histogram", - "KindBad", - "KindFloat64", - "KindFloat64Histogram", - "KindUint64", - "Read", - "Sample", - "Value", - "ValueKind", - }, - "runtime/pprof": { - "Do", - "ForLabels", - "Label", - "LabelSet", - "Labels", - "Lookup", - "NewProfile", - "Profile", - "Profiles", - "SetGoroutineLabels", - "StartCPUProfile", - "StopCPUProfile", - "WithLabels", - "WriteHeapProfile", - }, - "runtime/trace": { - "IsEnabled", - "Log", - "Logf", - "NewTask", - "Region", - "Start", - "StartRegion", - "Stop", - "Task", - "WithRegion", - }, - "sort": { - "Find", - "Float64Slice", - "Float64s", - "Float64sAreSorted", - "IntSlice", - "Interface", - "Ints", - "IntsAreSorted", - "IsSorted", - "Reverse", - "Search", - "SearchFloat64s", - "SearchInts", - "SearchStrings", - "Slice", - "SliceIsSorted", - "SliceStable", - "Sort", - "Stable", - "StringSlice", - "Strings", - "StringsAreSorted", - }, - "strconv": { - "AppendBool", - "AppendFloat", - "AppendInt", - "AppendQuote", - "AppendQuoteRune", - "AppendQuoteRuneToASCII", - "AppendQuoteRuneToGraphic", - "AppendQuoteToASCII", - "AppendQuoteToGraphic", - "AppendUint", - "Atoi", - "CanBackquote", - "ErrRange", - "ErrSyntax", - "FormatBool", - "FormatComplex", - "FormatFloat", - "FormatInt", - "FormatUint", - "IntSize", - "IsGraphic", - "IsPrint", - "Itoa", - "NumError", - "ParseBool", - "ParseComplex", - "ParseFloat", - "ParseInt", - "ParseUint", - "Quote", - "QuoteRune", - "QuoteRuneToASCII", - "QuoteRuneToGraphic", - "QuoteToASCII", - "QuoteToGraphic", - "QuotedPrefix", - "Unquote", - "UnquoteChar", - }, - "strings": { - "Builder", - "Clone", - "Compare", - "Contains", - "ContainsAny", - "ContainsRune", - "Count", - "Cut", - "CutPrefix", - "CutSuffix", - "EqualFold", - "Fields", - "FieldsFunc", - "HasPrefix", - "HasSuffix", - "Index", - "IndexAny", - "IndexByte", - "IndexFunc", - "IndexRune", - "Join", - "LastIndex", - "LastIndexAny", - "LastIndexByte", - "LastIndexFunc", - "Map", - "NewReader", - "NewReplacer", - "Reader", - "Repeat", - "Replace", - "ReplaceAll", - "Replacer", - "Split", - "SplitAfter", - "SplitAfterN", - "SplitN", - "Title", - "ToLower", - "ToLowerSpecial", - "ToTitle", - "ToTitleSpecial", - "ToUpper", - "ToUpperSpecial", - "ToValidUTF8", - "Trim", - "TrimFunc", - "TrimLeft", - "TrimLeftFunc", - "TrimPrefix", - "TrimRight", - "TrimRightFunc", - "TrimSpace", - "TrimSuffix", - }, - "sync": { - "Cond", - "Locker", - "Map", - "Mutex", - "NewCond", - "Once", - "Pool", - "RWMutex", - "WaitGroup", - }, - "sync/atomic": { - "AddInt32", - "AddInt64", - "AddUint32", - "AddUint64", - "AddUintptr", - "Bool", - "CompareAndSwapInt32", - "CompareAndSwapInt64", - "CompareAndSwapPointer", - "CompareAndSwapUint32", - "CompareAndSwapUint64", - "CompareAndSwapUintptr", - "Int32", - "Int64", - "LoadInt32", - "LoadInt64", - "LoadPointer", - "LoadUint32", - "LoadUint64", - "LoadUintptr", - "Pointer", - "StoreInt32", - "StoreInt64", - "StorePointer", - "StoreUint32", - "StoreUint64", - "StoreUintptr", - "SwapInt32", - "SwapInt64", - "SwapPointer", - "SwapUint32", - "SwapUint64", - "SwapUintptr", - "Uint32", - "Uint64", - "Uintptr", - "Value", - }, - "syscall": { - "AF_ALG", - "AF_APPLETALK", - "AF_ARP", - "AF_ASH", - "AF_ATM", - "AF_ATMPVC", - "AF_ATMSVC", - "AF_AX25", - "AF_BLUETOOTH", - "AF_BRIDGE", - "AF_CAIF", - "AF_CAN", - "AF_CCITT", - "AF_CHAOS", - "AF_CNT", - "AF_COIP", - "AF_DATAKIT", - "AF_DECnet", - "AF_DLI", - "AF_E164", - "AF_ECMA", - "AF_ECONET", - "AF_ENCAP", - "AF_FILE", - "AF_HYLINK", - "AF_IEEE80211", - "AF_IEEE802154", - "AF_IMPLINK", - "AF_INET", - "AF_INET6", - "AF_INET6_SDP", - "AF_INET_SDP", - "AF_IPX", - "AF_IRDA", - "AF_ISDN", - "AF_ISO", - "AF_IUCV", - "AF_KEY", - "AF_LAT", - "AF_LINK", - "AF_LLC", - "AF_LOCAL", - "AF_MAX", - "AF_MPLS", - "AF_NATM", - "AF_NDRV", - "AF_NETBEUI", - "AF_NETBIOS", - "AF_NETGRAPH", - "AF_NETLINK", - "AF_NETROM", - "AF_NS", - "AF_OROUTE", - "AF_OSI", - "AF_PACKET", - "AF_PHONET", - "AF_PPP", - "AF_PPPOX", - "AF_PUP", - "AF_RDS", - "AF_RESERVED_36", - "AF_ROSE", - "AF_ROUTE", - "AF_RXRPC", - "AF_SCLUSTER", - "AF_SECURITY", - "AF_SIP", - "AF_SLOW", - "AF_SNA", - "AF_SYSTEM", - "AF_TIPC", - "AF_UNIX", - "AF_UNSPEC", - "AF_UTUN", - "AF_VENDOR00", - "AF_VENDOR01", - "AF_VENDOR02", - "AF_VENDOR03", - "AF_VENDOR04", - "AF_VENDOR05", - "AF_VENDOR06", - "AF_VENDOR07", - "AF_VENDOR08", - "AF_VENDOR09", - "AF_VENDOR10", - "AF_VENDOR11", - "AF_VENDOR12", - "AF_VENDOR13", - "AF_VENDOR14", - "AF_VENDOR15", - "AF_VENDOR16", - "AF_VENDOR17", - "AF_VENDOR18", - "AF_VENDOR19", - "AF_VENDOR20", - "AF_VENDOR21", - "AF_VENDOR22", - "AF_VENDOR23", - "AF_VENDOR24", - "AF_VENDOR25", - "AF_VENDOR26", - "AF_VENDOR27", - "AF_VENDOR28", - "AF_VENDOR29", - "AF_VENDOR30", - "AF_VENDOR31", - "AF_VENDOR32", - "AF_VENDOR33", - "AF_VENDOR34", - "AF_VENDOR35", - "AF_VENDOR36", - "AF_VENDOR37", - "AF_VENDOR38", - "AF_VENDOR39", - "AF_VENDOR40", - "AF_VENDOR41", - "AF_VENDOR42", - "AF_VENDOR43", - "AF_VENDOR44", - "AF_VENDOR45", - "AF_VENDOR46", - "AF_VENDOR47", - "AF_WANPIPE", - "AF_X25", - "AI_CANONNAME", - "AI_NUMERICHOST", - "AI_PASSIVE", - "APPLICATION_ERROR", - "ARPHRD_ADAPT", - "ARPHRD_APPLETLK", - "ARPHRD_ARCNET", - "ARPHRD_ASH", - "ARPHRD_ATM", - "ARPHRD_AX25", - "ARPHRD_BIF", - "ARPHRD_CHAOS", - "ARPHRD_CISCO", - "ARPHRD_CSLIP", - "ARPHRD_CSLIP6", - "ARPHRD_DDCMP", - "ARPHRD_DLCI", - "ARPHRD_ECONET", - "ARPHRD_EETHER", - "ARPHRD_ETHER", - "ARPHRD_EUI64", - "ARPHRD_FCAL", - "ARPHRD_FCFABRIC", - "ARPHRD_FCPL", - "ARPHRD_FCPP", - "ARPHRD_FDDI", - "ARPHRD_FRAD", - "ARPHRD_FRELAY", - "ARPHRD_HDLC", - "ARPHRD_HIPPI", - "ARPHRD_HWX25", - "ARPHRD_IEEE1394", - "ARPHRD_IEEE802", - "ARPHRD_IEEE80211", - "ARPHRD_IEEE80211_PRISM", - "ARPHRD_IEEE80211_RADIOTAP", - "ARPHRD_IEEE802154", - "ARPHRD_IEEE802154_PHY", - "ARPHRD_IEEE802_TR", - "ARPHRD_INFINIBAND", - "ARPHRD_IPDDP", - "ARPHRD_IPGRE", - "ARPHRD_IRDA", - "ARPHRD_LAPB", - "ARPHRD_LOCALTLK", - "ARPHRD_LOOPBACK", - "ARPHRD_METRICOM", - "ARPHRD_NETROM", - "ARPHRD_NONE", - "ARPHRD_PIMREG", - "ARPHRD_PPP", - "ARPHRD_PRONET", - "ARPHRD_RAWHDLC", - "ARPHRD_ROSE", - "ARPHRD_RSRVD", - "ARPHRD_SIT", - "ARPHRD_SKIP", - "ARPHRD_SLIP", - "ARPHRD_SLIP6", - "ARPHRD_STRIP", - "ARPHRD_TUNNEL", - "ARPHRD_TUNNEL6", - "ARPHRD_VOID", - "ARPHRD_X25", - "AUTHTYPE_CLIENT", - "AUTHTYPE_SERVER", - "Accept", - "Accept4", - "AcceptEx", - "Access", - "Acct", - "AddrinfoW", - "Adjtime", - "Adjtimex", - "AllThreadsSyscall", - "AllThreadsSyscall6", - "AttachLsf", - "B0", - "B1000000", - "B110", - "B115200", - "B1152000", - "B1200", - "B134", - "B14400", - "B150", - "B1500000", - "B1800", - "B19200", - "B200", - "B2000000", - "B230400", - "B2400", - "B2500000", - "B28800", - "B300", - "B3000000", - "B3500000", - "B38400", - "B4000000", - "B460800", - "B4800", - "B50", - "B500000", - "B57600", - "B576000", - "B600", - "B7200", - "B75", - "B76800", - "B921600", - "B9600", - "BASE_PROTOCOL", - "BIOCFEEDBACK", - "BIOCFLUSH", - "BIOCGBLEN", - "BIOCGDIRECTION", - "BIOCGDIRFILT", - "BIOCGDLT", - "BIOCGDLTLIST", - "BIOCGETBUFMODE", - "BIOCGETIF", - "BIOCGETZMAX", - "BIOCGFEEDBACK", - "BIOCGFILDROP", - "BIOCGHDRCMPLT", - "BIOCGRSIG", - "BIOCGRTIMEOUT", - "BIOCGSEESENT", - "BIOCGSTATS", - "BIOCGSTATSOLD", - "BIOCGTSTAMP", - "BIOCIMMEDIATE", - "BIOCLOCK", - "BIOCPROMISC", - "BIOCROTZBUF", - "BIOCSBLEN", - "BIOCSDIRECTION", - "BIOCSDIRFILT", - "BIOCSDLT", - "BIOCSETBUFMODE", - "BIOCSETF", - "BIOCSETFNR", - "BIOCSETIF", - "BIOCSETWF", - "BIOCSETZBUF", - "BIOCSFEEDBACK", - "BIOCSFILDROP", - "BIOCSHDRCMPLT", - "BIOCSRSIG", - "BIOCSRTIMEOUT", - "BIOCSSEESENT", - "BIOCSTCPF", - "BIOCSTSTAMP", - "BIOCSUDPF", - "BIOCVERSION", - "BPF_A", - "BPF_ABS", - "BPF_ADD", - "BPF_ALIGNMENT", - "BPF_ALIGNMENT32", - "BPF_ALU", - "BPF_AND", - "BPF_B", - "BPF_BUFMODE_BUFFER", - "BPF_BUFMODE_ZBUF", - "BPF_DFLTBUFSIZE", - "BPF_DIRECTION_IN", - "BPF_DIRECTION_OUT", - "BPF_DIV", - "BPF_H", - "BPF_IMM", - "BPF_IND", - "BPF_JA", - "BPF_JEQ", - "BPF_JGE", - "BPF_JGT", - "BPF_JMP", - "BPF_JSET", - "BPF_K", - "BPF_LD", - "BPF_LDX", - "BPF_LEN", - "BPF_LSH", - "BPF_MAJOR_VERSION", - "BPF_MAXBUFSIZE", - "BPF_MAXINSNS", - "BPF_MEM", - "BPF_MEMWORDS", - "BPF_MINBUFSIZE", - "BPF_MINOR_VERSION", - "BPF_MISC", - "BPF_MSH", - "BPF_MUL", - "BPF_NEG", - "BPF_OR", - "BPF_RELEASE", - "BPF_RET", - "BPF_RSH", - "BPF_ST", - "BPF_STX", - "BPF_SUB", - "BPF_TAX", - "BPF_TXA", - "BPF_T_BINTIME", - "BPF_T_BINTIME_FAST", - "BPF_T_BINTIME_MONOTONIC", - "BPF_T_BINTIME_MONOTONIC_FAST", - "BPF_T_FAST", - "BPF_T_FLAG_MASK", - "BPF_T_FORMAT_MASK", - "BPF_T_MICROTIME", - "BPF_T_MICROTIME_FAST", - "BPF_T_MICROTIME_MONOTONIC", - "BPF_T_MICROTIME_MONOTONIC_FAST", - "BPF_T_MONOTONIC", - "BPF_T_MONOTONIC_FAST", - "BPF_T_NANOTIME", - "BPF_T_NANOTIME_FAST", - "BPF_T_NANOTIME_MONOTONIC", - "BPF_T_NANOTIME_MONOTONIC_FAST", - "BPF_T_NONE", - "BPF_T_NORMAL", - "BPF_W", - "BPF_X", - "BRKINT", - "Bind", - "BindToDevice", - "BpfBuflen", - "BpfDatalink", - "BpfHdr", - "BpfHeadercmpl", - "BpfInsn", - "BpfInterface", - "BpfJump", - "BpfProgram", - "BpfStat", - "BpfStats", - "BpfStmt", - "BpfTimeout", - "BpfTimeval", - "BpfVersion", - "BpfZbuf", - "BpfZbufHeader", - "ByHandleFileInformation", - "BytePtrFromString", - "ByteSliceFromString", - "CCR0_FLUSH", - "CERT_CHAIN_POLICY_AUTHENTICODE", - "CERT_CHAIN_POLICY_AUTHENTICODE_TS", - "CERT_CHAIN_POLICY_BASE", - "CERT_CHAIN_POLICY_BASIC_CONSTRAINTS", - "CERT_CHAIN_POLICY_EV", - "CERT_CHAIN_POLICY_MICROSOFT_ROOT", - "CERT_CHAIN_POLICY_NT_AUTH", - "CERT_CHAIN_POLICY_SSL", - "CERT_E_CN_NO_MATCH", - "CERT_E_EXPIRED", - "CERT_E_PURPOSE", - "CERT_E_ROLE", - "CERT_E_UNTRUSTEDROOT", - "CERT_STORE_ADD_ALWAYS", - "CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG", - "CERT_STORE_PROV_MEMORY", - "CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT", - "CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT", - "CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT", - "CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT", - "CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT", - "CERT_TRUST_INVALID_BASIC_CONSTRAINTS", - "CERT_TRUST_INVALID_EXTENSION", - "CERT_TRUST_INVALID_NAME_CONSTRAINTS", - "CERT_TRUST_INVALID_POLICY_CONSTRAINTS", - "CERT_TRUST_IS_CYCLIC", - "CERT_TRUST_IS_EXPLICIT_DISTRUST", - "CERT_TRUST_IS_NOT_SIGNATURE_VALID", - "CERT_TRUST_IS_NOT_TIME_VALID", - "CERT_TRUST_IS_NOT_VALID_FOR_USAGE", - "CERT_TRUST_IS_OFFLINE_REVOCATION", - "CERT_TRUST_IS_REVOKED", - "CERT_TRUST_IS_UNTRUSTED_ROOT", - "CERT_TRUST_NO_ERROR", - "CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY", - "CERT_TRUST_REVOCATION_STATUS_UNKNOWN", - "CFLUSH", - "CLOCAL", - "CLONE_CHILD_CLEARTID", - "CLONE_CHILD_SETTID", - "CLONE_CLEAR_SIGHAND", - "CLONE_CSIGNAL", - "CLONE_DETACHED", - "CLONE_FILES", - "CLONE_FS", - "CLONE_INTO_CGROUP", - "CLONE_IO", - "CLONE_NEWCGROUP", - "CLONE_NEWIPC", - "CLONE_NEWNET", - "CLONE_NEWNS", - "CLONE_NEWPID", - "CLONE_NEWTIME", - "CLONE_NEWUSER", - "CLONE_NEWUTS", - "CLONE_PARENT", - "CLONE_PARENT_SETTID", - "CLONE_PID", - "CLONE_PIDFD", - "CLONE_PTRACE", - "CLONE_SETTLS", - "CLONE_SIGHAND", - "CLONE_SYSVSEM", - "CLONE_THREAD", - "CLONE_UNTRACED", - "CLONE_VFORK", - "CLONE_VM", - "CPUID_CFLUSH", - "CREAD", - "CREATE_ALWAYS", - "CREATE_NEW", - "CREATE_NEW_PROCESS_GROUP", - "CREATE_UNICODE_ENVIRONMENT", - "CRYPT_DEFAULT_CONTAINER_OPTIONAL", - "CRYPT_DELETEKEYSET", - "CRYPT_MACHINE_KEYSET", - "CRYPT_NEWKEYSET", - "CRYPT_SILENT", - "CRYPT_VERIFYCONTEXT", - "CS5", - "CS6", - "CS7", - "CS8", - "CSIZE", - "CSTART", - "CSTATUS", - "CSTOP", - "CSTOPB", - "CSUSP", - "CTL_MAXNAME", - "CTL_NET", - "CTL_QUERY", - "CTRL_BREAK_EVENT", - "CTRL_CLOSE_EVENT", - "CTRL_C_EVENT", - "CTRL_LOGOFF_EVENT", - "CTRL_SHUTDOWN_EVENT", - "CancelIo", - "CancelIoEx", - "CertAddCertificateContextToStore", - "CertChainContext", - "CertChainElement", - "CertChainPara", - "CertChainPolicyPara", - "CertChainPolicyStatus", - "CertCloseStore", - "CertContext", - "CertCreateCertificateContext", - "CertEnhKeyUsage", - "CertEnumCertificatesInStore", - "CertFreeCertificateChain", - "CertFreeCertificateContext", - "CertGetCertificateChain", - "CertInfo", - "CertOpenStore", - "CertOpenSystemStore", - "CertRevocationCrlInfo", - "CertRevocationInfo", - "CertSimpleChain", - "CertTrustListInfo", - "CertTrustStatus", - "CertUsageMatch", - "CertVerifyCertificateChainPolicy", - "Chdir", - "CheckBpfVersion", - "Chflags", - "Chmod", - "Chown", - "Chroot", - "Clearenv", - "Close", - "CloseHandle", - "CloseOnExec", - "Closesocket", - "CmsgLen", - "CmsgSpace", - "Cmsghdr", - "CommandLineToArgv", - "ComputerName", - "Conn", - "Connect", - "ConnectEx", - "ConvertSidToStringSid", - "ConvertStringSidToSid", - "CopySid", - "Creat", - "CreateDirectory", - "CreateFile", - "CreateFileMapping", - "CreateHardLink", - "CreateIoCompletionPort", - "CreatePipe", - "CreateProcess", - "CreateProcessAsUser", - "CreateSymbolicLink", - "CreateToolhelp32Snapshot", - "Credential", - "CryptAcquireContext", - "CryptGenRandom", - "CryptReleaseContext", - "DIOCBSFLUSH", - "DIOCOSFPFLUSH", - "DLL", - "DLLError", - "DLT_A429", - "DLT_A653_ICM", - "DLT_AIRONET_HEADER", - "DLT_AOS", - "DLT_APPLE_IP_OVER_IEEE1394", - "DLT_ARCNET", - "DLT_ARCNET_LINUX", - "DLT_ATM_CLIP", - "DLT_ATM_RFC1483", - "DLT_AURORA", - "DLT_AX25", - "DLT_AX25_KISS", - "DLT_BACNET_MS_TP", - "DLT_BLUETOOTH_HCI_H4", - "DLT_BLUETOOTH_HCI_H4_WITH_PHDR", - "DLT_CAN20B", - "DLT_CAN_SOCKETCAN", - "DLT_CHAOS", - "DLT_CHDLC", - "DLT_CISCO_IOS", - "DLT_C_HDLC", - "DLT_C_HDLC_WITH_DIR", - "DLT_DBUS", - "DLT_DECT", - "DLT_DOCSIS", - "DLT_DVB_CI", - "DLT_ECONET", - "DLT_EN10MB", - "DLT_EN3MB", - "DLT_ENC", - "DLT_ERF", - "DLT_ERF_ETH", - "DLT_ERF_POS", - "DLT_FC_2", - "DLT_FC_2_WITH_FRAME_DELIMS", - "DLT_FDDI", - "DLT_FLEXRAY", - "DLT_FRELAY", - "DLT_FRELAY_WITH_DIR", - "DLT_GCOM_SERIAL", - "DLT_GCOM_T1E1", - "DLT_GPF_F", - "DLT_GPF_T", - "DLT_GPRS_LLC", - "DLT_GSMTAP_ABIS", - "DLT_GSMTAP_UM", - "DLT_HDLC", - "DLT_HHDLC", - "DLT_HIPPI", - "DLT_IBM_SN", - "DLT_IBM_SP", - "DLT_IEEE802", - "DLT_IEEE802_11", - "DLT_IEEE802_11_RADIO", - "DLT_IEEE802_11_RADIO_AVS", - "DLT_IEEE802_15_4", - "DLT_IEEE802_15_4_LINUX", - "DLT_IEEE802_15_4_NOFCS", - "DLT_IEEE802_15_4_NONASK_PHY", - "DLT_IEEE802_16_MAC_CPS", - "DLT_IEEE802_16_MAC_CPS_RADIO", - "DLT_IPFILTER", - "DLT_IPMB", - "DLT_IPMB_LINUX", - "DLT_IPNET", - "DLT_IPOIB", - "DLT_IPV4", - "DLT_IPV6", - "DLT_IP_OVER_FC", - "DLT_JUNIPER_ATM1", - "DLT_JUNIPER_ATM2", - "DLT_JUNIPER_ATM_CEMIC", - "DLT_JUNIPER_CHDLC", - "DLT_JUNIPER_ES", - "DLT_JUNIPER_ETHER", - "DLT_JUNIPER_FIBRECHANNEL", - "DLT_JUNIPER_FRELAY", - "DLT_JUNIPER_GGSN", - "DLT_JUNIPER_ISM", - "DLT_JUNIPER_MFR", - "DLT_JUNIPER_MLFR", - "DLT_JUNIPER_MLPPP", - "DLT_JUNIPER_MONITOR", - "DLT_JUNIPER_PIC_PEER", - "DLT_JUNIPER_PPP", - "DLT_JUNIPER_PPPOE", - "DLT_JUNIPER_PPPOE_ATM", - "DLT_JUNIPER_SERVICES", - "DLT_JUNIPER_SRX_E2E", - "DLT_JUNIPER_ST", - "DLT_JUNIPER_VP", - "DLT_JUNIPER_VS", - "DLT_LAPB_WITH_DIR", - "DLT_LAPD", - "DLT_LIN", - "DLT_LINUX_EVDEV", - "DLT_LINUX_IRDA", - "DLT_LINUX_LAPD", - "DLT_LINUX_PPP_WITHDIRECTION", - "DLT_LINUX_SLL", - "DLT_LOOP", - "DLT_LTALK", - "DLT_MATCHING_MAX", - "DLT_MATCHING_MIN", - "DLT_MFR", - "DLT_MOST", - "DLT_MPEG_2_TS", - "DLT_MPLS", - "DLT_MTP2", - "DLT_MTP2_WITH_PHDR", - "DLT_MTP3", - "DLT_MUX27010", - "DLT_NETANALYZER", - "DLT_NETANALYZER_TRANSPARENT", - "DLT_NFC_LLCP", - "DLT_NFLOG", - "DLT_NG40", - "DLT_NULL", - "DLT_PCI_EXP", - "DLT_PFLOG", - "DLT_PFSYNC", - "DLT_PPI", - "DLT_PPP", - "DLT_PPP_BSDOS", - "DLT_PPP_ETHER", - "DLT_PPP_PPPD", - "DLT_PPP_SERIAL", - "DLT_PPP_WITH_DIR", - "DLT_PPP_WITH_DIRECTION", - "DLT_PRISM_HEADER", - "DLT_PRONET", - "DLT_RAIF1", - "DLT_RAW", - "DLT_RAWAF_MASK", - "DLT_RIO", - "DLT_SCCP", - "DLT_SITA", - "DLT_SLIP", - "DLT_SLIP_BSDOS", - "DLT_STANAG_5066_D_PDU", - "DLT_SUNATM", - "DLT_SYMANTEC_FIREWALL", - "DLT_TZSP", - "DLT_USB", - "DLT_USB_LINUX", - "DLT_USB_LINUX_MMAPPED", - "DLT_USER0", - "DLT_USER1", - "DLT_USER10", - "DLT_USER11", - "DLT_USER12", - "DLT_USER13", - "DLT_USER14", - "DLT_USER15", - "DLT_USER2", - "DLT_USER3", - "DLT_USER4", - "DLT_USER5", - "DLT_USER6", - "DLT_USER7", - "DLT_USER8", - "DLT_USER9", - "DLT_WIHART", - "DLT_X2E_SERIAL", - "DLT_X2E_XORAYA", - "DNSMXData", - "DNSPTRData", - "DNSRecord", - "DNSSRVData", - "DNSTXTData", - "DNS_INFO_NO_RECORDS", - "DNS_TYPE_A", - "DNS_TYPE_A6", - "DNS_TYPE_AAAA", - "DNS_TYPE_ADDRS", - "DNS_TYPE_AFSDB", - "DNS_TYPE_ALL", - "DNS_TYPE_ANY", - "DNS_TYPE_ATMA", - "DNS_TYPE_AXFR", - "DNS_TYPE_CERT", - "DNS_TYPE_CNAME", - "DNS_TYPE_DHCID", - "DNS_TYPE_DNAME", - "DNS_TYPE_DNSKEY", - "DNS_TYPE_DS", - "DNS_TYPE_EID", - "DNS_TYPE_GID", - "DNS_TYPE_GPOS", - "DNS_TYPE_HINFO", - "DNS_TYPE_ISDN", - "DNS_TYPE_IXFR", - "DNS_TYPE_KEY", - "DNS_TYPE_KX", - "DNS_TYPE_LOC", - "DNS_TYPE_MAILA", - "DNS_TYPE_MAILB", - "DNS_TYPE_MB", - "DNS_TYPE_MD", - "DNS_TYPE_MF", - "DNS_TYPE_MG", - "DNS_TYPE_MINFO", - "DNS_TYPE_MR", - "DNS_TYPE_MX", - "DNS_TYPE_NAPTR", - "DNS_TYPE_NBSTAT", - "DNS_TYPE_NIMLOC", - "DNS_TYPE_NS", - "DNS_TYPE_NSAP", - "DNS_TYPE_NSAPPTR", - "DNS_TYPE_NSEC", - "DNS_TYPE_NULL", - "DNS_TYPE_NXT", - "DNS_TYPE_OPT", - "DNS_TYPE_PTR", - "DNS_TYPE_PX", - "DNS_TYPE_RP", - "DNS_TYPE_RRSIG", - "DNS_TYPE_RT", - "DNS_TYPE_SIG", - "DNS_TYPE_SINK", - "DNS_TYPE_SOA", - "DNS_TYPE_SRV", - "DNS_TYPE_TEXT", - "DNS_TYPE_TKEY", - "DNS_TYPE_TSIG", - "DNS_TYPE_UID", - "DNS_TYPE_UINFO", - "DNS_TYPE_UNSPEC", - "DNS_TYPE_WINS", - "DNS_TYPE_WINSR", - "DNS_TYPE_WKS", - "DNS_TYPE_X25", - "DT_BLK", - "DT_CHR", - "DT_DIR", - "DT_FIFO", - "DT_LNK", - "DT_REG", - "DT_SOCK", - "DT_UNKNOWN", - "DT_WHT", - "DUPLICATE_CLOSE_SOURCE", - "DUPLICATE_SAME_ACCESS", - "DeleteFile", - "DetachLsf", - "DeviceIoControl", - "Dirent", - "DnsNameCompare", - "DnsQuery", - "DnsRecordListFree", - "DnsSectionAdditional", - "DnsSectionAnswer", - "DnsSectionAuthority", - "DnsSectionQuestion", - "Dup", - "Dup2", - "Dup3", - "DuplicateHandle", - "E2BIG", - "EACCES", - "EADDRINUSE", - "EADDRNOTAVAIL", - "EADV", - "EAFNOSUPPORT", - "EAGAIN", - "EALREADY", - "EAUTH", - "EBADARCH", - "EBADE", - "EBADEXEC", - "EBADF", - "EBADFD", - "EBADMACHO", - "EBADMSG", - "EBADR", - "EBADRPC", - "EBADRQC", - "EBADSLT", - "EBFONT", - "EBUSY", - "ECANCELED", - "ECAPMODE", - "ECHILD", - "ECHO", - "ECHOCTL", - "ECHOE", - "ECHOK", - "ECHOKE", - "ECHONL", - "ECHOPRT", - "ECHRNG", - "ECOMM", - "ECONNABORTED", - "ECONNREFUSED", - "ECONNRESET", - "EDEADLK", - "EDEADLOCK", - "EDESTADDRREQ", - "EDEVERR", - "EDOM", - "EDOOFUS", - "EDOTDOT", - "EDQUOT", - "EEXIST", - "EFAULT", - "EFBIG", - "EFER_LMA", - "EFER_LME", - "EFER_NXE", - "EFER_SCE", - "EFTYPE", - "EHOSTDOWN", - "EHOSTUNREACH", - "EHWPOISON", - "EIDRM", - "EILSEQ", - "EINPROGRESS", - "EINTR", - "EINVAL", - "EIO", - "EIPSEC", - "EISCONN", - "EISDIR", - "EISNAM", - "EKEYEXPIRED", - "EKEYREJECTED", - "EKEYREVOKED", - "EL2HLT", - "EL2NSYNC", - "EL3HLT", - "EL3RST", - "ELAST", - "ELF_NGREG", - "ELF_PRARGSZ", - "ELIBACC", - "ELIBBAD", - "ELIBEXEC", - "ELIBMAX", - "ELIBSCN", - "ELNRNG", - "ELOOP", - "EMEDIUMTYPE", - "EMFILE", - "EMLINK", - "EMSGSIZE", - "EMT_TAGOVF", - "EMULTIHOP", - "EMUL_ENABLED", - "EMUL_LINUX", - "EMUL_LINUX32", - "EMUL_MAXID", - "EMUL_NATIVE", - "ENAMETOOLONG", - "ENAVAIL", - "ENDRUNDISC", - "ENEEDAUTH", - "ENETDOWN", - "ENETRESET", - "ENETUNREACH", - "ENFILE", - "ENOANO", - "ENOATTR", - "ENOBUFS", - "ENOCSI", - "ENODATA", - "ENODEV", - "ENOENT", - "ENOEXEC", - "ENOKEY", - "ENOLCK", - "ENOLINK", - "ENOMEDIUM", - "ENOMEM", - "ENOMSG", - "ENONET", - "ENOPKG", - "ENOPOLICY", - "ENOPROTOOPT", - "ENOSPC", - "ENOSR", - "ENOSTR", - "ENOSYS", - "ENOTBLK", - "ENOTCAPABLE", - "ENOTCONN", - "ENOTDIR", - "ENOTEMPTY", - "ENOTNAM", - "ENOTRECOVERABLE", - "ENOTSOCK", - "ENOTSUP", - "ENOTTY", - "ENOTUNIQ", - "ENXIO", - "EN_SW_CTL_INF", - "EN_SW_CTL_PREC", - "EN_SW_CTL_ROUND", - "EN_SW_DATACHAIN", - "EN_SW_DENORM", - "EN_SW_INVOP", - "EN_SW_OVERFLOW", - "EN_SW_PRECLOSS", - "EN_SW_UNDERFLOW", - "EN_SW_ZERODIV", - "EOPNOTSUPP", - "EOVERFLOW", - "EOWNERDEAD", - "EPERM", - "EPFNOSUPPORT", - "EPIPE", - "EPOLLERR", - "EPOLLET", - "EPOLLHUP", - "EPOLLIN", - "EPOLLMSG", - "EPOLLONESHOT", - "EPOLLOUT", - "EPOLLPRI", - "EPOLLRDBAND", - "EPOLLRDHUP", - "EPOLLRDNORM", - "EPOLLWRBAND", - "EPOLLWRNORM", - "EPOLL_CLOEXEC", - "EPOLL_CTL_ADD", - "EPOLL_CTL_DEL", - "EPOLL_CTL_MOD", - "EPOLL_NONBLOCK", - "EPROCLIM", - "EPROCUNAVAIL", - "EPROGMISMATCH", - "EPROGUNAVAIL", - "EPROTO", - "EPROTONOSUPPORT", - "EPROTOTYPE", - "EPWROFF", - "EQFULL", - "ERANGE", - "EREMCHG", - "EREMOTE", - "EREMOTEIO", - "ERESTART", - "ERFKILL", - "EROFS", - "ERPCMISMATCH", - "ERROR_ACCESS_DENIED", - "ERROR_ALREADY_EXISTS", - "ERROR_BROKEN_PIPE", - "ERROR_BUFFER_OVERFLOW", - "ERROR_DIR_NOT_EMPTY", - "ERROR_ENVVAR_NOT_FOUND", - "ERROR_FILE_EXISTS", - "ERROR_FILE_NOT_FOUND", - "ERROR_HANDLE_EOF", - "ERROR_INSUFFICIENT_BUFFER", - "ERROR_IO_PENDING", - "ERROR_MOD_NOT_FOUND", - "ERROR_MORE_DATA", - "ERROR_NETNAME_DELETED", - "ERROR_NOT_FOUND", - "ERROR_NO_MORE_FILES", - "ERROR_OPERATION_ABORTED", - "ERROR_PATH_NOT_FOUND", - "ERROR_PRIVILEGE_NOT_HELD", - "ERROR_PROC_NOT_FOUND", - "ESHLIBVERS", - "ESHUTDOWN", - "ESOCKTNOSUPPORT", - "ESPIPE", - "ESRCH", - "ESRMNT", - "ESTALE", - "ESTRPIPE", - "ETHERCAP_JUMBO_MTU", - "ETHERCAP_VLAN_HWTAGGING", - "ETHERCAP_VLAN_MTU", - "ETHERMIN", - "ETHERMTU", - "ETHERMTU_JUMBO", - "ETHERTYPE_8023", - "ETHERTYPE_AARP", - "ETHERTYPE_ACCTON", - "ETHERTYPE_AEONIC", - "ETHERTYPE_ALPHA", - "ETHERTYPE_AMBER", - "ETHERTYPE_AMOEBA", - "ETHERTYPE_AOE", - "ETHERTYPE_APOLLO", - "ETHERTYPE_APOLLODOMAIN", - "ETHERTYPE_APPLETALK", - "ETHERTYPE_APPLITEK", - "ETHERTYPE_ARGONAUT", - "ETHERTYPE_ARP", - "ETHERTYPE_AT", - "ETHERTYPE_ATALK", - "ETHERTYPE_ATOMIC", - "ETHERTYPE_ATT", - "ETHERTYPE_ATTSTANFORD", - "ETHERTYPE_AUTOPHON", - "ETHERTYPE_AXIS", - "ETHERTYPE_BCLOOP", - "ETHERTYPE_BOFL", - "ETHERTYPE_CABLETRON", - "ETHERTYPE_CHAOS", - "ETHERTYPE_COMDESIGN", - "ETHERTYPE_COMPUGRAPHIC", - "ETHERTYPE_COUNTERPOINT", - "ETHERTYPE_CRONUS", - "ETHERTYPE_CRONUSVLN", - "ETHERTYPE_DCA", - "ETHERTYPE_DDE", - "ETHERTYPE_DEBNI", - "ETHERTYPE_DECAM", - "ETHERTYPE_DECCUST", - "ETHERTYPE_DECDIAG", - "ETHERTYPE_DECDNS", - "ETHERTYPE_DECDTS", - "ETHERTYPE_DECEXPER", - "ETHERTYPE_DECLAST", - "ETHERTYPE_DECLTM", - "ETHERTYPE_DECMUMPS", - "ETHERTYPE_DECNETBIOS", - "ETHERTYPE_DELTACON", - "ETHERTYPE_DIDDLE", - "ETHERTYPE_DLOG1", - "ETHERTYPE_DLOG2", - "ETHERTYPE_DN", - "ETHERTYPE_DOGFIGHT", - "ETHERTYPE_DSMD", - "ETHERTYPE_ECMA", - "ETHERTYPE_ENCRYPT", - "ETHERTYPE_ES", - "ETHERTYPE_EXCELAN", - "ETHERTYPE_EXPERDATA", - "ETHERTYPE_FLIP", - "ETHERTYPE_FLOWCONTROL", - "ETHERTYPE_FRARP", - "ETHERTYPE_GENDYN", - "ETHERTYPE_HAYES", - "ETHERTYPE_HIPPI_FP", - "ETHERTYPE_HITACHI", - "ETHERTYPE_HP", - "ETHERTYPE_IEEEPUP", - "ETHERTYPE_IEEEPUPAT", - "ETHERTYPE_IMLBL", - "ETHERTYPE_IMLBLDIAG", - "ETHERTYPE_IP", - "ETHERTYPE_IPAS", - "ETHERTYPE_IPV6", - "ETHERTYPE_IPX", - "ETHERTYPE_IPXNEW", - "ETHERTYPE_KALPANA", - "ETHERTYPE_LANBRIDGE", - "ETHERTYPE_LANPROBE", - "ETHERTYPE_LAT", - "ETHERTYPE_LBACK", - "ETHERTYPE_LITTLE", - "ETHERTYPE_LLDP", - "ETHERTYPE_LOGICRAFT", - "ETHERTYPE_LOOPBACK", - "ETHERTYPE_MATRA", - "ETHERTYPE_MAX", - "ETHERTYPE_MERIT", - "ETHERTYPE_MICP", - "ETHERTYPE_MOPDL", - "ETHERTYPE_MOPRC", - "ETHERTYPE_MOTOROLA", - "ETHERTYPE_MPLS", - "ETHERTYPE_MPLS_MCAST", - "ETHERTYPE_MUMPS", - "ETHERTYPE_NBPCC", - "ETHERTYPE_NBPCLAIM", - "ETHERTYPE_NBPCLREQ", - "ETHERTYPE_NBPCLRSP", - "ETHERTYPE_NBPCREQ", - "ETHERTYPE_NBPCRSP", - "ETHERTYPE_NBPDG", - "ETHERTYPE_NBPDGB", - "ETHERTYPE_NBPDLTE", - "ETHERTYPE_NBPRAR", - "ETHERTYPE_NBPRAS", - "ETHERTYPE_NBPRST", - "ETHERTYPE_NBPSCD", - "ETHERTYPE_NBPVCD", - "ETHERTYPE_NBS", - "ETHERTYPE_NCD", - "ETHERTYPE_NESTAR", - "ETHERTYPE_NETBEUI", - "ETHERTYPE_NOVELL", - "ETHERTYPE_NS", - "ETHERTYPE_NSAT", - "ETHERTYPE_NSCOMPAT", - "ETHERTYPE_NTRAILER", - "ETHERTYPE_OS9", - "ETHERTYPE_OS9NET", - "ETHERTYPE_PACER", - "ETHERTYPE_PAE", - "ETHERTYPE_PCS", - "ETHERTYPE_PLANNING", - "ETHERTYPE_PPP", - "ETHERTYPE_PPPOE", - "ETHERTYPE_PPPOEDISC", - "ETHERTYPE_PRIMENTS", - "ETHERTYPE_PUP", - "ETHERTYPE_PUPAT", - "ETHERTYPE_QINQ", - "ETHERTYPE_RACAL", - "ETHERTYPE_RATIONAL", - "ETHERTYPE_RAWFR", - "ETHERTYPE_RCL", - "ETHERTYPE_RDP", - "ETHERTYPE_RETIX", - "ETHERTYPE_REVARP", - "ETHERTYPE_SCA", - "ETHERTYPE_SECTRA", - "ETHERTYPE_SECUREDATA", - "ETHERTYPE_SGITW", - "ETHERTYPE_SG_BOUNCE", - "ETHERTYPE_SG_DIAG", - "ETHERTYPE_SG_NETGAMES", - "ETHERTYPE_SG_RESV", - "ETHERTYPE_SIMNET", - "ETHERTYPE_SLOW", - "ETHERTYPE_SLOWPROTOCOLS", - "ETHERTYPE_SNA", - "ETHERTYPE_SNMP", - "ETHERTYPE_SONIX", - "ETHERTYPE_SPIDER", - "ETHERTYPE_SPRITE", - "ETHERTYPE_STP", - "ETHERTYPE_TALARIS", - "ETHERTYPE_TALARISMC", - "ETHERTYPE_TCPCOMP", - "ETHERTYPE_TCPSM", - "ETHERTYPE_TEC", - "ETHERTYPE_TIGAN", - "ETHERTYPE_TRAIL", - "ETHERTYPE_TRANSETHER", - "ETHERTYPE_TYMSHARE", - "ETHERTYPE_UBBST", - "ETHERTYPE_UBDEBUG", - "ETHERTYPE_UBDIAGLOOP", - "ETHERTYPE_UBDL", - "ETHERTYPE_UBNIU", - "ETHERTYPE_UBNMC", - "ETHERTYPE_VALID", - "ETHERTYPE_VARIAN", - "ETHERTYPE_VAXELN", - "ETHERTYPE_VEECO", - "ETHERTYPE_VEXP", - "ETHERTYPE_VGLAB", - "ETHERTYPE_VINES", - "ETHERTYPE_VINESECHO", - "ETHERTYPE_VINESLOOP", - "ETHERTYPE_VITAL", - "ETHERTYPE_VLAN", - "ETHERTYPE_VLTLMAN", - "ETHERTYPE_VPROD", - "ETHERTYPE_VURESERVED", - "ETHERTYPE_WATERLOO", - "ETHERTYPE_WELLFLEET", - "ETHERTYPE_X25", - "ETHERTYPE_X75", - "ETHERTYPE_XNSSM", - "ETHERTYPE_XTP", - "ETHER_ADDR_LEN", - "ETHER_ALIGN", - "ETHER_CRC_LEN", - "ETHER_CRC_POLY_BE", - "ETHER_CRC_POLY_LE", - "ETHER_HDR_LEN", - "ETHER_MAX_DIX_LEN", - "ETHER_MAX_LEN", - "ETHER_MAX_LEN_JUMBO", - "ETHER_MIN_LEN", - "ETHER_PPPOE_ENCAP_LEN", - "ETHER_TYPE_LEN", - "ETHER_VLAN_ENCAP_LEN", - "ETH_P_1588", - "ETH_P_8021Q", - "ETH_P_802_2", - "ETH_P_802_3", - "ETH_P_AARP", - "ETH_P_ALL", - "ETH_P_AOE", - "ETH_P_ARCNET", - "ETH_P_ARP", - "ETH_P_ATALK", - "ETH_P_ATMFATE", - "ETH_P_ATMMPOA", - "ETH_P_AX25", - "ETH_P_BPQ", - "ETH_P_CAIF", - "ETH_P_CAN", - "ETH_P_CONTROL", - "ETH_P_CUST", - "ETH_P_DDCMP", - "ETH_P_DEC", - "ETH_P_DIAG", - "ETH_P_DNA_DL", - "ETH_P_DNA_RC", - "ETH_P_DNA_RT", - "ETH_P_DSA", - "ETH_P_ECONET", - "ETH_P_EDSA", - "ETH_P_FCOE", - "ETH_P_FIP", - "ETH_P_HDLC", - "ETH_P_IEEE802154", - "ETH_P_IEEEPUP", - "ETH_P_IEEEPUPAT", - "ETH_P_IP", - "ETH_P_IPV6", - "ETH_P_IPX", - "ETH_P_IRDA", - "ETH_P_LAT", - "ETH_P_LINK_CTL", - "ETH_P_LOCALTALK", - "ETH_P_LOOP", - "ETH_P_MOBITEX", - "ETH_P_MPLS_MC", - "ETH_P_MPLS_UC", - "ETH_P_PAE", - "ETH_P_PAUSE", - "ETH_P_PHONET", - "ETH_P_PPPTALK", - "ETH_P_PPP_DISC", - "ETH_P_PPP_MP", - "ETH_P_PPP_SES", - "ETH_P_PUP", - "ETH_P_PUPAT", - "ETH_P_RARP", - "ETH_P_SCA", - "ETH_P_SLOW", - "ETH_P_SNAP", - "ETH_P_TEB", - "ETH_P_TIPC", - "ETH_P_TRAILER", - "ETH_P_TR_802_2", - "ETH_P_WAN_PPP", - "ETH_P_WCCP", - "ETH_P_X25", - "ETIME", - "ETIMEDOUT", - "ETOOMANYREFS", - "ETXTBSY", - "EUCLEAN", - "EUNATCH", - "EUSERS", - "EVFILT_AIO", - "EVFILT_FS", - "EVFILT_LIO", - "EVFILT_MACHPORT", - "EVFILT_PROC", - "EVFILT_READ", - "EVFILT_SIGNAL", - "EVFILT_SYSCOUNT", - "EVFILT_THREADMARKER", - "EVFILT_TIMER", - "EVFILT_USER", - "EVFILT_VM", - "EVFILT_VNODE", - "EVFILT_WRITE", - "EV_ADD", - "EV_CLEAR", - "EV_DELETE", - "EV_DISABLE", - "EV_DISPATCH", - "EV_DROP", - "EV_ENABLE", - "EV_EOF", - "EV_ERROR", - "EV_FLAG0", - "EV_FLAG1", - "EV_ONESHOT", - "EV_OOBAND", - "EV_POLL", - "EV_RECEIPT", - "EV_SYSFLAGS", - "EWINDOWS", - "EWOULDBLOCK", - "EXDEV", - "EXFULL", - "EXTA", - "EXTB", - "EXTPROC", - "Environ", - "EpollCreate", - "EpollCreate1", - "EpollCtl", - "EpollEvent", - "EpollWait", - "Errno", - "EscapeArg", - "Exchangedata", - "Exec", - "Exit", - "ExitProcess", - "FD_CLOEXEC", - "FD_SETSIZE", - "FILE_ACTION_ADDED", - "FILE_ACTION_MODIFIED", - "FILE_ACTION_REMOVED", - "FILE_ACTION_RENAMED_NEW_NAME", - "FILE_ACTION_RENAMED_OLD_NAME", - "FILE_APPEND_DATA", - "FILE_ATTRIBUTE_ARCHIVE", - "FILE_ATTRIBUTE_DIRECTORY", - "FILE_ATTRIBUTE_HIDDEN", - "FILE_ATTRIBUTE_NORMAL", - "FILE_ATTRIBUTE_READONLY", - "FILE_ATTRIBUTE_REPARSE_POINT", - "FILE_ATTRIBUTE_SYSTEM", - "FILE_BEGIN", - "FILE_CURRENT", - "FILE_END", - "FILE_FLAG_BACKUP_SEMANTICS", - "FILE_FLAG_OPEN_REPARSE_POINT", - "FILE_FLAG_OVERLAPPED", - "FILE_LIST_DIRECTORY", - "FILE_MAP_COPY", - "FILE_MAP_EXECUTE", - "FILE_MAP_READ", - "FILE_MAP_WRITE", - "FILE_NOTIFY_CHANGE_ATTRIBUTES", - "FILE_NOTIFY_CHANGE_CREATION", - "FILE_NOTIFY_CHANGE_DIR_NAME", - "FILE_NOTIFY_CHANGE_FILE_NAME", - "FILE_NOTIFY_CHANGE_LAST_ACCESS", - "FILE_NOTIFY_CHANGE_LAST_WRITE", - "FILE_NOTIFY_CHANGE_SIZE", - "FILE_SHARE_DELETE", - "FILE_SHARE_READ", - "FILE_SHARE_WRITE", - "FILE_SKIP_COMPLETION_PORT_ON_SUCCESS", - "FILE_SKIP_SET_EVENT_ON_HANDLE", - "FILE_TYPE_CHAR", - "FILE_TYPE_DISK", - "FILE_TYPE_PIPE", - "FILE_TYPE_REMOTE", - "FILE_TYPE_UNKNOWN", - "FILE_WRITE_ATTRIBUTES", - "FLUSHO", - "FORMAT_MESSAGE_ALLOCATE_BUFFER", - "FORMAT_MESSAGE_ARGUMENT_ARRAY", - "FORMAT_MESSAGE_FROM_HMODULE", - "FORMAT_MESSAGE_FROM_STRING", - "FORMAT_MESSAGE_FROM_SYSTEM", - "FORMAT_MESSAGE_IGNORE_INSERTS", - "FORMAT_MESSAGE_MAX_WIDTH_MASK", - "FSCTL_GET_REPARSE_POINT", - "F_ADDFILESIGS", - "F_ADDSIGS", - "F_ALLOCATEALL", - "F_ALLOCATECONTIG", - "F_CANCEL", - "F_CHKCLEAN", - "F_CLOSEM", - "F_DUP2FD", - "F_DUP2FD_CLOEXEC", - "F_DUPFD", - "F_DUPFD_CLOEXEC", - "F_EXLCK", - "F_FINDSIGS", - "F_FLUSH_DATA", - "F_FREEZE_FS", - "F_FSCTL", - "F_FSDIRMASK", - "F_FSIN", - "F_FSINOUT", - "F_FSOUT", - "F_FSPRIV", - "F_FSVOID", - "F_FULLFSYNC", - "F_GETCODEDIR", - "F_GETFD", - "F_GETFL", - "F_GETLEASE", - "F_GETLK", - "F_GETLK64", - "F_GETLKPID", - "F_GETNOSIGPIPE", - "F_GETOWN", - "F_GETOWN_EX", - "F_GETPATH", - "F_GETPATH_MTMINFO", - "F_GETPIPE_SZ", - "F_GETPROTECTIONCLASS", - "F_GETPROTECTIONLEVEL", - "F_GETSIG", - "F_GLOBAL_NOCACHE", - "F_LOCK", - "F_LOG2PHYS", - "F_LOG2PHYS_EXT", - "F_MARKDEPENDENCY", - "F_MAXFD", - "F_NOCACHE", - "F_NODIRECT", - "F_NOTIFY", - "F_OGETLK", - "F_OK", - "F_OSETLK", - "F_OSETLKW", - "F_PARAM_MASK", - "F_PARAM_MAX", - "F_PATHPKG_CHECK", - "F_PEOFPOSMODE", - "F_PREALLOCATE", - "F_RDADVISE", - "F_RDAHEAD", - "F_RDLCK", - "F_READAHEAD", - "F_READBOOTSTRAP", - "F_SETBACKINGSTORE", - "F_SETFD", - "F_SETFL", - "F_SETLEASE", - "F_SETLK", - "F_SETLK64", - "F_SETLKW", - "F_SETLKW64", - "F_SETLKWTIMEOUT", - "F_SETLK_REMOTE", - "F_SETNOSIGPIPE", - "F_SETOWN", - "F_SETOWN_EX", - "F_SETPIPE_SZ", - "F_SETPROTECTIONCLASS", - "F_SETSIG", - "F_SETSIZE", - "F_SHLCK", - "F_SINGLE_WRITER", - "F_TEST", - "F_THAW_FS", - "F_TLOCK", - "F_TRANSCODEKEY", - "F_ULOCK", - "F_UNLCK", - "F_UNLCKSYS", - "F_VOLPOSMODE", - "F_WRITEBOOTSTRAP", - "F_WRLCK", - "Faccessat", - "Fallocate", - "Fbootstraptransfer_t", - "Fchdir", - "Fchflags", - "Fchmod", - "Fchmodat", - "Fchown", - "Fchownat", - "FcntlFlock", - "FdSet", - "Fdatasync", - "FileNotifyInformation", - "Filetime", - "FindClose", - "FindFirstFile", - "FindNextFile", - "Flock", - "Flock_t", - "FlushBpf", - "FlushFileBuffers", - "FlushViewOfFile", - "ForkExec", - "ForkLock", - "FormatMessage", - "Fpathconf", - "FreeAddrInfoW", - "FreeEnvironmentStrings", - "FreeLibrary", - "Fsid", - "Fstat", - "Fstatat", - "Fstatfs", - "Fstore_t", - "Fsync", - "Ftruncate", - "FullPath", - "Futimes", - "Futimesat", - "GENERIC_ALL", - "GENERIC_EXECUTE", - "GENERIC_READ", - "GENERIC_WRITE", - "GUID", - "GetAcceptExSockaddrs", - "GetAdaptersInfo", - "GetAddrInfoW", - "GetCommandLine", - "GetComputerName", - "GetConsoleMode", - "GetCurrentDirectory", - "GetCurrentProcess", - "GetEnvironmentStrings", - "GetEnvironmentVariable", - "GetExitCodeProcess", - "GetFileAttributes", - "GetFileAttributesEx", - "GetFileExInfoStandard", - "GetFileExMaxInfoLevel", - "GetFileInformationByHandle", - "GetFileType", - "GetFullPathName", - "GetHostByName", - "GetIfEntry", - "GetLastError", - "GetLengthSid", - "GetLongPathName", - "GetProcAddress", - "GetProcessTimes", - "GetProtoByName", - "GetQueuedCompletionStatus", - "GetServByName", - "GetShortPathName", - "GetStartupInfo", - "GetStdHandle", - "GetSystemTimeAsFileTime", - "GetTempPath", - "GetTimeZoneInformation", - "GetTokenInformation", - "GetUserNameEx", - "GetUserProfileDirectory", - "GetVersion", - "Getcwd", - "Getdents", - "Getdirentries", - "Getdtablesize", - "Getegid", - "Getenv", - "Geteuid", - "Getfsstat", - "Getgid", - "Getgroups", - "Getpagesize", - "Getpeername", - "Getpgid", - "Getpgrp", - "Getpid", - "Getppid", - "Getpriority", - "Getrlimit", - "Getrusage", - "Getsid", - "Getsockname", - "Getsockopt", - "GetsockoptByte", - "GetsockoptICMPv6Filter", - "GetsockoptIPMreq", - "GetsockoptIPMreqn", - "GetsockoptIPv6MTUInfo", - "GetsockoptIPv6Mreq", - "GetsockoptInet4Addr", - "GetsockoptInt", - "GetsockoptUcred", - "Gettid", - "Gettimeofday", - "Getuid", - "Getwd", - "Getxattr", - "HANDLE_FLAG_INHERIT", - "HKEY_CLASSES_ROOT", - "HKEY_CURRENT_CONFIG", - "HKEY_CURRENT_USER", - "HKEY_DYN_DATA", - "HKEY_LOCAL_MACHINE", - "HKEY_PERFORMANCE_DATA", - "HKEY_USERS", - "HUPCL", - "Handle", - "Hostent", - "ICANON", - "ICMP6_FILTER", - "ICMPV6_FILTER", - "ICMPv6Filter", - "ICRNL", - "IEXTEN", - "IFAN_ARRIVAL", - "IFAN_DEPARTURE", - "IFA_ADDRESS", - "IFA_ANYCAST", - "IFA_BROADCAST", - "IFA_CACHEINFO", - "IFA_F_DADFAILED", - "IFA_F_DEPRECATED", - "IFA_F_HOMEADDRESS", - "IFA_F_NODAD", - "IFA_F_OPTIMISTIC", - "IFA_F_PERMANENT", - "IFA_F_SECONDARY", - "IFA_F_TEMPORARY", - "IFA_F_TENTATIVE", - "IFA_LABEL", - "IFA_LOCAL", - "IFA_MAX", - "IFA_MULTICAST", - "IFA_ROUTE", - "IFA_UNSPEC", - "IFF_ALLMULTI", - "IFF_ALTPHYS", - "IFF_AUTOMEDIA", - "IFF_BROADCAST", - "IFF_CANTCHANGE", - "IFF_CANTCONFIG", - "IFF_DEBUG", - "IFF_DRV_OACTIVE", - "IFF_DRV_RUNNING", - "IFF_DYING", - "IFF_DYNAMIC", - "IFF_LINK0", - "IFF_LINK1", - "IFF_LINK2", - "IFF_LOOPBACK", - "IFF_MASTER", - "IFF_MONITOR", - "IFF_MULTICAST", - "IFF_NOARP", - "IFF_NOTRAILERS", - "IFF_NO_PI", - "IFF_OACTIVE", - "IFF_ONE_QUEUE", - "IFF_POINTOPOINT", - "IFF_POINTTOPOINT", - "IFF_PORTSEL", - "IFF_PPROMISC", - "IFF_PROMISC", - "IFF_RENAMING", - "IFF_RUNNING", - "IFF_SIMPLEX", - "IFF_SLAVE", - "IFF_SMART", - "IFF_STATICARP", - "IFF_TAP", - "IFF_TUN", - "IFF_TUN_EXCL", - "IFF_UP", - "IFF_VNET_HDR", - "IFLA_ADDRESS", - "IFLA_BROADCAST", - "IFLA_COST", - "IFLA_IFALIAS", - "IFLA_IFNAME", - "IFLA_LINK", - "IFLA_LINKINFO", - "IFLA_LINKMODE", - "IFLA_MAP", - "IFLA_MASTER", - "IFLA_MAX", - "IFLA_MTU", - "IFLA_NET_NS_PID", - "IFLA_OPERSTATE", - "IFLA_PRIORITY", - "IFLA_PROTINFO", - "IFLA_QDISC", - "IFLA_STATS", - "IFLA_TXQLEN", - "IFLA_UNSPEC", - "IFLA_WEIGHT", - "IFLA_WIRELESS", - "IFNAMSIZ", - "IFT_1822", - "IFT_A12MPPSWITCH", - "IFT_AAL2", - "IFT_AAL5", - "IFT_ADSL", - "IFT_AFLANE8023", - "IFT_AFLANE8025", - "IFT_ARAP", - "IFT_ARCNET", - "IFT_ARCNETPLUS", - "IFT_ASYNC", - "IFT_ATM", - "IFT_ATMDXI", - "IFT_ATMFUNI", - "IFT_ATMIMA", - "IFT_ATMLOGICAL", - "IFT_ATMRADIO", - "IFT_ATMSUBINTERFACE", - "IFT_ATMVCIENDPT", - "IFT_ATMVIRTUAL", - "IFT_BGPPOLICYACCOUNTING", - "IFT_BLUETOOTH", - "IFT_BRIDGE", - "IFT_BSC", - "IFT_CARP", - "IFT_CCTEMUL", - "IFT_CELLULAR", - "IFT_CEPT", - "IFT_CES", - "IFT_CHANNEL", - "IFT_CNR", - "IFT_COFFEE", - "IFT_COMPOSITELINK", - "IFT_DCN", - "IFT_DIGITALPOWERLINE", - "IFT_DIGITALWRAPPEROVERHEADCHANNEL", - "IFT_DLSW", - "IFT_DOCSCABLEDOWNSTREAM", - "IFT_DOCSCABLEMACLAYER", - "IFT_DOCSCABLEUPSTREAM", - "IFT_DOCSCABLEUPSTREAMCHANNEL", - "IFT_DS0", - "IFT_DS0BUNDLE", - "IFT_DS1FDL", - "IFT_DS3", - "IFT_DTM", - "IFT_DUMMY", - "IFT_DVBASILN", - "IFT_DVBASIOUT", - "IFT_DVBRCCDOWNSTREAM", - "IFT_DVBRCCMACLAYER", - "IFT_DVBRCCUPSTREAM", - "IFT_ECONET", - "IFT_ENC", - "IFT_EON", - "IFT_EPLRS", - "IFT_ESCON", - "IFT_ETHER", - "IFT_FAITH", - "IFT_FAST", - "IFT_FASTETHER", - "IFT_FASTETHERFX", - "IFT_FDDI", - "IFT_FIBRECHANNEL", - "IFT_FRAMERELAYINTERCONNECT", - "IFT_FRAMERELAYMPI", - "IFT_FRDLCIENDPT", - "IFT_FRELAY", - "IFT_FRELAYDCE", - "IFT_FRF16MFRBUNDLE", - "IFT_FRFORWARD", - "IFT_G703AT2MB", - "IFT_G703AT64K", - "IFT_GIF", - "IFT_GIGABITETHERNET", - "IFT_GR303IDT", - "IFT_GR303RDT", - "IFT_H323GATEKEEPER", - "IFT_H323PROXY", - "IFT_HDH1822", - "IFT_HDLC", - "IFT_HDSL2", - "IFT_HIPERLAN2", - "IFT_HIPPI", - "IFT_HIPPIINTERFACE", - "IFT_HOSTPAD", - "IFT_HSSI", - "IFT_HY", - "IFT_IBM370PARCHAN", - "IFT_IDSL", - "IFT_IEEE1394", - "IFT_IEEE80211", - "IFT_IEEE80212", - "IFT_IEEE8023ADLAG", - "IFT_IFGSN", - "IFT_IMT", - "IFT_INFINIBAND", - "IFT_INTERLEAVE", - "IFT_IP", - "IFT_IPFORWARD", - "IFT_IPOVERATM", - "IFT_IPOVERCDLC", - "IFT_IPOVERCLAW", - "IFT_IPSWITCH", - "IFT_IPXIP", - "IFT_ISDN", - "IFT_ISDNBASIC", - "IFT_ISDNPRIMARY", - "IFT_ISDNS", - "IFT_ISDNU", - "IFT_ISO88022LLC", - "IFT_ISO88023", - "IFT_ISO88024", - "IFT_ISO88025", - "IFT_ISO88025CRFPINT", - "IFT_ISO88025DTR", - "IFT_ISO88025FIBER", - "IFT_ISO88026", - "IFT_ISUP", - "IFT_L2VLAN", - "IFT_L3IPVLAN", - "IFT_L3IPXVLAN", - "IFT_LAPB", - "IFT_LAPD", - "IFT_LAPF", - "IFT_LINEGROUP", - "IFT_LOCALTALK", - "IFT_LOOP", - "IFT_MEDIAMAILOVERIP", - "IFT_MFSIGLINK", - "IFT_MIOX25", - "IFT_MODEM", - "IFT_MPC", - "IFT_MPLS", - "IFT_MPLSTUNNEL", - "IFT_MSDSL", - "IFT_MVL", - "IFT_MYRINET", - "IFT_NFAS", - "IFT_NSIP", - "IFT_OPTICALCHANNEL", - "IFT_OPTICALTRANSPORT", - "IFT_OTHER", - "IFT_P10", - "IFT_P80", - "IFT_PARA", - "IFT_PDP", - "IFT_PFLOG", - "IFT_PFLOW", - "IFT_PFSYNC", - "IFT_PLC", - "IFT_PON155", - "IFT_PON622", - "IFT_POS", - "IFT_PPP", - "IFT_PPPMULTILINKBUNDLE", - "IFT_PROPATM", - "IFT_PROPBWAP2MP", - "IFT_PROPCNLS", - "IFT_PROPDOCSWIRELESSDOWNSTREAM", - "IFT_PROPDOCSWIRELESSMACLAYER", - "IFT_PROPDOCSWIRELESSUPSTREAM", - "IFT_PROPMUX", - "IFT_PROPVIRTUAL", - "IFT_PROPWIRELESSP2P", - "IFT_PTPSERIAL", - "IFT_PVC", - "IFT_Q2931", - "IFT_QLLC", - "IFT_RADIOMAC", - "IFT_RADSL", - "IFT_REACHDSL", - "IFT_RFC1483", - "IFT_RS232", - "IFT_RSRB", - "IFT_SDLC", - "IFT_SDSL", - "IFT_SHDSL", - "IFT_SIP", - "IFT_SIPSIG", - "IFT_SIPTG", - "IFT_SLIP", - "IFT_SMDSDXI", - "IFT_SMDSICIP", - "IFT_SONET", - "IFT_SONETOVERHEADCHANNEL", - "IFT_SONETPATH", - "IFT_SONETVT", - "IFT_SRP", - "IFT_SS7SIGLINK", - "IFT_STACKTOSTACK", - "IFT_STARLAN", - "IFT_STF", - "IFT_T1", - "IFT_TDLC", - "IFT_TELINK", - "IFT_TERMPAD", - "IFT_TR008", - "IFT_TRANSPHDLC", - "IFT_TUNNEL", - "IFT_ULTRA", - "IFT_USB", - "IFT_V11", - "IFT_V35", - "IFT_V36", - "IFT_V37", - "IFT_VDSL", - "IFT_VIRTUALIPADDRESS", - "IFT_VIRTUALTG", - "IFT_VOICEDID", - "IFT_VOICEEM", - "IFT_VOICEEMFGD", - "IFT_VOICEENCAP", - "IFT_VOICEFGDEANA", - "IFT_VOICEFXO", - "IFT_VOICEFXS", - "IFT_VOICEOVERATM", - "IFT_VOICEOVERCABLE", - "IFT_VOICEOVERFRAMERELAY", - "IFT_VOICEOVERIP", - "IFT_X213", - "IFT_X25", - "IFT_X25DDN", - "IFT_X25HUNTGROUP", - "IFT_X25MLP", - "IFT_X25PLE", - "IFT_XETHER", - "IGNBRK", - "IGNCR", - "IGNORE", - "IGNPAR", - "IMAXBEL", - "INFINITE", - "INLCR", - "INPCK", - "INVALID_FILE_ATTRIBUTES", - "IN_ACCESS", - "IN_ALL_EVENTS", - "IN_ATTRIB", - "IN_CLASSA_HOST", - "IN_CLASSA_MAX", - "IN_CLASSA_NET", - "IN_CLASSA_NSHIFT", - "IN_CLASSB_HOST", - "IN_CLASSB_MAX", - "IN_CLASSB_NET", - "IN_CLASSB_NSHIFT", - "IN_CLASSC_HOST", - "IN_CLASSC_NET", - "IN_CLASSC_NSHIFT", - "IN_CLASSD_HOST", - "IN_CLASSD_NET", - "IN_CLASSD_NSHIFT", - "IN_CLOEXEC", - "IN_CLOSE", - "IN_CLOSE_NOWRITE", - "IN_CLOSE_WRITE", - "IN_CREATE", - "IN_DELETE", - "IN_DELETE_SELF", - "IN_DONT_FOLLOW", - "IN_EXCL_UNLINK", - "IN_IGNORED", - "IN_ISDIR", - "IN_LINKLOCALNETNUM", - "IN_LOOPBACKNET", - "IN_MASK_ADD", - "IN_MODIFY", - "IN_MOVE", - "IN_MOVED_FROM", - "IN_MOVED_TO", - "IN_MOVE_SELF", - "IN_NONBLOCK", - "IN_ONESHOT", - "IN_ONLYDIR", - "IN_OPEN", - "IN_Q_OVERFLOW", - "IN_RFC3021_HOST", - "IN_RFC3021_MASK", - "IN_RFC3021_NET", - "IN_RFC3021_NSHIFT", - "IN_UNMOUNT", - "IOC_IN", - "IOC_INOUT", - "IOC_OUT", - "IOC_VENDOR", - "IOC_WS2", - "IO_REPARSE_TAG_SYMLINK", - "IPMreq", - "IPMreqn", - "IPPROTO_3PC", - "IPPROTO_ADFS", - "IPPROTO_AH", - "IPPROTO_AHIP", - "IPPROTO_APES", - "IPPROTO_ARGUS", - "IPPROTO_AX25", - "IPPROTO_BHA", - "IPPROTO_BLT", - "IPPROTO_BRSATMON", - "IPPROTO_CARP", - "IPPROTO_CFTP", - "IPPROTO_CHAOS", - "IPPROTO_CMTP", - "IPPROTO_COMP", - "IPPROTO_CPHB", - "IPPROTO_CPNX", - "IPPROTO_DCCP", - "IPPROTO_DDP", - "IPPROTO_DGP", - "IPPROTO_DIVERT", - "IPPROTO_DIVERT_INIT", - "IPPROTO_DIVERT_RESP", - "IPPROTO_DONE", - "IPPROTO_DSTOPTS", - "IPPROTO_EGP", - "IPPROTO_EMCON", - "IPPROTO_ENCAP", - "IPPROTO_EON", - "IPPROTO_ESP", - "IPPROTO_ETHERIP", - "IPPROTO_FRAGMENT", - "IPPROTO_GGP", - "IPPROTO_GMTP", - "IPPROTO_GRE", - "IPPROTO_HELLO", - "IPPROTO_HMP", - "IPPROTO_HOPOPTS", - "IPPROTO_ICMP", - "IPPROTO_ICMPV6", - "IPPROTO_IDP", - "IPPROTO_IDPR", - "IPPROTO_IDRP", - "IPPROTO_IGMP", - "IPPROTO_IGP", - "IPPROTO_IGRP", - "IPPROTO_IL", - "IPPROTO_INLSP", - "IPPROTO_INP", - "IPPROTO_IP", - "IPPROTO_IPCOMP", - "IPPROTO_IPCV", - "IPPROTO_IPEIP", - "IPPROTO_IPIP", - "IPPROTO_IPPC", - "IPPROTO_IPV4", - "IPPROTO_IPV6", - "IPPROTO_IPV6_ICMP", - "IPPROTO_IRTP", - "IPPROTO_KRYPTOLAN", - "IPPROTO_LARP", - "IPPROTO_LEAF1", - "IPPROTO_LEAF2", - "IPPROTO_MAX", - "IPPROTO_MAXID", - "IPPROTO_MEAS", - "IPPROTO_MH", - "IPPROTO_MHRP", - "IPPROTO_MICP", - "IPPROTO_MOBILE", - "IPPROTO_MPLS", - "IPPROTO_MTP", - "IPPROTO_MUX", - "IPPROTO_ND", - "IPPROTO_NHRP", - "IPPROTO_NONE", - "IPPROTO_NSP", - "IPPROTO_NVPII", - "IPPROTO_OLD_DIVERT", - "IPPROTO_OSPFIGP", - "IPPROTO_PFSYNC", - "IPPROTO_PGM", - "IPPROTO_PIGP", - "IPPROTO_PIM", - "IPPROTO_PRM", - "IPPROTO_PUP", - "IPPROTO_PVP", - "IPPROTO_RAW", - "IPPROTO_RCCMON", - "IPPROTO_RDP", - "IPPROTO_ROUTING", - "IPPROTO_RSVP", - "IPPROTO_RVD", - "IPPROTO_SATEXPAK", - "IPPROTO_SATMON", - "IPPROTO_SCCSP", - "IPPROTO_SCTP", - "IPPROTO_SDRP", - "IPPROTO_SEND", - "IPPROTO_SEP", - "IPPROTO_SKIP", - "IPPROTO_SPACER", - "IPPROTO_SRPC", - "IPPROTO_ST", - "IPPROTO_SVMTP", - "IPPROTO_SWIPE", - "IPPROTO_TCF", - "IPPROTO_TCP", - "IPPROTO_TLSP", - "IPPROTO_TP", - "IPPROTO_TPXX", - "IPPROTO_TRUNK1", - "IPPROTO_TRUNK2", - "IPPROTO_TTP", - "IPPROTO_UDP", - "IPPROTO_UDPLITE", - "IPPROTO_VINES", - "IPPROTO_VISA", - "IPPROTO_VMTP", - "IPPROTO_VRRP", - "IPPROTO_WBEXPAK", - "IPPROTO_WBMON", - "IPPROTO_WSN", - "IPPROTO_XNET", - "IPPROTO_XTP", - "IPV6_2292DSTOPTS", - "IPV6_2292HOPLIMIT", - "IPV6_2292HOPOPTS", - "IPV6_2292NEXTHOP", - "IPV6_2292PKTINFO", - "IPV6_2292PKTOPTIONS", - "IPV6_2292RTHDR", - "IPV6_ADDRFORM", - "IPV6_ADD_MEMBERSHIP", - "IPV6_AUTHHDR", - "IPV6_AUTH_LEVEL", - "IPV6_AUTOFLOWLABEL", - "IPV6_BINDANY", - "IPV6_BINDV6ONLY", - "IPV6_BOUND_IF", - "IPV6_CHECKSUM", - "IPV6_DEFAULT_MULTICAST_HOPS", - "IPV6_DEFAULT_MULTICAST_LOOP", - "IPV6_DEFHLIM", - "IPV6_DONTFRAG", - "IPV6_DROP_MEMBERSHIP", - "IPV6_DSTOPTS", - "IPV6_ESP_NETWORK_LEVEL", - "IPV6_ESP_TRANS_LEVEL", - "IPV6_FAITH", - "IPV6_FLOWINFO_MASK", - "IPV6_FLOWLABEL_MASK", - "IPV6_FRAGTTL", - "IPV6_FW_ADD", - "IPV6_FW_DEL", - "IPV6_FW_FLUSH", - "IPV6_FW_GET", - "IPV6_FW_ZERO", - "IPV6_HLIMDEC", - "IPV6_HOPLIMIT", - "IPV6_HOPOPTS", - "IPV6_IPCOMP_LEVEL", - "IPV6_IPSEC_POLICY", - "IPV6_JOIN_ANYCAST", - "IPV6_JOIN_GROUP", - "IPV6_LEAVE_ANYCAST", - "IPV6_LEAVE_GROUP", - "IPV6_MAXHLIM", - "IPV6_MAXOPTHDR", - "IPV6_MAXPACKET", - "IPV6_MAX_GROUP_SRC_FILTER", - "IPV6_MAX_MEMBERSHIPS", - "IPV6_MAX_SOCK_SRC_FILTER", - "IPV6_MIN_MEMBERSHIPS", - "IPV6_MMTU", - "IPV6_MSFILTER", - "IPV6_MTU", - "IPV6_MTU_DISCOVER", - "IPV6_MULTICAST_HOPS", - "IPV6_MULTICAST_IF", - "IPV6_MULTICAST_LOOP", - "IPV6_NEXTHOP", - "IPV6_OPTIONS", - "IPV6_PATHMTU", - "IPV6_PIPEX", - "IPV6_PKTINFO", - "IPV6_PMTUDISC_DO", - "IPV6_PMTUDISC_DONT", - "IPV6_PMTUDISC_PROBE", - "IPV6_PMTUDISC_WANT", - "IPV6_PORTRANGE", - "IPV6_PORTRANGE_DEFAULT", - "IPV6_PORTRANGE_HIGH", - "IPV6_PORTRANGE_LOW", - "IPV6_PREFER_TEMPADDR", - "IPV6_RECVDSTOPTS", - "IPV6_RECVDSTPORT", - "IPV6_RECVERR", - "IPV6_RECVHOPLIMIT", - "IPV6_RECVHOPOPTS", - "IPV6_RECVPATHMTU", - "IPV6_RECVPKTINFO", - "IPV6_RECVRTHDR", - "IPV6_RECVTCLASS", - "IPV6_ROUTER_ALERT", - "IPV6_RTABLE", - "IPV6_RTHDR", - "IPV6_RTHDRDSTOPTS", - "IPV6_RTHDR_LOOSE", - "IPV6_RTHDR_STRICT", - "IPV6_RTHDR_TYPE_0", - "IPV6_RXDSTOPTS", - "IPV6_RXHOPOPTS", - "IPV6_SOCKOPT_RESERVED1", - "IPV6_TCLASS", - "IPV6_UNICAST_HOPS", - "IPV6_USE_MIN_MTU", - "IPV6_V6ONLY", - "IPV6_VERSION", - "IPV6_VERSION_MASK", - "IPV6_XFRM_POLICY", - "IP_ADD_MEMBERSHIP", - "IP_ADD_SOURCE_MEMBERSHIP", - "IP_AUTH_LEVEL", - "IP_BINDANY", - "IP_BLOCK_SOURCE", - "IP_BOUND_IF", - "IP_DEFAULT_MULTICAST_LOOP", - "IP_DEFAULT_MULTICAST_TTL", - "IP_DF", - "IP_DIVERTFL", - "IP_DONTFRAG", - "IP_DROP_MEMBERSHIP", - "IP_DROP_SOURCE_MEMBERSHIP", - "IP_DUMMYNET3", - "IP_DUMMYNET_CONFIGURE", - "IP_DUMMYNET_DEL", - "IP_DUMMYNET_FLUSH", - "IP_DUMMYNET_GET", - "IP_EF", - "IP_ERRORMTU", - "IP_ESP_NETWORK_LEVEL", - "IP_ESP_TRANS_LEVEL", - "IP_FAITH", - "IP_FREEBIND", - "IP_FW3", - "IP_FW_ADD", - "IP_FW_DEL", - "IP_FW_FLUSH", - "IP_FW_GET", - "IP_FW_NAT_CFG", - "IP_FW_NAT_DEL", - "IP_FW_NAT_GET_CONFIG", - "IP_FW_NAT_GET_LOG", - "IP_FW_RESETLOG", - "IP_FW_TABLE_ADD", - "IP_FW_TABLE_DEL", - "IP_FW_TABLE_FLUSH", - "IP_FW_TABLE_GETSIZE", - "IP_FW_TABLE_LIST", - "IP_FW_ZERO", - "IP_HDRINCL", - "IP_IPCOMP_LEVEL", - "IP_IPSECFLOWINFO", - "IP_IPSEC_LOCAL_AUTH", - "IP_IPSEC_LOCAL_CRED", - "IP_IPSEC_LOCAL_ID", - "IP_IPSEC_POLICY", - "IP_IPSEC_REMOTE_AUTH", - "IP_IPSEC_REMOTE_CRED", - "IP_IPSEC_REMOTE_ID", - "IP_MAXPACKET", - "IP_MAX_GROUP_SRC_FILTER", - "IP_MAX_MEMBERSHIPS", - "IP_MAX_SOCK_MUTE_FILTER", - "IP_MAX_SOCK_SRC_FILTER", - "IP_MAX_SOURCE_FILTER", - "IP_MF", - "IP_MINFRAGSIZE", - "IP_MINTTL", - "IP_MIN_MEMBERSHIPS", - "IP_MSFILTER", - "IP_MSS", - "IP_MTU", - "IP_MTU_DISCOVER", - "IP_MULTICAST_IF", - "IP_MULTICAST_IFINDEX", - "IP_MULTICAST_LOOP", - "IP_MULTICAST_TTL", - "IP_MULTICAST_VIF", - "IP_NAT__XXX", - "IP_OFFMASK", - "IP_OLD_FW_ADD", - "IP_OLD_FW_DEL", - "IP_OLD_FW_FLUSH", - "IP_OLD_FW_GET", - "IP_OLD_FW_RESETLOG", - "IP_OLD_FW_ZERO", - "IP_ONESBCAST", - "IP_OPTIONS", - "IP_ORIGDSTADDR", - "IP_PASSSEC", - "IP_PIPEX", - "IP_PKTINFO", - "IP_PKTOPTIONS", - "IP_PMTUDISC", - "IP_PMTUDISC_DO", - "IP_PMTUDISC_DONT", - "IP_PMTUDISC_PROBE", - "IP_PMTUDISC_WANT", - "IP_PORTRANGE", - "IP_PORTRANGE_DEFAULT", - "IP_PORTRANGE_HIGH", - "IP_PORTRANGE_LOW", - "IP_RECVDSTADDR", - "IP_RECVDSTPORT", - "IP_RECVERR", - "IP_RECVIF", - "IP_RECVOPTS", - "IP_RECVORIGDSTADDR", - "IP_RECVPKTINFO", - "IP_RECVRETOPTS", - "IP_RECVRTABLE", - "IP_RECVTOS", - "IP_RECVTTL", - "IP_RETOPTS", - "IP_RF", - "IP_ROUTER_ALERT", - "IP_RSVP_OFF", - "IP_RSVP_ON", - "IP_RSVP_VIF_OFF", - "IP_RSVP_VIF_ON", - "IP_RTABLE", - "IP_SENDSRCADDR", - "IP_STRIPHDR", - "IP_TOS", - "IP_TRAFFIC_MGT_BACKGROUND", - "IP_TRANSPARENT", - "IP_TTL", - "IP_UNBLOCK_SOURCE", - "IP_XFRM_POLICY", - "IPv6MTUInfo", - "IPv6Mreq", - "ISIG", - "ISTRIP", - "IUCLC", - "IUTF8", - "IXANY", - "IXOFF", - "IXON", - "IfAddrmsg", - "IfAnnounceMsghdr", - "IfData", - "IfInfomsg", - "IfMsghdr", - "IfaMsghdr", - "IfmaMsghdr", - "IfmaMsghdr2", - "ImplementsGetwd", - "Inet4Pktinfo", - "Inet6Pktinfo", - "InotifyAddWatch", - "InotifyEvent", - "InotifyInit", - "InotifyInit1", - "InotifyRmWatch", - "InterfaceAddrMessage", - "InterfaceAnnounceMessage", - "InterfaceInfo", - "InterfaceMessage", - "InterfaceMulticastAddrMessage", - "InvalidHandle", - "Ioperm", - "Iopl", - "Iovec", - "IpAdapterInfo", - "IpAddrString", - "IpAddressString", - "IpMaskString", - "Issetugid", - "KEY_ALL_ACCESS", - "KEY_CREATE_LINK", - "KEY_CREATE_SUB_KEY", - "KEY_ENUMERATE_SUB_KEYS", - "KEY_EXECUTE", - "KEY_NOTIFY", - "KEY_QUERY_VALUE", - "KEY_READ", - "KEY_SET_VALUE", - "KEY_WOW64_32KEY", - "KEY_WOW64_64KEY", - "KEY_WRITE", - "Kevent", - "Kevent_t", - "Kill", - "Klogctl", - "Kqueue", - "LANG_ENGLISH", - "LAYERED_PROTOCOL", - "LCNT_OVERLOAD_FLUSH", - "LINUX_REBOOT_CMD_CAD_OFF", - "LINUX_REBOOT_CMD_CAD_ON", - "LINUX_REBOOT_CMD_HALT", - "LINUX_REBOOT_CMD_KEXEC", - "LINUX_REBOOT_CMD_POWER_OFF", - "LINUX_REBOOT_CMD_RESTART", - "LINUX_REBOOT_CMD_RESTART2", - "LINUX_REBOOT_CMD_SW_SUSPEND", - "LINUX_REBOOT_MAGIC1", - "LINUX_REBOOT_MAGIC2", - "LOCK_EX", - "LOCK_NB", - "LOCK_SH", - "LOCK_UN", - "LazyDLL", - "LazyProc", - "Lchown", - "Linger", - "Link", - "Listen", - "Listxattr", - "LoadCancelIoEx", - "LoadConnectEx", - "LoadCreateSymbolicLink", - "LoadDLL", - "LoadGetAddrInfo", - "LoadLibrary", - "LoadSetFileCompletionNotificationModes", - "LocalFree", - "Log2phys_t", - "LookupAccountName", - "LookupAccountSid", - "LookupSID", - "LsfJump", - "LsfSocket", - "LsfStmt", - "Lstat", - "MADV_AUTOSYNC", - "MADV_CAN_REUSE", - "MADV_CORE", - "MADV_DOFORK", - "MADV_DONTFORK", - "MADV_DONTNEED", - "MADV_FREE", - "MADV_FREE_REUSABLE", - "MADV_FREE_REUSE", - "MADV_HUGEPAGE", - "MADV_HWPOISON", - "MADV_MERGEABLE", - "MADV_NOCORE", - "MADV_NOHUGEPAGE", - "MADV_NORMAL", - "MADV_NOSYNC", - "MADV_PROTECT", - "MADV_RANDOM", - "MADV_REMOVE", - "MADV_SEQUENTIAL", - "MADV_SPACEAVAIL", - "MADV_UNMERGEABLE", - "MADV_WILLNEED", - "MADV_ZERO_WIRED_PAGES", - "MAP_32BIT", - "MAP_ALIGNED_SUPER", - "MAP_ALIGNMENT_16MB", - "MAP_ALIGNMENT_1TB", - "MAP_ALIGNMENT_256TB", - "MAP_ALIGNMENT_4GB", - "MAP_ALIGNMENT_64KB", - "MAP_ALIGNMENT_64PB", - "MAP_ALIGNMENT_MASK", - "MAP_ALIGNMENT_SHIFT", - "MAP_ANON", - "MAP_ANONYMOUS", - "MAP_COPY", - "MAP_DENYWRITE", - "MAP_EXECUTABLE", - "MAP_FILE", - "MAP_FIXED", - "MAP_FLAGMASK", - "MAP_GROWSDOWN", - "MAP_HASSEMAPHORE", - "MAP_HUGETLB", - "MAP_INHERIT", - "MAP_INHERIT_COPY", - "MAP_INHERIT_DEFAULT", - "MAP_INHERIT_DONATE_COPY", - "MAP_INHERIT_NONE", - "MAP_INHERIT_SHARE", - "MAP_JIT", - "MAP_LOCKED", - "MAP_NOCACHE", - "MAP_NOCORE", - "MAP_NOEXTEND", - "MAP_NONBLOCK", - "MAP_NORESERVE", - "MAP_NOSYNC", - "MAP_POPULATE", - "MAP_PREFAULT_READ", - "MAP_PRIVATE", - "MAP_RENAME", - "MAP_RESERVED0080", - "MAP_RESERVED0100", - "MAP_SHARED", - "MAP_STACK", - "MAP_TRYFIXED", - "MAP_TYPE", - "MAP_WIRED", - "MAXIMUM_REPARSE_DATA_BUFFER_SIZE", - "MAXLEN_IFDESCR", - "MAXLEN_PHYSADDR", - "MAX_ADAPTER_ADDRESS_LENGTH", - "MAX_ADAPTER_DESCRIPTION_LENGTH", - "MAX_ADAPTER_NAME_LENGTH", - "MAX_COMPUTERNAME_LENGTH", - "MAX_INTERFACE_NAME_LEN", - "MAX_LONG_PATH", - "MAX_PATH", - "MAX_PROTOCOL_CHAIN", - "MCL_CURRENT", - "MCL_FUTURE", - "MNT_DETACH", - "MNT_EXPIRE", - "MNT_FORCE", - "MSG_BCAST", - "MSG_CMSG_CLOEXEC", - "MSG_COMPAT", - "MSG_CONFIRM", - "MSG_CONTROLMBUF", - "MSG_CTRUNC", - "MSG_DONTROUTE", - "MSG_DONTWAIT", - "MSG_EOF", - "MSG_EOR", - "MSG_ERRQUEUE", - "MSG_FASTOPEN", - "MSG_FIN", - "MSG_FLUSH", - "MSG_HAVEMORE", - "MSG_HOLD", - "MSG_IOVUSRSPACE", - "MSG_LENUSRSPACE", - "MSG_MCAST", - "MSG_MORE", - "MSG_NAMEMBUF", - "MSG_NBIO", - "MSG_NEEDSA", - "MSG_NOSIGNAL", - "MSG_NOTIFICATION", - "MSG_OOB", - "MSG_PEEK", - "MSG_PROXY", - "MSG_RCVMORE", - "MSG_RST", - "MSG_SEND", - "MSG_SYN", - "MSG_TRUNC", - "MSG_TRYHARD", - "MSG_USERFLAGS", - "MSG_WAITALL", - "MSG_WAITFORONE", - "MSG_WAITSTREAM", - "MS_ACTIVE", - "MS_ASYNC", - "MS_BIND", - "MS_DEACTIVATE", - "MS_DIRSYNC", - "MS_INVALIDATE", - "MS_I_VERSION", - "MS_KERNMOUNT", - "MS_KILLPAGES", - "MS_MANDLOCK", - "MS_MGC_MSK", - "MS_MGC_VAL", - "MS_MOVE", - "MS_NOATIME", - "MS_NODEV", - "MS_NODIRATIME", - "MS_NOEXEC", - "MS_NOSUID", - "MS_NOUSER", - "MS_POSIXACL", - "MS_PRIVATE", - "MS_RDONLY", - "MS_REC", - "MS_RELATIME", - "MS_REMOUNT", - "MS_RMT_MASK", - "MS_SHARED", - "MS_SILENT", - "MS_SLAVE", - "MS_STRICTATIME", - "MS_SYNC", - "MS_SYNCHRONOUS", - "MS_UNBINDABLE", - "Madvise", - "MapViewOfFile", - "MaxTokenInfoClass", - "Mclpool", - "MibIfRow", - "Mkdir", - "Mkdirat", - "Mkfifo", - "Mknod", - "Mknodat", - "Mlock", - "Mlockall", - "Mmap", - "Mount", - "MoveFile", - "Mprotect", - "Msghdr", - "Munlock", - "Munlockall", - "Munmap", - "MustLoadDLL", - "NAME_MAX", - "NETLINK_ADD_MEMBERSHIP", - "NETLINK_AUDIT", - "NETLINK_BROADCAST_ERROR", - "NETLINK_CONNECTOR", - "NETLINK_DNRTMSG", - "NETLINK_DROP_MEMBERSHIP", - "NETLINK_ECRYPTFS", - "NETLINK_FIB_LOOKUP", - "NETLINK_FIREWALL", - "NETLINK_GENERIC", - "NETLINK_INET_DIAG", - "NETLINK_IP6_FW", - "NETLINK_ISCSI", - "NETLINK_KOBJECT_UEVENT", - "NETLINK_NETFILTER", - "NETLINK_NFLOG", - "NETLINK_NO_ENOBUFS", - "NETLINK_PKTINFO", - "NETLINK_RDMA", - "NETLINK_ROUTE", - "NETLINK_SCSITRANSPORT", - "NETLINK_SELINUX", - "NETLINK_UNUSED", - "NETLINK_USERSOCK", - "NETLINK_XFRM", - "NET_RT_DUMP", - "NET_RT_DUMP2", - "NET_RT_FLAGS", - "NET_RT_IFLIST", - "NET_RT_IFLIST2", - "NET_RT_IFLISTL", - "NET_RT_IFMALIST", - "NET_RT_MAXID", - "NET_RT_OIFLIST", - "NET_RT_OOIFLIST", - "NET_RT_STAT", - "NET_RT_STATS", - "NET_RT_TABLE", - "NET_RT_TRASH", - "NLA_ALIGNTO", - "NLA_F_NESTED", - "NLA_F_NET_BYTEORDER", - "NLA_HDRLEN", - "NLMSG_ALIGNTO", - "NLMSG_DONE", - "NLMSG_ERROR", - "NLMSG_HDRLEN", - "NLMSG_MIN_TYPE", - "NLMSG_NOOP", - "NLMSG_OVERRUN", - "NLM_F_ACK", - "NLM_F_APPEND", - "NLM_F_ATOMIC", - "NLM_F_CREATE", - "NLM_F_DUMP", - "NLM_F_ECHO", - "NLM_F_EXCL", - "NLM_F_MATCH", - "NLM_F_MULTI", - "NLM_F_REPLACE", - "NLM_F_REQUEST", - "NLM_F_ROOT", - "NOFLSH", - "NOTE_ABSOLUTE", - "NOTE_ATTRIB", - "NOTE_BACKGROUND", - "NOTE_CHILD", - "NOTE_CRITICAL", - "NOTE_DELETE", - "NOTE_EOF", - "NOTE_EXEC", - "NOTE_EXIT", - "NOTE_EXITSTATUS", - "NOTE_EXIT_CSERROR", - "NOTE_EXIT_DECRYPTFAIL", - "NOTE_EXIT_DETAIL", - "NOTE_EXIT_DETAIL_MASK", - "NOTE_EXIT_MEMORY", - "NOTE_EXIT_REPARENTED", - "NOTE_EXTEND", - "NOTE_FFAND", - "NOTE_FFCOPY", - "NOTE_FFCTRLMASK", - "NOTE_FFLAGSMASK", - "NOTE_FFNOP", - "NOTE_FFOR", - "NOTE_FORK", - "NOTE_LEEWAY", - "NOTE_LINK", - "NOTE_LOWAT", - "NOTE_NONE", - "NOTE_NSECONDS", - "NOTE_PCTRLMASK", - "NOTE_PDATAMASK", - "NOTE_REAP", - "NOTE_RENAME", - "NOTE_RESOURCEEND", - "NOTE_REVOKE", - "NOTE_SECONDS", - "NOTE_SIGNAL", - "NOTE_TRACK", - "NOTE_TRACKERR", - "NOTE_TRIGGER", - "NOTE_TRUNCATE", - "NOTE_USECONDS", - "NOTE_VM_ERROR", - "NOTE_VM_PRESSURE", - "NOTE_VM_PRESSURE_SUDDEN_TERMINATE", - "NOTE_VM_PRESSURE_TERMINATE", - "NOTE_WRITE", - "NameCanonical", - "NameCanonicalEx", - "NameDisplay", - "NameDnsDomain", - "NameFullyQualifiedDN", - "NameSamCompatible", - "NameServicePrincipal", - "NameUniqueId", - "NameUnknown", - "NameUserPrincipal", - "Nanosleep", - "NetApiBufferFree", - "NetGetJoinInformation", - "NetSetupDomainName", - "NetSetupUnjoined", - "NetSetupUnknownStatus", - "NetSetupWorkgroupName", - "NetUserGetInfo", - "NetlinkMessage", - "NetlinkRIB", - "NetlinkRouteAttr", - "NetlinkRouteRequest", - "NewCallback", - "NewCallbackCDecl", - "NewLazyDLL", - "NlAttr", - "NlMsgerr", - "NlMsghdr", - "NsecToFiletime", - "NsecToTimespec", - "NsecToTimeval", - "Ntohs", - "OCRNL", - "OFDEL", - "OFILL", - "OFIOGETBMAP", - "OID_PKIX_KP_SERVER_AUTH", - "OID_SERVER_GATED_CRYPTO", - "OID_SGC_NETSCAPE", - "OLCUC", - "ONLCR", - "ONLRET", - "ONOCR", - "ONOEOT", - "OPEN_ALWAYS", - "OPEN_EXISTING", - "OPOST", - "O_ACCMODE", - "O_ALERT", - "O_ALT_IO", - "O_APPEND", - "O_ASYNC", - "O_CLOEXEC", - "O_CREAT", - "O_DIRECT", - "O_DIRECTORY", - "O_DP_GETRAWENCRYPTED", - "O_DSYNC", - "O_EVTONLY", - "O_EXCL", - "O_EXEC", - "O_EXLOCK", - "O_FSYNC", - "O_LARGEFILE", - "O_NDELAY", - "O_NOATIME", - "O_NOCTTY", - "O_NOFOLLOW", - "O_NONBLOCK", - "O_NOSIGPIPE", - "O_POPUP", - "O_RDONLY", - "O_RDWR", - "O_RSYNC", - "O_SHLOCK", - "O_SYMLINK", - "O_SYNC", - "O_TRUNC", - "O_TTY_INIT", - "O_WRONLY", - "Open", - "OpenCurrentProcessToken", - "OpenProcess", - "OpenProcessToken", - "Openat", - "Overlapped", - "PACKET_ADD_MEMBERSHIP", - "PACKET_BROADCAST", - "PACKET_DROP_MEMBERSHIP", - "PACKET_FASTROUTE", - "PACKET_HOST", - "PACKET_LOOPBACK", - "PACKET_MR_ALLMULTI", - "PACKET_MR_MULTICAST", - "PACKET_MR_PROMISC", - "PACKET_MULTICAST", - "PACKET_OTHERHOST", - "PACKET_OUTGOING", - "PACKET_RECV_OUTPUT", - "PACKET_RX_RING", - "PACKET_STATISTICS", - "PAGE_EXECUTE_READ", - "PAGE_EXECUTE_READWRITE", - "PAGE_EXECUTE_WRITECOPY", - "PAGE_READONLY", - "PAGE_READWRITE", - "PAGE_WRITECOPY", - "PARENB", - "PARMRK", - "PARODD", - "PENDIN", - "PFL_HIDDEN", - "PFL_MATCHES_PROTOCOL_ZERO", - "PFL_MULTIPLE_PROTO_ENTRIES", - "PFL_NETWORKDIRECT_PROVIDER", - "PFL_RECOMMENDED_PROTO_ENTRY", - "PF_FLUSH", - "PKCS_7_ASN_ENCODING", - "PMC5_PIPELINE_FLUSH", - "PRIO_PGRP", - "PRIO_PROCESS", - "PRIO_USER", - "PRI_IOFLUSH", - "PROCESS_QUERY_INFORMATION", - "PROCESS_TERMINATE", - "PROT_EXEC", - "PROT_GROWSDOWN", - "PROT_GROWSUP", - "PROT_NONE", - "PROT_READ", - "PROT_WRITE", - "PROV_DH_SCHANNEL", - "PROV_DSS", - "PROV_DSS_DH", - "PROV_EC_ECDSA_FULL", - "PROV_EC_ECDSA_SIG", - "PROV_EC_ECNRA_FULL", - "PROV_EC_ECNRA_SIG", - "PROV_FORTEZZA", - "PROV_INTEL_SEC", - "PROV_MS_EXCHANGE", - "PROV_REPLACE_OWF", - "PROV_RNG", - "PROV_RSA_AES", - "PROV_RSA_FULL", - "PROV_RSA_SCHANNEL", - "PROV_RSA_SIG", - "PROV_SPYRUS_LYNKS", - "PROV_SSL", - "PR_CAPBSET_DROP", - "PR_CAPBSET_READ", - "PR_CLEAR_SECCOMP_FILTER", - "PR_ENDIAN_BIG", - "PR_ENDIAN_LITTLE", - "PR_ENDIAN_PPC_LITTLE", - "PR_FPEMU_NOPRINT", - "PR_FPEMU_SIGFPE", - "PR_FP_EXC_ASYNC", - "PR_FP_EXC_DISABLED", - "PR_FP_EXC_DIV", - "PR_FP_EXC_INV", - "PR_FP_EXC_NONRECOV", - "PR_FP_EXC_OVF", - "PR_FP_EXC_PRECISE", - "PR_FP_EXC_RES", - "PR_FP_EXC_SW_ENABLE", - "PR_FP_EXC_UND", - "PR_GET_DUMPABLE", - "PR_GET_ENDIAN", - "PR_GET_FPEMU", - "PR_GET_FPEXC", - "PR_GET_KEEPCAPS", - "PR_GET_NAME", - "PR_GET_PDEATHSIG", - "PR_GET_SECCOMP", - "PR_GET_SECCOMP_FILTER", - "PR_GET_SECUREBITS", - "PR_GET_TIMERSLACK", - "PR_GET_TIMING", - "PR_GET_TSC", - "PR_GET_UNALIGN", - "PR_MCE_KILL", - "PR_MCE_KILL_CLEAR", - "PR_MCE_KILL_DEFAULT", - "PR_MCE_KILL_EARLY", - "PR_MCE_KILL_GET", - "PR_MCE_KILL_LATE", - "PR_MCE_KILL_SET", - "PR_SECCOMP_FILTER_EVENT", - "PR_SECCOMP_FILTER_SYSCALL", - "PR_SET_DUMPABLE", - "PR_SET_ENDIAN", - "PR_SET_FPEMU", - "PR_SET_FPEXC", - "PR_SET_KEEPCAPS", - "PR_SET_NAME", - "PR_SET_PDEATHSIG", - "PR_SET_PTRACER", - "PR_SET_SECCOMP", - "PR_SET_SECCOMP_FILTER", - "PR_SET_SECUREBITS", - "PR_SET_TIMERSLACK", - "PR_SET_TIMING", - "PR_SET_TSC", - "PR_SET_UNALIGN", - "PR_TASK_PERF_EVENTS_DISABLE", - "PR_TASK_PERF_EVENTS_ENABLE", - "PR_TIMING_STATISTICAL", - "PR_TIMING_TIMESTAMP", - "PR_TSC_ENABLE", - "PR_TSC_SIGSEGV", - "PR_UNALIGN_NOPRINT", - "PR_UNALIGN_SIGBUS", - "PTRACE_ARCH_PRCTL", - "PTRACE_ATTACH", - "PTRACE_CONT", - "PTRACE_DETACH", - "PTRACE_EVENT_CLONE", - "PTRACE_EVENT_EXEC", - "PTRACE_EVENT_EXIT", - "PTRACE_EVENT_FORK", - "PTRACE_EVENT_VFORK", - "PTRACE_EVENT_VFORK_DONE", - "PTRACE_GETCRUNCHREGS", - "PTRACE_GETEVENTMSG", - "PTRACE_GETFPREGS", - "PTRACE_GETFPXREGS", - "PTRACE_GETHBPREGS", - "PTRACE_GETREGS", - "PTRACE_GETREGSET", - "PTRACE_GETSIGINFO", - "PTRACE_GETVFPREGS", - "PTRACE_GETWMMXREGS", - "PTRACE_GET_THREAD_AREA", - "PTRACE_KILL", - "PTRACE_OLDSETOPTIONS", - "PTRACE_O_MASK", - "PTRACE_O_TRACECLONE", - "PTRACE_O_TRACEEXEC", - "PTRACE_O_TRACEEXIT", - "PTRACE_O_TRACEFORK", - "PTRACE_O_TRACESYSGOOD", - "PTRACE_O_TRACEVFORK", - "PTRACE_O_TRACEVFORKDONE", - "PTRACE_PEEKDATA", - "PTRACE_PEEKTEXT", - "PTRACE_PEEKUSR", - "PTRACE_POKEDATA", - "PTRACE_POKETEXT", - "PTRACE_POKEUSR", - "PTRACE_SETCRUNCHREGS", - "PTRACE_SETFPREGS", - "PTRACE_SETFPXREGS", - "PTRACE_SETHBPREGS", - "PTRACE_SETOPTIONS", - "PTRACE_SETREGS", - "PTRACE_SETREGSET", - "PTRACE_SETSIGINFO", - "PTRACE_SETVFPREGS", - "PTRACE_SETWMMXREGS", - "PTRACE_SET_SYSCALL", - "PTRACE_SET_THREAD_AREA", - "PTRACE_SINGLEBLOCK", - "PTRACE_SINGLESTEP", - "PTRACE_SYSCALL", - "PTRACE_SYSEMU", - "PTRACE_SYSEMU_SINGLESTEP", - "PTRACE_TRACEME", - "PT_ATTACH", - "PT_ATTACHEXC", - "PT_CONTINUE", - "PT_DATA_ADDR", - "PT_DENY_ATTACH", - "PT_DETACH", - "PT_FIRSTMACH", - "PT_FORCEQUOTA", - "PT_KILL", - "PT_MASK", - "PT_READ_D", - "PT_READ_I", - "PT_READ_U", - "PT_SIGEXC", - "PT_STEP", - "PT_TEXT_ADDR", - "PT_TEXT_END_ADDR", - "PT_THUPDATE", - "PT_TRACE_ME", - "PT_WRITE_D", - "PT_WRITE_I", - "PT_WRITE_U", - "ParseDirent", - "ParseNetlinkMessage", - "ParseNetlinkRouteAttr", - "ParseRoutingMessage", - "ParseRoutingSockaddr", - "ParseSocketControlMessage", - "ParseUnixCredentials", - "ParseUnixRights", - "PathMax", - "Pathconf", - "Pause", - "Pipe", - "Pipe2", - "PivotRoot", - "Pointer", - "PostQueuedCompletionStatus", - "Pread", - "Proc", - "ProcAttr", - "Process32First", - "Process32Next", - "ProcessEntry32", - "ProcessInformation", - "Protoent", - "PtraceAttach", - "PtraceCont", - "PtraceDetach", - "PtraceGetEventMsg", - "PtraceGetRegs", - "PtracePeekData", - "PtracePeekText", - "PtracePokeData", - "PtracePokeText", - "PtraceRegs", - "PtraceSetOptions", - "PtraceSetRegs", - "PtraceSingleStep", - "PtraceSyscall", - "Pwrite", - "REG_BINARY", - "REG_DWORD", - "REG_DWORD_BIG_ENDIAN", - "REG_DWORD_LITTLE_ENDIAN", - "REG_EXPAND_SZ", - "REG_FULL_RESOURCE_DESCRIPTOR", - "REG_LINK", - "REG_MULTI_SZ", - "REG_NONE", - "REG_QWORD", - "REG_QWORD_LITTLE_ENDIAN", - "REG_RESOURCE_LIST", - "REG_RESOURCE_REQUIREMENTS_LIST", - "REG_SZ", - "RLIMIT_AS", - "RLIMIT_CORE", - "RLIMIT_CPU", - "RLIMIT_CPU_USAGE_MONITOR", - "RLIMIT_DATA", - "RLIMIT_FSIZE", - "RLIMIT_NOFILE", - "RLIMIT_STACK", - "RLIM_INFINITY", - "RTAX_ADVMSS", - "RTAX_AUTHOR", - "RTAX_BRD", - "RTAX_CWND", - "RTAX_DST", - "RTAX_FEATURES", - "RTAX_FEATURE_ALLFRAG", - "RTAX_FEATURE_ECN", - "RTAX_FEATURE_SACK", - "RTAX_FEATURE_TIMESTAMP", - "RTAX_GATEWAY", - "RTAX_GENMASK", - "RTAX_HOPLIMIT", - "RTAX_IFA", - "RTAX_IFP", - "RTAX_INITCWND", - "RTAX_INITRWND", - "RTAX_LABEL", - "RTAX_LOCK", - "RTAX_MAX", - "RTAX_MTU", - "RTAX_NETMASK", - "RTAX_REORDERING", - "RTAX_RTO_MIN", - "RTAX_RTT", - "RTAX_RTTVAR", - "RTAX_SRC", - "RTAX_SRCMASK", - "RTAX_SSTHRESH", - "RTAX_TAG", - "RTAX_UNSPEC", - "RTAX_WINDOW", - "RTA_ALIGNTO", - "RTA_AUTHOR", - "RTA_BRD", - "RTA_CACHEINFO", - "RTA_DST", - "RTA_FLOW", - "RTA_GATEWAY", - "RTA_GENMASK", - "RTA_IFA", - "RTA_IFP", - "RTA_IIF", - "RTA_LABEL", - "RTA_MAX", - "RTA_METRICS", - "RTA_MULTIPATH", - "RTA_NETMASK", - "RTA_OIF", - "RTA_PREFSRC", - "RTA_PRIORITY", - "RTA_SRC", - "RTA_SRCMASK", - "RTA_TABLE", - "RTA_TAG", - "RTA_UNSPEC", - "RTCF_DIRECTSRC", - "RTCF_DOREDIRECT", - "RTCF_LOG", - "RTCF_MASQ", - "RTCF_NAT", - "RTCF_VALVE", - "RTF_ADDRCLASSMASK", - "RTF_ADDRCONF", - "RTF_ALLONLINK", - "RTF_ANNOUNCE", - "RTF_BLACKHOLE", - "RTF_BROADCAST", - "RTF_CACHE", - "RTF_CLONED", - "RTF_CLONING", - "RTF_CONDEMNED", - "RTF_DEFAULT", - "RTF_DELCLONE", - "RTF_DONE", - "RTF_DYNAMIC", - "RTF_FLOW", - "RTF_FMASK", - "RTF_GATEWAY", - "RTF_GWFLAG_COMPAT", - "RTF_HOST", - "RTF_IFREF", - "RTF_IFSCOPE", - "RTF_INTERFACE", - "RTF_IRTT", - "RTF_LINKRT", - "RTF_LLDATA", - "RTF_LLINFO", - "RTF_LOCAL", - "RTF_MASK", - "RTF_MODIFIED", - "RTF_MPATH", - "RTF_MPLS", - "RTF_MSS", - "RTF_MTU", - "RTF_MULTICAST", - "RTF_NAT", - "RTF_NOFORWARD", - "RTF_NONEXTHOP", - "RTF_NOPMTUDISC", - "RTF_PERMANENT_ARP", - "RTF_PINNED", - "RTF_POLICY", - "RTF_PRCLONING", - "RTF_PROTO1", - "RTF_PROTO2", - "RTF_PROTO3", - "RTF_PROXY", - "RTF_REINSTATE", - "RTF_REJECT", - "RTF_RNH_LOCKED", - "RTF_ROUTER", - "RTF_SOURCE", - "RTF_SRC", - "RTF_STATIC", - "RTF_STICKY", - "RTF_THROW", - "RTF_TUNNEL", - "RTF_UP", - "RTF_USETRAILERS", - "RTF_WASCLONED", - "RTF_WINDOW", - "RTF_XRESOLVE", - "RTM_ADD", - "RTM_BASE", - "RTM_CHANGE", - "RTM_CHGADDR", - "RTM_DELACTION", - "RTM_DELADDR", - "RTM_DELADDRLABEL", - "RTM_DELETE", - "RTM_DELLINK", - "RTM_DELMADDR", - "RTM_DELNEIGH", - "RTM_DELQDISC", - "RTM_DELROUTE", - "RTM_DELRULE", - "RTM_DELTCLASS", - "RTM_DELTFILTER", - "RTM_DESYNC", - "RTM_F_CLONED", - "RTM_F_EQUALIZE", - "RTM_F_NOTIFY", - "RTM_F_PREFIX", - "RTM_GET", - "RTM_GET2", - "RTM_GETACTION", - "RTM_GETADDR", - "RTM_GETADDRLABEL", - "RTM_GETANYCAST", - "RTM_GETDCB", - "RTM_GETLINK", - "RTM_GETMULTICAST", - "RTM_GETNEIGH", - "RTM_GETNEIGHTBL", - "RTM_GETQDISC", - "RTM_GETROUTE", - "RTM_GETRULE", - "RTM_GETTCLASS", - "RTM_GETTFILTER", - "RTM_IEEE80211", - "RTM_IFANNOUNCE", - "RTM_IFINFO", - "RTM_IFINFO2", - "RTM_LLINFO_UPD", - "RTM_LOCK", - "RTM_LOSING", - "RTM_MAX", - "RTM_MAXSIZE", - "RTM_MISS", - "RTM_NEWACTION", - "RTM_NEWADDR", - "RTM_NEWADDRLABEL", - "RTM_NEWLINK", - "RTM_NEWMADDR", - "RTM_NEWMADDR2", - "RTM_NEWNDUSEROPT", - "RTM_NEWNEIGH", - "RTM_NEWNEIGHTBL", - "RTM_NEWPREFIX", - "RTM_NEWQDISC", - "RTM_NEWROUTE", - "RTM_NEWRULE", - "RTM_NEWTCLASS", - "RTM_NEWTFILTER", - "RTM_NR_FAMILIES", - "RTM_NR_MSGTYPES", - "RTM_OIFINFO", - "RTM_OLDADD", - "RTM_OLDDEL", - "RTM_OOIFINFO", - "RTM_REDIRECT", - "RTM_RESOLVE", - "RTM_RTTUNIT", - "RTM_SETDCB", - "RTM_SETGATE", - "RTM_SETLINK", - "RTM_SETNEIGHTBL", - "RTM_VERSION", - "RTNH_ALIGNTO", - "RTNH_F_DEAD", - "RTNH_F_ONLINK", - "RTNH_F_PERVASIVE", - "RTNLGRP_IPV4_IFADDR", - "RTNLGRP_IPV4_MROUTE", - "RTNLGRP_IPV4_ROUTE", - "RTNLGRP_IPV4_RULE", - "RTNLGRP_IPV6_IFADDR", - "RTNLGRP_IPV6_IFINFO", - "RTNLGRP_IPV6_MROUTE", - "RTNLGRP_IPV6_PREFIX", - "RTNLGRP_IPV6_ROUTE", - "RTNLGRP_IPV6_RULE", - "RTNLGRP_LINK", - "RTNLGRP_ND_USEROPT", - "RTNLGRP_NEIGH", - "RTNLGRP_NONE", - "RTNLGRP_NOTIFY", - "RTNLGRP_TC", - "RTN_ANYCAST", - "RTN_BLACKHOLE", - "RTN_BROADCAST", - "RTN_LOCAL", - "RTN_MAX", - "RTN_MULTICAST", - "RTN_NAT", - "RTN_PROHIBIT", - "RTN_THROW", - "RTN_UNICAST", - "RTN_UNREACHABLE", - "RTN_UNSPEC", - "RTN_XRESOLVE", - "RTPROT_BIRD", - "RTPROT_BOOT", - "RTPROT_DHCP", - "RTPROT_DNROUTED", - "RTPROT_GATED", - "RTPROT_KERNEL", - "RTPROT_MRT", - "RTPROT_NTK", - "RTPROT_RA", - "RTPROT_REDIRECT", - "RTPROT_STATIC", - "RTPROT_UNSPEC", - "RTPROT_XORP", - "RTPROT_ZEBRA", - "RTV_EXPIRE", - "RTV_HOPCOUNT", - "RTV_MTU", - "RTV_RPIPE", - "RTV_RTT", - "RTV_RTTVAR", - "RTV_SPIPE", - "RTV_SSTHRESH", - "RTV_WEIGHT", - "RT_CACHING_CONTEXT", - "RT_CLASS_DEFAULT", - "RT_CLASS_LOCAL", - "RT_CLASS_MAIN", - "RT_CLASS_MAX", - "RT_CLASS_UNSPEC", - "RT_DEFAULT_FIB", - "RT_NORTREF", - "RT_SCOPE_HOST", - "RT_SCOPE_LINK", - "RT_SCOPE_NOWHERE", - "RT_SCOPE_SITE", - "RT_SCOPE_UNIVERSE", - "RT_TABLEID_MAX", - "RT_TABLE_COMPAT", - "RT_TABLE_DEFAULT", - "RT_TABLE_LOCAL", - "RT_TABLE_MAIN", - "RT_TABLE_MAX", - "RT_TABLE_UNSPEC", - "RUSAGE_CHILDREN", - "RUSAGE_SELF", - "RUSAGE_THREAD", - "Radvisory_t", - "RawConn", - "RawSockaddr", - "RawSockaddrAny", - "RawSockaddrDatalink", - "RawSockaddrInet4", - "RawSockaddrInet6", - "RawSockaddrLinklayer", - "RawSockaddrNetlink", - "RawSockaddrUnix", - "RawSyscall", - "RawSyscall6", - "Read", - "ReadConsole", - "ReadDirectoryChanges", - "ReadDirent", - "ReadFile", - "Readlink", - "Reboot", - "Recvfrom", - "Recvmsg", - "RegCloseKey", - "RegEnumKeyEx", - "RegOpenKeyEx", - "RegQueryInfoKey", - "RegQueryValueEx", - "RemoveDirectory", - "Removexattr", - "Rename", - "Renameat", - "Revoke", - "Rlimit", - "Rmdir", - "RouteMessage", - "RouteRIB", - "RoutingMessage", - "RtAttr", - "RtGenmsg", - "RtMetrics", - "RtMsg", - "RtMsghdr", - "RtNexthop", - "Rusage", - "SCM_BINTIME", - "SCM_CREDENTIALS", - "SCM_CREDS", - "SCM_RIGHTS", - "SCM_TIMESTAMP", - "SCM_TIMESTAMPING", - "SCM_TIMESTAMPNS", - "SCM_TIMESTAMP_MONOTONIC", - "SHUT_RD", - "SHUT_RDWR", - "SHUT_WR", - "SID", - "SIDAndAttributes", - "SIGABRT", - "SIGALRM", - "SIGBUS", - "SIGCHLD", - "SIGCLD", - "SIGCONT", - "SIGEMT", - "SIGFPE", - "SIGHUP", - "SIGILL", - "SIGINFO", - "SIGINT", - "SIGIO", - "SIGIOT", - "SIGKILL", - "SIGLIBRT", - "SIGLWP", - "SIGPIPE", - "SIGPOLL", - "SIGPROF", - "SIGPWR", - "SIGQUIT", - "SIGSEGV", - "SIGSTKFLT", - "SIGSTOP", - "SIGSYS", - "SIGTERM", - "SIGTHR", - "SIGTRAP", - "SIGTSTP", - "SIGTTIN", - "SIGTTOU", - "SIGUNUSED", - "SIGURG", - "SIGUSR1", - "SIGUSR2", - "SIGVTALRM", - "SIGWINCH", - "SIGXCPU", - "SIGXFSZ", - "SIOCADDDLCI", - "SIOCADDMULTI", - "SIOCADDRT", - "SIOCAIFADDR", - "SIOCAIFGROUP", - "SIOCALIFADDR", - "SIOCARPIPLL", - "SIOCATMARK", - "SIOCAUTOADDR", - "SIOCAUTONETMASK", - "SIOCBRDGADD", - "SIOCBRDGADDS", - "SIOCBRDGARL", - "SIOCBRDGDADDR", - "SIOCBRDGDEL", - "SIOCBRDGDELS", - "SIOCBRDGFLUSH", - "SIOCBRDGFRL", - "SIOCBRDGGCACHE", - "SIOCBRDGGFD", - "SIOCBRDGGHT", - "SIOCBRDGGIFFLGS", - "SIOCBRDGGMA", - "SIOCBRDGGPARAM", - "SIOCBRDGGPRI", - "SIOCBRDGGRL", - "SIOCBRDGGSIFS", - "SIOCBRDGGTO", - "SIOCBRDGIFS", - "SIOCBRDGRTS", - "SIOCBRDGSADDR", - "SIOCBRDGSCACHE", - "SIOCBRDGSFD", - "SIOCBRDGSHT", - "SIOCBRDGSIFCOST", - "SIOCBRDGSIFFLGS", - "SIOCBRDGSIFPRIO", - "SIOCBRDGSMA", - "SIOCBRDGSPRI", - "SIOCBRDGSPROTO", - "SIOCBRDGSTO", - "SIOCBRDGSTXHC", - "SIOCDARP", - "SIOCDELDLCI", - "SIOCDELMULTI", - "SIOCDELRT", - "SIOCDEVPRIVATE", - "SIOCDIFADDR", - "SIOCDIFGROUP", - "SIOCDIFPHYADDR", - "SIOCDLIFADDR", - "SIOCDRARP", - "SIOCGARP", - "SIOCGDRVSPEC", - "SIOCGETKALIVE", - "SIOCGETLABEL", - "SIOCGETPFLOW", - "SIOCGETPFSYNC", - "SIOCGETSGCNT", - "SIOCGETVIFCNT", - "SIOCGETVLAN", - "SIOCGHIWAT", - "SIOCGIFADDR", - "SIOCGIFADDRPREF", - "SIOCGIFALIAS", - "SIOCGIFALTMTU", - "SIOCGIFASYNCMAP", - "SIOCGIFBOND", - "SIOCGIFBR", - "SIOCGIFBRDADDR", - "SIOCGIFCAP", - "SIOCGIFCONF", - "SIOCGIFCOUNT", - "SIOCGIFDATA", - "SIOCGIFDESCR", - "SIOCGIFDEVMTU", - "SIOCGIFDLT", - "SIOCGIFDSTADDR", - "SIOCGIFENCAP", - "SIOCGIFFIB", - "SIOCGIFFLAGS", - "SIOCGIFGATTR", - "SIOCGIFGENERIC", - "SIOCGIFGMEMB", - "SIOCGIFGROUP", - "SIOCGIFHARDMTU", - "SIOCGIFHWADDR", - "SIOCGIFINDEX", - "SIOCGIFKPI", - "SIOCGIFMAC", - "SIOCGIFMAP", - "SIOCGIFMEDIA", - "SIOCGIFMEM", - "SIOCGIFMETRIC", - "SIOCGIFMTU", - "SIOCGIFNAME", - "SIOCGIFNETMASK", - "SIOCGIFPDSTADDR", - "SIOCGIFPFLAGS", - "SIOCGIFPHYS", - "SIOCGIFPRIORITY", - "SIOCGIFPSRCADDR", - "SIOCGIFRDOMAIN", - "SIOCGIFRTLABEL", - "SIOCGIFSLAVE", - "SIOCGIFSTATUS", - "SIOCGIFTIMESLOT", - "SIOCGIFTXQLEN", - "SIOCGIFVLAN", - "SIOCGIFWAKEFLAGS", - "SIOCGIFXFLAGS", - "SIOCGLIFADDR", - "SIOCGLIFPHYADDR", - "SIOCGLIFPHYRTABLE", - "SIOCGLIFPHYTTL", - "SIOCGLINKSTR", - "SIOCGLOWAT", - "SIOCGPGRP", - "SIOCGPRIVATE_0", - "SIOCGPRIVATE_1", - "SIOCGRARP", - "SIOCGSPPPPARAMS", - "SIOCGSTAMP", - "SIOCGSTAMPNS", - "SIOCGVH", - "SIOCGVNETID", - "SIOCIFCREATE", - "SIOCIFCREATE2", - "SIOCIFDESTROY", - "SIOCIFGCLONERS", - "SIOCINITIFADDR", - "SIOCPROTOPRIVATE", - "SIOCRSLVMULTI", - "SIOCRTMSG", - "SIOCSARP", - "SIOCSDRVSPEC", - "SIOCSETKALIVE", - "SIOCSETLABEL", - "SIOCSETPFLOW", - "SIOCSETPFSYNC", - "SIOCSETVLAN", - "SIOCSHIWAT", - "SIOCSIFADDR", - "SIOCSIFADDRPREF", - "SIOCSIFALTMTU", - "SIOCSIFASYNCMAP", - "SIOCSIFBOND", - "SIOCSIFBR", - "SIOCSIFBRDADDR", - "SIOCSIFCAP", - "SIOCSIFDESCR", - "SIOCSIFDSTADDR", - "SIOCSIFENCAP", - "SIOCSIFFIB", - "SIOCSIFFLAGS", - "SIOCSIFGATTR", - "SIOCSIFGENERIC", - "SIOCSIFHWADDR", - "SIOCSIFHWBROADCAST", - "SIOCSIFKPI", - "SIOCSIFLINK", - "SIOCSIFLLADDR", - "SIOCSIFMAC", - "SIOCSIFMAP", - "SIOCSIFMEDIA", - "SIOCSIFMEM", - "SIOCSIFMETRIC", - "SIOCSIFMTU", - "SIOCSIFNAME", - "SIOCSIFNETMASK", - "SIOCSIFPFLAGS", - "SIOCSIFPHYADDR", - "SIOCSIFPHYS", - "SIOCSIFPRIORITY", - "SIOCSIFRDOMAIN", - "SIOCSIFRTLABEL", - "SIOCSIFRVNET", - "SIOCSIFSLAVE", - "SIOCSIFTIMESLOT", - "SIOCSIFTXQLEN", - "SIOCSIFVLAN", - "SIOCSIFVNET", - "SIOCSIFXFLAGS", - "SIOCSLIFPHYADDR", - "SIOCSLIFPHYRTABLE", - "SIOCSLIFPHYTTL", - "SIOCSLINKSTR", - "SIOCSLOWAT", - "SIOCSPGRP", - "SIOCSRARP", - "SIOCSSPPPPARAMS", - "SIOCSVH", - "SIOCSVNETID", - "SIOCZIFDATA", - "SIO_GET_EXTENSION_FUNCTION_POINTER", - "SIO_GET_INTERFACE_LIST", - "SIO_KEEPALIVE_VALS", - "SIO_UDP_CONNRESET", - "SOCK_CLOEXEC", - "SOCK_DCCP", - "SOCK_DGRAM", - "SOCK_FLAGS_MASK", - "SOCK_MAXADDRLEN", - "SOCK_NONBLOCK", - "SOCK_NOSIGPIPE", - "SOCK_PACKET", - "SOCK_RAW", - "SOCK_RDM", - "SOCK_SEQPACKET", - "SOCK_STREAM", - "SOL_AAL", - "SOL_ATM", - "SOL_DECNET", - "SOL_ICMPV6", - "SOL_IP", - "SOL_IPV6", - "SOL_IRDA", - "SOL_PACKET", - "SOL_RAW", - "SOL_SOCKET", - "SOL_TCP", - "SOL_X25", - "SOMAXCONN", - "SO_ACCEPTCONN", - "SO_ACCEPTFILTER", - "SO_ATTACH_FILTER", - "SO_BINDANY", - "SO_BINDTODEVICE", - "SO_BINTIME", - "SO_BROADCAST", - "SO_BSDCOMPAT", - "SO_DEBUG", - "SO_DETACH_FILTER", - "SO_DOMAIN", - "SO_DONTROUTE", - "SO_DONTTRUNC", - "SO_ERROR", - "SO_KEEPALIVE", - "SO_LABEL", - "SO_LINGER", - "SO_LINGER_SEC", - "SO_LISTENINCQLEN", - "SO_LISTENQLEN", - "SO_LISTENQLIMIT", - "SO_MARK", - "SO_NETPROC", - "SO_NKE", - "SO_NOADDRERR", - "SO_NOHEADER", - "SO_NOSIGPIPE", - "SO_NOTIFYCONFLICT", - "SO_NO_CHECK", - "SO_NO_DDP", - "SO_NO_OFFLOAD", - "SO_NP_EXTENSIONS", - "SO_NREAD", - "SO_NUMRCVPKT", - "SO_NWRITE", - "SO_OOBINLINE", - "SO_OVERFLOWED", - "SO_PASSCRED", - "SO_PASSSEC", - "SO_PEERCRED", - "SO_PEERLABEL", - "SO_PEERNAME", - "SO_PEERSEC", - "SO_PRIORITY", - "SO_PROTOCOL", - "SO_PROTOTYPE", - "SO_RANDOMPORT", - "SO_RCVBUF", - "SO_RCVBUFFORCE", - "SO_RCVLOWAT", - "SO_RCVTIMEO", - "SO_RESTRICTIONS", - "SO_RESTRICT_DENYIN", - "SO_RESTRICT_DENYOUT", - "SO_RESTRICT_DENYSET", - "SO_REUSEADDR", - "SO_REUSEPORT", - "SO_REUSESHAREUID", - "SO_RTABLE", - "SO_RXQ_OVFL", - "SO_SECURITY_AUTHENTICATION", - "SO_SECURITY_ENCRYPTION_NETWORK", - "SO_SECURITY_ENCRYPTION_TRANSPORT", - "SO_SETFIB", - "SO_SNDBUF", - "SO_SNDBUFFORCE", - "SO_SNDLOWAT", - "SO_SNDTIMEO", - "SO_SPLICE", - "SO_TIMESTAMP", - "SO_TIMESTAMPING", - "SO_TIMESTAMPNS", - "SO_TIMESTAMP_MONOTONIC", - "SO_TYPE", - "SO_UPCALLCLOSEWAIT", - "SO_UPDATE_ACCEPT_CONTEXT", - "SO_UPDATE_CONNECT_CONTEXT", - "SO_USELOOPBACK", - "SO_USER_COOKIE", - "SO_VENDOR", - "SO_WANTMORE", - "SO_WANTOOBFLAG", - "SSLExtraCertChainPolicyPara", - "STANDARD_RIGHTS_ALL", - "STANDARD_RIGHTS_EXECUTE", - "STANDARD_RIGHTS_READ", - "STANDARD_RIGHTS_REQUIRED", - "STANDARD_RIGHTS_WRITE", - "STARTF_USESHOWWINDOW", - "STARTF_USESTDHANDLES", - "STD_ERROR_HANDLE", - "STD_INPUT_HANDLE", - "STD_OUTPUT_HANDLE", - "SUBLANG_ENGLISH_US", - "SW_FORCEMINIMIZE", - "SW_HIDE", - "SW_MAXIMIZE", - "SW_MINIMIZE", - "SW_NORMAL", - "SW_RESTORE", - "SW_SHOW", - "SW_SHOWDEFAULT", - "SW_SHOWMAXIMIZED", - "SW_SHOWMINIMIZED", - "SW_SHOWMINNOACTIVE", - "SW_SHOWNA", - "SW_SHOWNOACTIVATE", - "SW_SHOWNORMAL", - "SYMBOLIC_LINK_FLAG_DIRECTORY", - "SYNCHRONIZE", - "SYSCTL_VERSION", - "SYSCTL_VERS_0", - "SYSCTL_VERS_1", - "SYSCTL_VERS_MASK", - "SYS_ABORT2", - "SYS_ACCEPT", - "SYS_ACCEPT4", - "SYS_ACCEPT_NOCANCEL", - "SYS_ACCESS", - "SYS_ACCESS_EXTENDED", - "SYS_ACCT", - "SYS_ADD_KEY", - "SYS_ADD_PROFIL", - "SYS_ADJFREQ", - "SYS_ADJTIME", - "SYS_ADJTIMEX", - "SYS_AFS_SYSCALL", - "SYS_AIO_CANCEL", - "SYS_AIO_ERROR", - "SYS_AIO_FSYNC", - "SYS_AIO_READ", - "SYS_AIO_RETURN", - "SYS_AIO_SUSPEND", - "SYS_AIO_SUSPEND_NOCANCEL", - "SYS_AIO_WRITE", - "SYS_ALARM", - "SYS_ARCH_PRCTL", - "SYS_ARM_FADVISE64_64", - "SYS_ARM_SYNC_FILE_RANGE", - "SYS_ATGETMSG", - "SYS_ATPGETREQ", - "SYS_ATPGETRSP", - "SYS_ATPSNDREQ", - "SYS_ATPSNDRSP", - "SYS_ATPUTMSG", - "SYS_ATSOCKET", - "SYS_AUDIT", - "SYS_AUDITCTL", - "SYS_AUDITON", - "SYS_AUDIT_SESSION_JOIN", - "SYS_AUDIT_SESSION_PORT", - "SYS_AUDIT_SESSION_SELF", - "SYS_BDFLUSH", - "SYS_BIND", - "SYS_BINDAT", - "SYS_BREAK", - "SYS_BRK", - "SYS_BSDTHREAD_CREATE", - "SYS_BSDTHREAD_REGISTER", - "SYS_BSDTHREAD_TERMINATE", - "SYS_CAPGET", - "SYS_CAPSET", - "SYS_CAP_ENTER", - "SYS_CAP_FCNTLS_GET", - "SYS_CAP_FCNTLS_LIMIT", - "SYS_CAP_GETMODE", - "SYS_CAP_GETRIGHTS", - "SYS_CAP_IOCTLS_GET", - "SYS_CAP_IOCTLS_LIMIT", - "SYS_CAP_NEW", - "SYS_CAP_RIGHTS_GET", - "SYS_CAP_RIGHTS_LIMIT", - "SYS_CHDIR", - "SYS_CHFLAGS", - "SYS_CHFLAGSAT", - "SYS_CHMOD", - "SYS_CHMOD_EXTENDED", - "SYS_CHOWN", - "SYS_CHOWN32", - "SYS_CHROOT", - "SYS_CHUD", - "SYS_CLOCK_ADJTIME", - "SYS_CLOCK_GETCPUCLOCKID2", - "SYS_CLOCK_GETRES", - "SYS_CLOCK_GETTIME", - "SYS_CLOCK_NANOSLEEP", - "SYS_CLOCK_SETTIME", - "SYS_CLONE", - "SYS_CLOSE", - "SYS_CLOSEFROM", - "SYS_CLOSE_NOCANCEL", - "SYS_CONNECT", - "SYS_CONNECTAT", - "SYS_CONNECT_NOCANCEL", - "SYS_COPYFILE", - "SYS_CPUSET", - "SYS_CPUSET_GETAFFINITY", - "SYS_CPUSET_GETID", - "SYS_CPUSET_SETAFFINITY", - "SYS_CPUSET_SETID", - "SYS_CREAT", - "SYS_CREATE_MODULE", - "SYS_CSOPS", - "SYS_CSOPS_AUDITTOKEN", - "SYS_DELETE", - "SYS_DELETE_MODULE", - "SYS_DUP", - "SYS_DUP2", - "SYS_DUP3", - "SYS_EACCESS", - "SYS_EPOLL_CREATE", - "SYS_EPOLL_CREATE1", - "SYS_EPOLL_CTL", - "SYS_EPOLL_CTL_OLD", - "SYS_EPOLL_PWAIT", - "SYS_EPOLL_WAIT", - "SYS_EPOLL_WAIT_OLD", - "SYS_EVENTFD", - "SYS_EVENTFD2", - "SYS_EXCHANGEDATA", - "SYS_EXECVE", - "SYS_EXIT", - "SYS_EXIT_GROUP", - "SYS_EXTATTRCTL", - "SYS_EXTATTR_DELETE_FD", - "SYS_EXTATTR_DELETE_FILE", - "SYS_EXTATTR_DELETE_LINK", - "SYS_EXTATTR_GET_FD", - "SYS_EXTATTR_GET_FILE", - "SYS_EXTATTR_GET_LINK", - "SYS_EXTATTR_LIST_FD", - "SYS_EXTATTR_LIST_FILE", - "SYS_EXTATTR_LIST_LINK", - "SYS_EXTATTR_SET_FD", - "SYS_EXTATTR_SET_FILE", - "SYS_EXTATTR_SET_LINK", - "SYS_FACCESSAT", - "SYS_FADVISE64", - "SYS_FADVISE64_64", - "SYS_FALLOCATE", - "SYS_FANOTIFY_INIT", - "SYS_FANOTIFY_MARK", - "SYS_FCHDIR", - "SYS_FCHFLAGS", - "SYS_FCHMOD", - "SYS_FCHMODAT", - "SYS_FCHMOD_EXTENDED", - "SYS_FCHOWN", - "SYS_FCHOWN32", - "SYS_FCHOWNAT", - "SYS_FCHROOT", - "SYS_FCNTL", - "SYS_FCNTL64", - "SYS_FCNTL_NOCANCEL", - "SYS_FDATASYNC", - "SYS_FEXECVE", - "SYS_FFCLOCK_GETCOUNTER", - "SYS_FFCLOCK_GETESTIMATE", - "SYS_FFCLOCK_SETESTIMATE", - "SYS_FFSCTL", - "SYS_FGETATTRLIST", - "SYS_FGETXATTR", - "SYS_FHOPEN", - "SYS_FHSTAT", - "SYS_FHSTATFS", - "SYS_FILEPORT_MAKEFD", - "SYS_FILEPORT_MAKEPORT", - "SYS_FKTRACE", - "SYS_FLISTXATTR", - "SYS_FLOCK", - "SYS_FORK", - "SYS_FPATHCONF", - "SYS_FREEBSD6_FTRUNCATE", - "SYS_FREEBSD6_LSEEK", - "SYS_FREEBSD6_MMAP", - "SYS_FREEBSD6_PREAD", - "SYS_FREEBSD6_PWRITE", - "SYS_FREEBSD6_TRUNCATE", - "SYS_FREMOVEXATTR", - "SYS_FSCTL", - "SYS_FSETATTRLIST", - "SYS_FSETXATTR", - "SYS_FSGETPATH", - "SYS_FSTAT", - "SYS_FSTAT64", - "SYS_FSTAT64_EXTENDED", - "SYS_FSTATAT", - "SYS_FSTATAT64", - "SYS_FSTATFS", - "SYS_FSTATFS64", - "SYS_FSTATV", - "SYS_FSTATVFS1", - "SYS_FSTAT_EXTENDED", - "SYS_FSYNC", - "SYS_FSYNC_NOCANCEL", - "SYS_FSYNC_RANGE", - "SYS_FTIME", - "SYS_FTRUNCATE", - "SYS_FTRUNCATE64", - "SYS_FUTEX", - "SYS_FUTIMENS", - "SYS_FUTIMES", - "SYS_FUTIMESAT", - "SYS_GETATTRLIST", - "SYS_GETAUDIT", - "SYS_GETAUDIT_ADDR", - "SYS_GETAUID", - "SYS_GETCONTEXT", - "SYS_GETCPU", - "SYS_GETCWD", - "SYS_GETDENTS", - "SYS_GETDENTS64", - "SYS_GETDIRENTRIES", - "SYS_GETDIRENTRIES64", - "SYS_GETDIRENTRIESATTR", - "SYS_GETDTABLECOUNT", - "SYS_GETDTABLESIZE", - "SYS_GETEGID", - "SYS_GETEGID32", - "SYS_GETEUID", - "SYS_GETEUID32", - "SYS_GETFH", - "SYS_GETFSSTAT", - "SYS_GETFSSTAT64", - "SYS_GETGID", - "SYS_GETGID32", - "SYS_GETGROUPS", - "SYS_GETGROUPS32", - "SYS_GETHOSTUUID", - "SYS_GETITIMER", - "SYS_GETLCID", - "SYS_GETLOGIN", - "SYS_GETLOGINCLASS", - "SYS_GETPEERNAME", - "SYS_GETPGID", - "SYS_GETPGRP", - "SYS_GETPID", - "SYS_GETPMSG", - "SYS_GETPPID", - "SYS_GETPRIORITY", - "SYS_GETRESGID", - "SYS_GETRESGID32", - "SYS_GETRESUID", - "SYS_GETRESUID32", - "SYS_GETRLIMIT", - "SYS_GETRTABLE", - "SYS_GETRUSAGE", - "SYS_GETSGROUPS", - "SYS_GETSID", - "SYS_GETSOCKNAME", - "SYS_GETSOCKOPT", - "SYS_GETTHRID", - "SYS_GETTID", - "SYS_GETTIMEOFDAY", - "SYS_GETUID", - "SYS_GETUID32", - "SYS_GETVFSSTAT", - "SYS_GETWGROUPS", - "SYS_GETXATTR", - "SYS_GET_KERNEL_SYMS", - "SYS_GET_MEMPOLICY", - "SYS_GET_ROBUST_LIST", - "SYS_GET_THREAD_AREA", - "SYS_GTTY", - "SYS_IDENTITYSVC", - "SYS_IDLE", - "SYS_INITGROUPS", - "SYS_INIT_MODULE", - "SYS_INOTIFY_ADD_WATCH", - "SYS_INOTIFY_INIT", - "SYS_INOTIFY_INIT1", - "SYS_INOTIFY_RM_WATCH", - "SYS_IOCTL", - "SYS_IOPERM", - "SYS_IOPL", - "SYS_IOPOLICYSYS", - "SYS_IOPRIO_GET", - "SYS_IOPRIO_SET", - "SYS_IO_CANCEL", - "SYS_IO_DESTROY", - "SYS_IO_GETEVENTS", - "SYS_IO_SETUP", - "SYS_IO_SUBMIT", - "SYS_IPC", - "SYS_ISSETUGID", - "SYS_JAIL", - "SYS_JAIL_ATTACH", - "SYS_JAIL_GET", - "SYS_JAIL_REMOVE", - "SYS_JAIL_SET", - "SYS_KAS_INFO", - "SYS_KDEBUG_TRACE", - "SYS_KENV", - "SYS_KEVENT", - "SYS_KEVENT64", - "SYS_KEXEC_LOAD", - "SYS_KEYCTL", - "SYS_KILL", - "SYS_KLDFIND", - "SYS_KLDFIRSTMOD", - "SYS_KLDLOAD", - "SYS_KLDNEXT", - "SYS_KLDSTAT", - "SYS_KLDSYM", - "SYS_KLDUNLOAD", - "SYS_KLDUNLOADF", - "SYS_KQUEUE", - "SYS_KQUEUE1", - "SYS_KTIMER_CREATE", - "SYS_KTIMER_DELETE", - "SYS_KTIMER_GETOVERRUN", - "SYS_KTIMER_GETTIME", - "SYS_KTIMER_SETTIME", - "SYS_KTRACE", - "SYS_LCHFLAGS", - "SYS_LCHMOD", - "SYS_LCHOWN", - "SYS_LCHOWN32", - "SYS_LEDGER", - "SYS_LGETFH", - "SYS_LGETXATTR", - "SYS_LINK", - "SYS_LINKAT", - "SYS_LIO_LISTIO", - "SYS_LISTEN", - "SYS_LISTXATTR", - "SYS_LLISTXATTR", - "SYS_LOCK", - "SYS_LOOKUP_DCOOKIE", - "SYS_LPATHCONF", - "SYS_LREMOVEXATTR", - "SYS_LSEEK", - "SYS_LSETXATTR", - "SYS_LSTAT", - "SYS_LSTAT64", - "SYS_LSTAT64_EXTENDED", - "SYS_LSTATV", - "SYS_LSTAT_EXTENDED", - "SYS_LUTIMES", - "SYS_MAC_SYSCALL", - "SYS_MADVISE", - "SYS_MADVISE1", - "SYS_MAXSYSCALL", - "SYS_MBIND", - "SYS_MIGRATE_PAGES", - "SYS_MINCORE", - "SYS_MINHERIT", - "SYS_MKCOMPLEX", - "SYS_MKDIR", - "SYS_MKDIRAT", - "SYS_MKDIR_EXTENDED", - "SYS_MKFIFO", - "SYS_MKFIFOAT", - "SYS_MKFIFO_EXTENDED", - "SYS_MKNOD", - "SYS_MKNODAT", - "SYS_MLOCK", - "SYS_MLOCKALL", - "SYS_MMAP", - "SYS_MMAP2", - "SYS_MODCTL", - "SYS_MODFIND", - "SYS_MODFNEXT", - "SYS_MODIFY_LDT", - "SYS_MODNEXT", - "SYS_MODSTAT", - "SYS_MODWATCH", - "SYS_MOUNT", - "SYS_MOVE_PAGES", - "SYS_MPROTECT", - "SYS_MPX", - "SYS_MQUERY", - "SYS_MQ_GETSETATTR", - "SYS_MQ_NOTIFY", - "SYS_MQ_OPEN", - "SYS_MQ_TIMEDRECEIVE", - "SYS_MQ_TIMEDSEND", - "SYS_MQ_UNLINK", - "SYS_MREMAP", - "SYS_MSGCTL", - "SYS_MSGGET", - "SYS_MSGRCV", - "SYS_MSGRCV_NOCANCEL", - "SYS_MSGSND", - "SYS_MSGSND_NOCANCEL", - "SYS_MSGSYS", - "SYS_MSYNC", - "SYS_MSYNC_NOCANCEL", - "SYS_MUNLOCK", - "SYS_MUNLOCKALL", - "SYS_MUNMAP", - "SYS_NAME_TO_HANDLE_AT", - "SYS_NANOSLEEP", - "SYS_NEWFSTATAT", - "SYS_NFSCLNT", - "SYS_NFSSERVCTL", - "SYS_NFSSVC", - "SYS_NFSTAT", - "SYS_NICE", - "SYS_NLSTAT", - "SYS_NMOUNT", - "SYS_NSTAT", - "SYS_NTP_ADJTIME", - "SYS_NTP_GETTIME", - "SYS_OABI_SYSCALL_BASE", - "SYS_OBREAK", - "SYS_OLDFSTAT", - "SYS_OLDLSTAT", - "SYS_OLDOLDUNAME", - "SYS_OLDSTAT", - "SYS_OLDUNAME", - "SYS_OPEN", - "SYS_OPENAT", - "SYS_OPENBSD_POLL", - "SYS_OPEN_BY_HANDLE_AT", - "SYS_OPEN_DPROTECTED_NP", - "SYS_OPEN_EXTENDED", - "SYS_OPEN_NOCANCEL", - "SYS_OVADVISE", - "SYS_PACCEPT", - "SYS_PATHCONF", - "SYS_PAUSE", - "SYS_PCICONFIG_IOBASE", - "SYS_PCICONFIG_READ", - "SYS_PCICONFIG_WRITE", - "SYS_PDFORK", - "SYS_PDGETPID", - "SYS_PDKILL", - "SYS_PERF_EVENT_OPEN", - "SYS_PERSONALITY", - "SYS_PID_HIBERNATE", - "SYS_PID_RESUME", - "SYS_PID_SHUTDOWN_SOCKETS", - "SYS_PID_SUSPEND", - "SYS_PIPE", - "SYS_PIPE2", - "SYS_PIVOT_ROOT", - "SYS_PMC_CONTROL", - "SYS_PMC_GET_INFO", - "SYS_POLL", - "SYS_POLLTS", - "SYS_POLL_NOCANCEL", - "SYS_POSIX_FADVISE", - "SYS_POSIX_FALLOCATE", - "SYS_POSIX_OPENPT", - "SYS_POSIX_SPAWN", - "SYS_PPOLL", - "SYS_PRCTL", - "SYS_PREAD", - "SYS_PREAD64", - "SYS_PREADV", - "SYS_PREAD_NOCANCEL", - "SYS_PRLIMIT64", - "SYS_PROCCTL", - "SYS_PROCESS_POLICY", - "SYS_PROCESS_VM_READV", - "SYS_PROCESS_VM_WRITEV", - "SYS_PROC_INFO", - "SYS_PROF", - "SYS_PROFIL", - "SYS_PSELECT", - "SYS_PSELECT6", - "SYS_PSET_ASSIGN", - "SYS_PSET_CREATE", - "SYS_PSET_DESTROY", - "SYS_PSYNCH_CVBROAD", - "SYS_PSYNCH_CVCLRPREPOST", - "SYS_PSYNCH_CVSIGNAL", - "SYS_PSYNCH_CVWAIT", - "SYS_PSYNCH_MUTEXDROP", - "SYS_PSYNCH_MUTEXWAIT", - "SYS_PSYNCH_RW_DOWNGRADE", - "SYS_PSYNCH_RW_LONGRDLOCK", - "SYS_PSYNCH_RW_RDLOCK", - "SYS_PSYNCH_RW_UNLOCK", - "SYS_PSYNCH_RW_UNLOCK2", - "SYS_PSYNCH_RW_UPGRADE", - "SYS_PSYNCH_RW_WRLOCK", - "SYS_PSYNCH_RW_YIELDWRLOCK", - "SYS_PTRACE", - "SYS_PUTPMSG", - "SYS_PWRITE", - "SYS_PWRITE64", - "SYS_PWRITEV", - "SYS_PWRITE_NOCANCEL", - "SYS_QUERY_MODULE", - "SYS_QUOTACTL", - "SYS_RASCTL", - "SYS_RCTL_ADD_RULE", - "SYS_RCTL_GET_LIMITS", - "SYS_RCTL_GET_RACCT", - "SYS_RCTL_GET_RULES", - "SYS_RCTL_REMOVE_RULE", - "SYS_READ", - "SYS_READAHEAD", - "SYS_READDIR", - "SYS_READLINK", - "SYS_READLINKAT", - "SYS_READV", - "SYS_READV_NOCANCEL", - "SYS_READ_NOCANCEL", - "SYS_REBOOT", - "SYS_RECV", - "SYS_RECVFROM", - "SYS_RECVFROM_NOCANCEL", - "SYS_RECVMMSG", - "SYS_RECVMSG", - "SYS_RECVMSG_NOCANCEL", - "SYS_REMAP_FILE_PAGES", - "SYS_REMOVEXATTR", - "SYS_RENAME", - "SYS_RENAMEAT", - "SYS_REQUEST_KEY", - "SYS_RESTART_SYSCALL", - "SYS_REVOKE", - "SYS_RFORK", - "SYS_RMDIR", - "SYS_RTPRIO", - "SYS_RTPRIO_THREAD", - "SYS_RT_SIGACTION", - "SYS_RT_SIGPENDING", - "SYS_RT_SIGPROCMASK", - "SYS_RT_SIGQUEUEINFO", - "SYS_RT_SIGRETURN", - "SYS_RT_SIGSUSPEND", - "SYS_RT_SIGTIMEDWAIT", - "SYS_RT_TGSIGQUEUEINFO", - "SYS_SBRK", - "SYS_SCHED_GETAFFINITY", - "SYS_SCHED_GETPARAM", - "SYS_SCHED_GETSCHEDULER", - "SYS_SCHED_GET_PRIORITY_MAX", - "SYS_SCHED_GET_PRIORITY_MIN", - "SYS_SCHED_RR_GET_INTERVAL", - "SYS_SCHED_SETAFFINITY", - "SYS_SCHED_SETPARAM", - "SYS_SCHED_SETSCHEDULER", - "SYS_SCHED_YIELD", - "SYS_SCTP_GENERIC_RECVMSG", - "SYS_SCTP_GENERIC_SENDMSG", - "SYS_SCTP_GENERIC_SENDMSG_IOV", - "SYS_SCTP_PEELOFF", - "SYS_SEARCHFS", - "SYS_SECURITY", - "SYS_SELECT", - "SYS_SELECT_NOCANCEL", - "SYS_SEMCONFIG", - "SYS_SEMCTL", - "SYS_SEMGET", - "SYS_SEMOP", - "SYS_SEMSYS", - "SYS_SEMTIMEDOP", - "SYS_SEM_CLOSE", - "SYS_SEM_DESTROY", - "SYS_SEM_GETVALUE", - "SYS_SEM_INIT", - "SYS_SEM_OPEN", - "SYS_SEM_POST", - "SYS_SEM_TRYWAIT", - "SYS_SEM_UNLINK", - "SYS_SEM_WAIT", - "SYS_SEM_WAIT_NOCANCEL", - "SYS_SEND", - "SYS_SENDFILE", - "SYS_SENDFILE64", - "SYS_SENDMMSG", - "SYS_SENDMSG", - "SYS_SENDMSG_NOCANCEL", - "SYS_SENDTO", - "SYS_SENDTO_NOCANCEL", - "SYS_SETATTRLIST", - "SYS_SETAUDIT", - "SYS_SETAUDIT_ADDR", - "SYS_SETAUID", - "SYS_SETCONTEXT", - "SYS_SETDOMAINNAME", - "SYS_SETEGID", - "SYS_SETEUID", - "SYS_SETFIB", - "SYS_SETFSGID", - "SYS_SETFSGID32", - "SYS_SETFSUID", - "SYS_SETFSUID32", - "SYS_SETGID", - "SYS_SETGID32", - "SYS_SETGROUPS", - "SYS_SETGROUPS32", - "SYS_SETHOSTNAME", - "SYS_SETITIMER", - "SYS_SETLCID", - "SYS_SETLOGIN", - "SYS_SETLOGINCLASS", - "SYS_SETNS", - "SYS_SETPGID", - "SYS_SETPRIORITY", - "SYS_SETPRIVEXEC", - "SYS_SETREGID", - "SYS_SETREGID32", - "SYS_SETRESGID", - "SYS_SETRESGID32", - "SYS_SETRESUID", - "SYS_SETRESUID32", - "SYS_SETREUID", - "SYS_SETREUID32", - "SYS_SETRLIMIT", - "SYS_SETRTABLE", - "SYS_SETSGROUPS", - "SYS_SETSID", - "SYS_SETSOCKOPT", - "SYS_SETTID", - "SYS_SETTID_WITH_PID", - "SYS_SETTIMEOFDAY", - "SYS_SETUID", - "SYS_SETUID32", - "SYS_SETWGROUPS", - "SYS_SETXATTR", - "SYS_SET_MEMPOLICY", - "SYS_SET_ROBUST_LIST", - "SYS_SET_THREAD_AREA", - "SYS_SET_TID_ADDRESS", - "SYS_SGETMASK", - "SYS_SHARED_REGION_CHECK_NP", - "SYS_SHARED_REGION_MAP_AND_SLIDE_NP", - "SYS_SHMAT", - "SYS_SHMCTL", - "SYS_SHMDT", - "SYS_SHMGET", - "SYS_SHMSYS", - "SYS_SHM_OPEN", - "SYS_SHM_UNLINK", - "SYS_SHUTDOWN", - "SYS_SIGACTION", - "SYS_SIGALTSTACK", - "SYS_SIGNAL", - "SYS_SIGNALFD", - "SYS_SIGNALFD4", - "SYS_SIGPENDING", - "SYS_SIGPROCMASK", - "SYS_SIGQUEUE", - "SYS_SIGQUEUEINFO", - "SYS_SIGRETURN", - "SYS_SIGSUSPEND", - "SYS_SIGSUSPEND_NOCANCEL", - "SYS_SIGTIMEDWAIT", - "SYS_SIGWAIT", - "SYS_SIGWAITINFO", - "SYS_SOCKET", - "SYS_SOCKETCALL", - "SYS_SOCKETPAIR", - "SYS_SPLICE", - "SYS_SSETMASK", - "SYS_SSTK", - "SYS_STACK_SNAPSHOT", - "SYS_STAT", - "SYS_STAT64", - "SYS_STAT64_EXTENDED", - "SYS_STATFS", - "SYS_STATFS64", - "SYS_STATV", - "SYS_STATVFS1", - "SYS_STAT_EXTENDED", - "SYS_STIME", - "SYS_STTY", - "SYS_SWAPCONTEXT", - "SYS_SWAPCTL", - "SYS_SWAPOFF", - "SYS_SWAPON", - "SYS_SYMLINK", - "SYS_SYMLINKAT", - "SYS_SYNC", - "SYS_SYNCFS", - "SYS_SYNC_FILE_RANGE", - "SYS_SYSARCH", - "SYS_SYSCALL", - "SYS_SYSCALL_BASE", - "SYS_SYSFS", - "SYS_SYSINFO", - "SYS_SYSLOG", - "SYS_TEE", - "SYS_TGKILL", - "SYS_THREAD_SELFID", - "SYS_THR_CREATE", - "SYS_THR_EXIT", - "SYS_THR_KILL", - "SYS_THR_KILL2", - "SYS_THR_NEW", - "SYS_THR_SELF", - "SYS_THR_SET_NAME", - "SYS_THR_SUSPEND", - "SYS_THR_WAKE", - "SYS_TIME", - "SYS_TIMERFD_CREATE", - "SYS_TIMERFD_GETTIME", - "SYS_TIMERFD_SETTIME", - "SYS_TIMER_CREATE", - "SYS_TIMER_DELETE", - "SYS_TIMER_GETOVERRUN", - "SYS_TIMER_GETTIME", - "SYS_TIMER_SETTIME", - "SYS_TIMES", - "SYS_TKILL", - "SYS_TRUNCATE", - "SYS_TRUNCATE64", - "SYS_TUXCALL", - "SYS_UGETRLIMIT", - "SYS_ULIMIT", - "SYS_UMASK", - "SYS_UMASK_EXTENDED", - "SYS_UMOUNT", - "SYS_UMOUNT2", - "SYS_UNAME", - "SYS_UNDELETE", - "SYS_UNLINK", - "SYS_UNLINKAT", - "SYS_UNMOUNT", - "SYS_UNSHARE", - "SYS_USELIB", - "SYS_USTAT", - "SYS_UTIME", - "SYS_UTIMENSAT", - "SYS_UTIMES", - "SYS_UTRACE", - "SYS_UUIDGEN", - "SYS_VADVISE", - "SYS_VFORK", - "SYS_VHANGUP", - "SYS_VM86", - "SYS_VM86OLD", - "SYS_VMSPLICE", - "SYS_VM_PRESSURE_MONITOR", - "SYS_VSERVER", - "SYS_WAIT4", - "SYS_WAIT4_NOCANCEL", - "SYS_WAIT6", - "SYS_WAITEVENT", - "SYS_WAITID", - "SYS_WAITID_NOCANCEL", - "SYS_WAITPID", - "SYS_WATCHEVENT", - "SYS_WORKQ_KERNRETURN", - "SYS_WORKQ_OPEN", - "SYS_WRITE", - "SYS_WRITEV", - "SYS_WRITEV_NOCANCEL", - "SYS_WRITE_NOCANCEL", - "SYS_YIELD", - "SYS__LLSEEK", - "SYS__LWP_CONTINUE", - "SYS__LWP_CREATE", - "SYS__LWP_CTL", - "SYS__LWP_DETACH", - "SYS__LWP_EXIT", - "SYS__LWP_GETNAME", - "SYS__LWP_GETPRIVATE", - "SYS__LWP_KILL", - "SYS__LWP_PARK", - "SYS__LWP_SELF", - "SYS__LWP_SETNAME", - "SYS__LWP_SETPRIVATE", - "SYS__LWP_SUSPEND", - "SYS__LWP_UNPARK", - "SYS__LWP_UNPARK_ALL", - "SYS__LWP_WAIT", - "SYS__LWP_WAKEUP", - "SYS__NEWSELECT", - "SYS__PSET_BIND", - "SYS__SCHED_GETAFFINITY", - "SYS__SCHED_GETPARAM", - "SYS__SCHED_SETAFFINITY", - "SYS__SCHED_SETPARAM", - "SYS__SYSCTL", - "SYS__UMTX_LOCK", - "SYS__UMTX_OP", - "SYS__UMTX_UNLOCK", - "SYS___ACL_ACLCHECK_FD", - "SYS___ACL_ACLCHECK_FILE", - "SYS___ACL_ACLCHECK_LINK", - "SYS___ACL_DELETE_FD", - "SYS___ACL_DELETE_FILE", - "SYS___ACL_DELETE_LINK", - "SYS___ACL_GET_FD", - "SYS___ACL_GET_FILE", - "SYS___ACL_GET_LINK", - "SYS___ACL_SET_FD", - "SYS___ACL_SET_FILE", - "SYS___ACL_SET_LINK", - "SYS___CLONE", - "SYS___DISABLE_THREADSIGNAL", - "SYS___GETCWD", - "SYS___GETLOGIN", - "SYS___GET_TCB", - "SYS___MAC_EXECVE", - "SYS___MAC_GETFSSTAT", - "SYS___MAC_GET_FD", - "SYS___MAC_GET_FILE", - "SYS___MAC_GET_LCID", - "SYS___MAC_GET_LCTX", - "SYS___MAC_GET_LINK", - "SYS___MAC_GET_MOUNT", - "SYS___MAC_GET_PID", - "SYS___MAC_GET_PROC", - "SYS___MAC_MOUNT", - "SYS___MAC_SET_FD", - "SYS___MAC_SET_FILE", - "SYS___MAC_SET_LCTX", - "SYS___MAC_SET_LINK", - "SYS___MAC_SET_PROC", - "SYS___MAC_SYSCALL", - "SYS___OLD_SEMWAIT_SIGNAL", - "SYS___OLD_SEMWAIT_SIGNAL_NOCANCEL", - "SYS___POSIX_CHOWN", - "SYS___POSIX_FCHOWN", - "SYS___POSIX_LCHOWN", - "SYS___POSIX_RENAME", - "SYS___PTHREAD_CANCELED", - "SYS___PTHREAD_CHDIR", - "SYS___PTHREAD_FCHDIR", - "SYS___PTHREAD_KILL", - "SYS___PTHREAD_MARKCANCEL", - "SYS___PTHREAD_SIGMASK", - "SYS___QUOTACTL", - "SYS___SEMCTL", - "SYS___SEMWAIT_SIGNAL", - "SYS___SEMWAIT_SIGNAL_NOCANCEL", - "SYS___SETLOGIN", - "SYS___SETUGID", - "SYS___SET_TCB", - "SYS___SIGACTION_SIGTRAMP", - "SYS___SIGTIMEDWAIT", - "SYS___SIGWAIT", - "SYS___SIGWAIT_NOCANCEL", - "SYS___SYSCTL", - "SYS___TFORK", - "SYS___THREXIT", - "SYS___THRSIGDIVERT", - "SYS___THRSLEEP", - "SYS___THRWAKEUP", - "S_ARCH1", - "S_ARCH2", - "S_BLKSIZE", - "S_IEXEC", - "S_IFBLK", - "S_IFCHR", - "S_IFDIR", - "S_IFIFO", - "S_IFLNK", - "S_IFMT", - "S_IFREG", - "S_IFSOCK", - "S_IFWHT", - "S_IREAD", - "S_IRGRP", - "S_IROTH", - "S_IRUSR", - "S_IRWXG", - "S_IRWXO", - "S_IRWXU", - "S_ISGID", - "S_ISTXT", - "S_ISUID", - "S_ISVTX", - "S_IWGRP", - "S_IWOTH", - "S_IWRITE", - "S_IWUSR", - "S_IXGRP", - "S_IXOTH", - "S_IXUSR", - "S_LOGIN_SET", - "SecurityAttributes", - "Seek", - "Select", - "Sendfile", - "Sendmsg", - "SendmsgN", - "Sendto", - "Servent", - "SetBpf", - "SetBpfBuflen", - "SetBpfDatalink", - "SetBpfHeadercmpl", - "SetBpfImmediate", - "SetBpfInterface", - "SetBpfPromisc", - "SetBpfTimeout", - "SetCurrentDirectory", - "SetEndOfFile", - "SetEnvironmentVariable", - "SetFileAttributes", - "SetFileCompletionNotificationModes", - "SetFilePointer", - "SetFileTime", - "SetHandleInformation", - "SetKevent", - "SetLsfPromisc", - "SetNonblock", - "Setdomainname", - "Setegid", - "Setenv", - "Seteuid", - "Setfsgid", - "Setfsuid", - "Setgid", - "Setgroups", - "Sethostname", - "Setlogin", - "Setpgid", - "Setpriority", - "Setprivexec", - "Setregid", - "Setresgid", - "Setresuid", - "Setreuid", - "Setrlimit", - "Setsid", - "Setsockopt", - "SetsockoptByte", - "SetsockoptICMPv6Filter", - "SetsockoptIPMreq", - "SetsockoptIPMreqn", - "SetsockoptIPv6Mreq", - "SetsockoptInet4Addr", - "SetsockoptInt", - "SetsockoptLinger", - "SetsockoptString", - "SetsockoptTimeval", - "Settimeofday", - "Setuid", - "Setxattr", - "Shutdown", - "SidTypeAlias", - "SidTypeComputer", - "SidTypeDeletedAccount", - "SidTypeDomain", - "SidTypeGroup", - "SidTypeInvalid", - "SidTypeLabel", - "SidTypeUnknown", - "SidTypeUser", - "SidTypeWellKnownGroup", - "Signal", - "SizeofBpfHdr", - "SizeofBpfInsn", - "SizeofBpfProgram", - "SizeofBpfStat", - "SizeofBpfVersion", - "SizeofBpfZbuf", - "SizeofBpfZbufHeader", - "SizeofCmsghdr", - "SizeofICMPv6Filter", - "SizeofIPMreq", - "SizeofIPMreqn", - "SizeofIPv6MTUInfo", - "SizeofIPv6Mreq", - "SizeofIfAddrmsg", - "SizeofIfAnnounceMsghdr", - "SizeofIfData", - "SizeofIfInfomsg", - "SizeofIfMsghdr", - "SizeofIfaMsghdr", - "SizeofIfmaMsghdr", - "SizeofIfmaMsghdr2", - "SizeofInet4Pktinfo", - "SizeofInet6Pktinfo", - "SizeofInotifyEvent", - "SizeofLinger", - "SizeofMsghdr", - "SizeofNlAttr", - "SizeofNlMsgerr", - "SizeofNlMsghdr", - "SizeofRtAttr", - "SizeofRtGenmsg", - "SizeofRtMetrics", - "SizeofRtMsg", - "SizeofRtMsghdr", - "SizeofRtNexthop", - "SizeofSockFilter", - "SizeofSockFprog", - "SizeofSockaddrAny", - "SizeofSockaddrDatalink", - "SizeofSockaddrInet4", - "SizeofSockaddrInet6", - "SizeofSockaddrLinklayer", - "SizeofSockaddrNetlink", - "SizeofSockaddrUnix", - "SizeofTCPInfo", - "SizeofUcred", - "SlicePtrFromStrings", - "SockFilter", - "SockFprog", - "Sockaddr", - "SockaddrDatalink", - "SockaddrGen", - "SockaddrInet4", - "SockaddrInet6", - "SockaddrLinklayer", - "SockaddrNetlink", - "SockaddrUnix", - "Socket", - "SocketControlMessage", - "SocketDisableIPv6", - "Socketpair", - "Splice", - "StartProcess", - "StartupInfo", - "Stat", - "Stat_t", - "Statfs", - "Statfs_t", - "Stderr", - "Stdin", - "Stdout", - "StringBytePtr", - "StringByteSlice", - "StringSlicePtr", - "StringToSid", - "StringToUTF16", - "StringToUTF16Ptr", - "Symlink", - "Sync", - "SyncFileRange", - "SysProcAttr", - "SysProcIDMap", - "Syscall", - "Syscall12", - "Syscall15", - "Syscall18", - "Syscall6", - "Syscall9", - "SyscallN", - "Sysctl", - "SysctlUint32", - "Sysctlnode", - "Sysinfo", - "Sysinfo_t", - "Systemtime", - "TCGETS", - "TCIFLUSH", - "TCIOFLUSH", - "TCOFLUSH", - "TCPInfo", - "TCPKeepalive", - "TCP_CA_NAME_MAX", - "TCP_CONGCTL", - "TCP_CONGESTION", - "TCP_CONNECTIONTIMEOUT", - "TCP_CORK", - "TCP_DEFER_ACCEPT", - "TCP_ENABLE_ECN", - "TCP_INFO", - "TCP_KEEPALIVE", - "TCP_KEEPCNT", - "TCP_KEEPIDLE", - "TCP_KEEPINIT", - "TCP_KEEPINTVL", - "TCP_LINGER2", - "TCP_MAXBURST", - "TCP_MAXHLEN", - "TCP_MAXOLEN", - "TCP_MAXSEG", - "TCP_MAXWIN", - "TCP_MAX_SACK", - "TCP_MAX_WINSHIFT", - "TCP_MD5SIG", - "TCP_MD5SIG_MAXKEYLEN", - "TCP_MINMSS", - "TCP_MINMSSOVERLOAD", - "TCP_MSS", - "TCP_NODELAY", - "TCP_NOOPT", - "TCP_NOPUSH", - "TCP_NOTSENT_LOWAT", - "TCP_NSTATES", - "TCP_QUICKACK", - "TCP_RXT_CONNDROPTIME", - "TCP_RXT_FINDROP", - "TCP_SACK_ENABLE", - "TCP_SENDMOREACKS", - "TCP_SYNCNT", - "TCP_VENDOR", - "TCP_WINDOW_CLAMP", - "TCSAFLUSH", - "TCSETS", - "TF_DISCONNECT", - "TF_REUSE_SOCKET", - "TF_USE_DEFAULT_WORKER", - "TF_USE_KERNEL_APC", - "TF_USE_SYSTEM_THREAD", - "TF_WRITE_BEHIND", - "TH32CS_INHERIT", - "TH32CS_SNAPALL", - "TH32CS_SNAPHEAPLIST", - "TH32CS_SNAPMODULE", - "TH32CS_SNAPMODULE32", - "TH32CS_SNAPPROCESS", - "TH32CS_SNAPTHREAD", - "TIME_ZONE_ID_DAYLIGHT", - "TIME_ZONE_ID_STANDARD", - "TIME_ZONE_ID_UNKNOWN", - "TIOCCBRK", - "TIOCCDTR", - "TIOCCONS", - "TIOCDCDTIMESTAMP", - "TIOCDRAIN", - "TIOCDSIMICROCODE", - "TIOCEXCL", - "TIOCEXT", - "TIOCFLAG_CDTRCTS", - "TIOCFLAG_CLOCAL", - "TIOCFLAG_CRTSCTS", - "TIOCFLAG_MDMBUF", - "TIOCFLAG_PPS", - "TIOCFLAG_SOFTCAR", - "TIOCFLUSH", - "TIOCGDEV", - "TIOCGDRAINWAIT", - "TIOCGETA", - "TIOCGETD", - "TIOCGFLAGS", - "TIOCGICOUNT", - "TIOCGLCKTRMIOS", - "TIOCGLINED", - "TIOCGPGRP", - "TIOCGPTN", - "TIOCGQSIZE", - "TIOCGRANTPT", - "TIOCGRS485", - "TIOCGSERIAL", - "TIOCGSID", - "TIOCGSIZE", - "TIOCGSOFTCAR", - "TIOCGTSTAMP", - "TIOCGWINSZ", - "TIOCINQ", - "TIOCIXOFF", - "TIOCIXON", - "TIOCLINUX", - "TIOCMBIC", - "TIOCMBIS", - "TIOCMGDTRWAIT", - "TIOCMGET", - "TIOCMIWAIT", - "TIOCMODG", - "TIOCMODS", - "TIOCMSDTRWAIT", - "TIOCMSET", - "TIOCM_CAR", - "TIOCM_CD", - "TIOCM_CTS", - "TIOCM_DCD", - "TIOCM_DSR", - "TIOCM_DTR", - "TIOCM_LE", - "TIOCM_RI", - "TIOCM_RNG", - "TIOCM_RTS", - "TIOCM_SR", - "TIOCM_ST", - "TIOCNOTTY", - "TIOCNXCL", - "TIOCOUTQ", - "TIOCPKT", - "TIOCPKT_DATA", - "TIOCPKT_DOSTOP", - "TIOCPKT_FLUSHREAD", - "TIOCPKT_FLUSHWRITE", - "TIOCPKT_IOCTL", - "TIOCPKT_NOSTOP", - "TIOCPKT_START", - "TIOCPKT_STOP", - "TIOCPTMASTER", - "TIOCPTMGET", - "TIOCPTSNAME", - "TIOCPTYGNAME", - "TIOCPTYGRANT", - "TIOCPTYUNLK", - "TIOCRCVFRAME", - "TIOCREMOTE", - "TIOCSBRK", - "TIOCSCONS", - "TIOCSCTTY", - "TIOCSDRAINWAIT", - "TIOCSDTR", - "TIOCSERCONFIG", - "TIOCSERGETLSR", - "TIOCSERGETMULTI", - "TIOCSERGSTRUCT", - "TIOCSERGWILD", - "TIOCSERSETMULTI", - "TIOCSERSWILD", - "TIOCSER_TEMT", - "TIOCSETA", - "TIOCSETAF", - "TIOCSETAW", - "TIOCSETD", - "TIOCSFLAGS", - "TIOCSIG", - "TIOCSLCKTRMIOS", - "TIOCSLINED", - "TIOCSPGRP", - "TIOCSPTLCK", - "TIOCSQSIZE", - "TIOCSRS485", - "TIOCSSERIAL", - "TIOCSSIZE", - "TIOCSSOFTCAR", - "TIOCSTART", - "TIOCSTAT", - "TIOCSTI", - "TIOCSTOP", - "TIOCSTSTAMP", - "TIOCSWINSZ", - "TIOCTIMESTAMP", - "TIOCUCNTL", - "TIOCVHANGUP", - "TIOCXMTFRAME", - "TOKEN_ADJUST_DEFAULT", - "TOKEN_ADJUST_GROUPS", - "TOKEN_ADJUST_PRIVILEGES", - "TOKEN_ADJUST_SESSIONID", - "TOKEN_ALL_ACCESS", - "TOKEN_ASSIGN_PRIMARY", - "TOKEN_DUPLICATE", - "TOKEN_EXECUTE", - "TOKEN_IMPERSONATE", - "TOKEN_QUERY", - "TOKEN_QUERY_SOURCE", - "TOKEN_READ", - "TOKEN_WRITE", - "TOSTOP", - "TRUNCATE_EXISTING", - "TUNATTACHFILTER", - "TUNDETACHFILTER", - "TUNGETFEATURES", - "TUNGETIFF", - "TUNGETSNDBUF", - "TUNGETVNETHDRSZ", - "TUNSETDEBUG", - "TUNSETGROUP", - "TUNSETIFF", - "TUNSETLINK", - "TUNSETNOCSUM", - "TUNSETOFFLOAD", - "TUNSETOWNER", - "TUNSETPERSIST", - "TUNSETSNDBUF", - "TUNSETTXFILTER", - "TUNSETVNETHDRSZ", - "Tee", - "TerminateProcess", - "Termios", - "Tgkill", - "Time", - "Time_t", - "Times", - "Timespec", - "TimespecToNsec", - "Timeval", - "Timeval32", - "TimevalToNsec", - "Timex", - "Timezoneinformation", - "Tms", - "Token", - "TokenAccessInformation", - "TokenAuditPolicy", - "TokenDefaultDacl", - "TokenElevation", - "TokenElevationType", - "TokenGroups", - "TokenGroupsAndPrivileges", - "TokenHasRestrictions", - "TokenImpersonationLevel", - "TokenIntegrityLevel", - "TokenLinkedToken", - "TokenLogonSid", - "TokenMandatoryPolicy", - "TokenOrigin", - "TokenOwner", - "TokenPrimaryGroup", - "TokenPrivileges", - "TokenRestrictedSids", - "TokenSandBoxInert", - "TokenSessionId", - "TokenSessionReference", - "TokenSource", - "TokenStatistics", - "TokenType", - "TokenUIAccess", - "TokenUser", - "TokenVirtualizationAllowed", - "TokenVirtualizationEnabled", - "Tokenprimarygroup", - "Tokenuser", - "TranslateAccountName", - "TranslateName", - "TransmitFile", - "TransmitFileBuffers", - "Truncate", - "UNIX_PATH_MAX", - "USAGE_MATCH_TYPE_AND", - "USAGE_MATCH_TYPE_OR", - "UTF16FromString", - "UTF16PtrFromString", - "UTF16ToString", - "Ucred", - "Umask", - "Uname", - "Undelete", - "UnixCredentials", - "UnixRights", - "Unlink", - "Unlinkat", - "UnmapViewOfFile", - "Unmount", - "Unsetenv", - "Unshare", - "UserInfo10", - "Ustat", - "Ustat_t", - "Utimbuf", - "Utime", - "Utimes", - "UtimesNano", - "Utsname", - "VDISCARD", - "VDSUSP", - "VEOF", - "VEOL", - "VEOL2", - "VERASE", - "VERASE2", - "VINTR", - "VKILL", - "VLNEXT", - "VMIN", - "VQUIT", - "VREPRINT", - "VSTART", - "VSTATUS", - "VSTOP", - "VSUSP", - "VSWTC", - "VT0", - "VT1", - "VTDLY", - "VTIME", - "VWERASE", - "VirtualLock", - "VirtualUnlock", - "WAIT_ABANDONED", - "WAIT_FAILED", - "WAIT_OBJECT_0", - "WAIT_TIMEOUT", - "WALL", - "WALLSIG", - "WALTSIG", - "WCLONE", - "WCONTINUED", - "WCOREFLAG", - "WEXITED", - "WLINUXCLONE", - "WNOHANG", - "WNOTHREAD", - "WNOWAIT", - "WNOZOMBIE", - "WOPTSCHECKED", - "WORDSIZE", - "WSABuf", - "WSACleanup", - "WSADESCRIPTION_LEN", - "WSAData", - "WSAEACCES", - "WSAECONNABORTED", - "WSAECONNRESET", - "WSAEnumProtocols", - "WSAID_CONNECTEX", - "WSAIoctl", - "WSAPROTOCOL_LEN", - "WSAProtocolChain", - "WSAProtocolInfo", - "WSARecv", - "WSARecvFrom", - "WSASYS_STATUS_LEN", - "WSASend", - "WSASendTo", - "WSASendto", - "WSAStartup", - "WSTOPPED", - "WTRAPPED", - "WUNTRACED", - "Wait4", - "WaitForSingleObject", - "WaitStatus", - "Win32FileAttributeData", - "Win32finddata", - "Write", - "WriteConsole", - "WriteFile", - "X509_ASN_ENCODING", - "XCASE", - "XP1_CONNECTIONLESS", - "XP1_CONNECT_DATA", - "XP1_DISCONNECT_DATA", - "XP1_EXPEDITED_DATA", - "XP1_GRACEFUL_CLOSE", - "XP1_GUARANTEED_DELIVERY", - "XP1_GUARANTEED_ORDER", - "XP1_IFS_HANDLES", - "XP1_MESSAGE_ORIENTED", - "XP1_MULTIPOINT_CONTROL_PLANE", - "XP1_MULTIPOINT_DATA_PLANE", - "XP1_PARTIAL_MESSAGE", - "XP1_PSEUDO_STREAM", - "XP1_QOS_SUPPORTED", - "XP1_SAN_SUPPORT_SDP", - "XP1_SUPPORT_BROADCAST", - "XP1_SUPPORT_MULTIPOINT", - "XP1_UNI_RECV", - "XP1_UNI_SEND", - }, - "syscall/js": { - "CopyBytesToGo", - "CopyBytesToJS", - "Error", - "Func", - "FuncOf", - "Global", - "Null", - "Type", - "TypeBoolean", - "TypeFunction", - "TypeNull", - "TypeNumber", - "TypeObject", - "TypeString", - "TypeSymbol", - "TypeUndefined", - "Undefined", - "Value", - "ValueError", - "ValueOf", - }, - "testing": { - "AllocsPerRun", - "B", - "Benchmark", - "BenchmarkResult", - "Cover", - "CoverBlock", - "CoverMode", - "Coverage", - "F", - "Init", - "InternalBenchmark", - "InternalExample", - "InternalFuzzTarget", - "InternalTest", - "M", - "Main", - "MainStart", - "PB", - "RegisterCover", - "RunBenchmarks", - "RunExamples", - "RunTests", - "Short", - "T", - "TB", - "Verbose", - }, - "testing/fstest": { - "MapFS", - "MapFile", - "TestFS", - }, - "testing/iotest": { - "DataErrReader", - "ErrReader", - "ErrTimeout", - "HalfReader", - "NewReadLogger", - "NewWriteLogger", - "OneByteReader", - "TestReader", - "TimeoutReader", - "TruncateWriter", - }, - "testing/quick": { - "Check", - "CheckEqual", - "CheckEqualError", - "CheckError", - "Config", - "Generator", - "SetupError", - "Value", - }, - "text/scanner": { - "Char", - "Comment", - "EOF", - "Float", - "GoTokens", - "GoWhitespace", - "Ident", - "Int", - "Position", - "RawString", - "ScanChars", - "ScanComments", - "ScanFloats", - "ScanIdents", - "ScanInts", - "ScanRawStrings", - "ScanStrings", - "Scanner", - "SkipComments", - "String", - "TokenString", - }, - "text/tabwriter": { - "AlignRight", - "Debug", - "DiscardEmptyColumns", - "Escape", - "FilterHTML", - "NewWriter", - "StripEscape", - "TabIndent", - "Writer", - }, - "text/template": { - "ExecError", - "FuncMap", - "HTMLEscape", - "HTMLEscapeString", - "HTMLEscaper", - "IsTrue", - "JSEscape", - "JSEscapeString", - "JSEscaper", - "Must", - "New", - "ParseFS", - "ParseFiles", - "ParseGlob", - "Template", - "URLQueryEscaper", - }, - "text/template/parse": { - "ActionNode", - "BoolNode", - "BranchNode", - "BreakNode", - "ChainNode", - "CommandNode", - "CommentNode", - "ContinueNode", - "DotNode", - "FieldNode", - "IdentifierNode", - "IfNode", - "IsEmptyTree", - "ListNode", - "Mode", - "New", - "NewIdentifier", - "NilNode", - "Node", - "NodeAction", - "NodeBool", - "NodeBreak", - "NodeChain", - "NodeCommand", - "NodeComment", - "NodeContinue", - "NodeDot", - "NodeField", - "NodeIdentifier", - "NodeIf", - "NodeList", - "NodeNil", - "NodeNumber", - "NodePipe", - "NodeRange", - "NodeString", - "NodeTemplate", - "NodeText", - "NodeType", - "NodeVariable", - "NodeWith", - "NumberNode", - "Parse", - "ParseComments", - "PipeNode", - "Pos", - "RangeNode", - "SkipFuncCheck", - "StringNode", - "TemplateNode", - "TextNode", - "Tree", - "VariableNode", - "WithNode", - }, - "time": { - "ANSIC", - "After", - "AfterFunc", - "April", - "August", - "Date", - "DateOnly", - "DateTime", - "December", - "Duration", - "February", - "FixedZone", - "Friday", - "Hour", - "January", - "July", - "June", - "Kitchen", - "Layout", - "LoadLocation", - "LoadLocationFromTZData", - "Local", - "Location", - "March", - "May", - "Microsecond", - "Millisecond", - "Minute", - "Monday", - "Month", - "Nanosecond", - "NewTicker", - "NewTimer", - "November", - "Now", - "October", - "Parse", - "ParseDuration", - "ParseError", - "ParseInLocation", - "RFC1123", - "RFC1123Z", - "RFC3339", - "RFC3339Nano", - "RFC822", - "RFC822Z", - "RFC850", - "RubyDate", - "Saturday", - "Second", - "September", - "Since", - "Sleep", - "Stamp", - "StampMicro", - "StampMilli", - "StampNano", - "Sunday", - "Thursday", - "Tick", - "Ticker", - "Time", - "TimeOnly", - "Timer", - "Tuesday", - "UTC", - "Unix", - "UnixDate", - "UnixMicro", - "UnixMilli", - "Until", - "Wednesday", - "Weekday", - }, - "unicode": { - "ASCII_Hex_Digit", - "Adlam", - "Ahom", - "Anatolian_Hieroglyphs", - "Arabic", - "Armenian", - "Avestan", - "AzeriCase", - "Balinese", - "Bamum", - "Bassa_Vah", - "Batak", - "Bengali", - "Bhaiksuki", - "Bidi_Control", - "Bopomofo", - "Brahmi", - "Braille", - "Buginese", - "Buhid", - "C", - "Canadian_Aboriginal", - "Carian", - "CaseRange", - "CaseRanges", - "Categories", - "Caucasian_Albanian", - "Cc", - "Cf", - "Chakma", - "Cham", - "Cherokee", - "Chorasmian", - "Co", - "Common", - "Coptic", - "Cs", - "Cuneiform", - "Cypriot", - "Cyrillic", - "Dash", - "Deprecated", - "Deseret", - "Devanagari", - "Diacritic", - "Digit", - "Dives_Akuru", - "Dogra", - "Duployan", - "Egyptian_Hieroglyphs", - "Elbasan", - "Elymaic", - "Ethiopic", - "Extender", - "FoldCategory", - "FoldScript", - "Georgian", - "Glagolitic", - "Gothic", - "Grantha", - "GraphicRanges", - "Greek", - "Gujarati", - "Gunjala_Gondi", - "Gurmukhi", - "Han", - "Hangul", - "Hanifi_Rohingya", - "Hanunoo", - "Hatran", - "Hebrew", - "Hex_Digit", - "Hiragana", - "Hyphen", - "IDS_Binary_Operator", - "IDS_Trinary_Operator", - "Ideographic", - "Imperial_Aramaic", - "In", - "Inherited", - "Inscriptional_Pahlavi", - "Inscriptional_Parthian", - "Is", - "IsControl", - "IsDigit", - "IsGraphic", - "IsLetter", - "IsLower", - "IsMark", - "IsNumber", - "IsOneOf", - "IsPrint", - "IsPunct", - "IsSpace", - "IsSymbol", - "IsTitle", - "IsUpper", - "Javanese", - "Join_Control", - "Kaithi", - "Kannada", - "Katakana", - "Kayah_Li", - "Kharoshthi", - "Khitan_Small_Script", - "Khmer", - "Khojki", - "Khudawadi", - "L", - "Lao", - "Latin", - "Lepcha", - "Letter", - "Limbu", - "Linear_A", - "Linear_B", - "Lisu", - "Ll", - "Lm", - "Lo", - "Logical_Order_Exception", - "Lower", - "LowerCase", - "Lt", - "Lu", - "Lycian", - "Lydian", - "M", - "Mahajani", - "Makasar", - "Malayalam", - "Mandaic", - "Manichaean", - "Marchen", - "Mark", - "Masaram_Gondi", - "MaxASCII", - "MaxCase", - "MaxLatin1", - "MaxRune", - "Mc", - "Me", - "Medefaidrin", - "Meetei_Mayek", - "Mende_Kikakui", - "Meroitic_Cursive", - "Meroitic_Hieroglyphs", - "Miao", - "Mn", - "Modi", - "Mongolian", - "Mro", - "Multani", - "Myanmar", - "N", - "Nabataean", - "Nandinagari", - "Nd", - "New_Tai_Lue", - "Newa", - "Nko", - "Nl", - "No", - "Noncharacter_Code_Point", - "Number", - "Nushu", - "Nyiakeng_Puachue_Hmong", - "Ogham", - "Ol_Chiki", - "Old_Hungarian", - "Old_Italic", - "Old_North_Arabian", - "Old_Permic", - "Old_Persian", - "Old_Sogdian", - "Old_South_Arabian", - "Old_Turkic", - "Oriya", - "Osage", - "Osmanya", - "Other", - "Other_Alphabetic", - "Other_Default_Ignorable_Code_Point", - "Other_Grapheme_Extend", - "Other_ID_Continue", - "Other_ID_Start", - "Other_Lowercase", - "Other_Math", - "Other_Uppercase", - "P", - "Pahawh_Hmong", - "Palmyrene", - "Pattern_Syntax", - "Pattern_White_Space", - "Pau_Cin_Hau", - "Pc", - "Pd", - "Pe", - "Pf", - "Phags_Pa", - "Phoenician", - "Pi", - "Po", - "Prepended_Concatenation_Mark", - "PrintRanges", - "Properties", - "Ps", - "Psalter_Pahlavi", - "Punct", - "Quotation_Mark", - "Radical", - "Range16", - "Range32", - "RangeTable", - "Regional_Indicator", - "Rejang", - "ReplacementChar", - "Runic", - "S", - "STerm", - "Samaritan", - "Saurashtra", - "Sc", - "Scripts", - "Sentence_Terminal", - "Sharada", - "Shavian", - "Siddham", - "SignWriting", - "SimpleFold", - "Sinhala", - "Sk", - "Sm", - "So", - "Soft_Dotted", - "Sogdian", - "Sora_Sompeng", - "Soyombo", - "Space", - "SpecialCase", - "Sundanese", - "Syloti_Nagri", - "Symbol", - "Syriac", - "Tagalog", - "Tagbanwa", - "Tai_Le", - "Tai_Tham", - "Tai_Viet", - "Takri", - "Tamil", - "Tangut", - "Telugu", - "Terminal_Punctuation", - "Thaana", - "Thai", - "Tibetan", - "Tifinagh", - "Tirhuta", - "Title", - "TitleCase", - "To", - "ToLower", - "ToTitle", - "ToUpper", - "TurkishCase", - "Ugaritic", - "Unified_Ideograph", - "Upper", - "UpperCase", - "UpperLower", - "Vai", - "Variation_Selector", - "Version", - "Wancho", - "Warang_Citi", - "White_Space", - "Yezidi", - "Yi", - "Z", - "Zanabazar_Square", - "Zl", - "Zp", - "Zs", - }, - "unicode/utf16": { - "AppendRune", - "Decode", - "DecodeRune", - "Encode", - "EncodeRune", - "IsSurrogate", - }, - "unicode/utf8": { - "AppendRune", - "DecodeLastRune", - "DecodeLastRuneInString", - "DecodeRune", - "DecodeRuneInString", - "EncodeRune", - "FullRune", - "FullRuneInString", - "MaxRune", - "RuneCount", - "RuneCountInString", - "RuneError", - "RuneLen", - "RuneSelf", - "RuneStart", - "UTFMax", - "Valid", - "ValidRune", - "ValidString", - }, - "unsafe": { - "Add", - "Alignof", - "Offsetof", - "Pointer", - "Sizeof", - "Slice", - "SliceData", - "String", - "StringData", - }, -} diff --git a/vendor/golang.org/x/tools/internal/pkgbits/codes.go b/vendor/golang.org/x/tools/internal/pkgbits/codes.go deleted file mode 100644 index f0cabde96eb..00000000000 --- a/vendor/golang.org/x/tools/internal/pkgbits/codes.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package pkgbits - -// A Code is an enum value that can be encoded into bitstreams. -// -// Code types are preferable for enum types, because they allow -// Decoder to detect desyncs. -type Code interface { - // Marker returns the SyncMarker for the Code's dynamic type. - Marker() SyncMarker - - // Value returns the Code's ordinal value. - Value() int -} - -// A CodeVal distinguishes among go/constant.Value encodings. -type CodeVal int - -func (c CodeVal) Marker() SyncMarker { return SyncVal } -func (c CodeVal) Value() int { return int(c) } - -// Note: These values are public and cannot be changed without -// updating the go/types importers. - -const ( - ValBool CodeVal = iota - ValString - ValInt64 - ValBigInt - ValBigRat - ValBigFloat -) - -// A CodeType distinguishes among go/types.Type encodings. -type CodeType int - -func (c CodeType) Marker() SyncMarker { return SyncType } -func (c CodeType) Value() int { return int(c) } - -// Note: These values are public and cannot be changed without -// updating the go/types importers. - -const ( - TypeBasic CodeType = iota - TypeNamed - TypePointer - TypeSlice - TypeArray - TypeChan - TypeMap - TypeSignature - TypeStruct - TypeInterface - TypeUnion - TypeTypeParam -) - -// A CodeObj distinguishes among go/types.Object encodings. -type CodeObj int - -func (c CodeObj) Marker() SyncMarker { return SyncCodeObj } -func (c CodeObj) Value() int { return int(c) } - -// Note: These values are public and cannot be changed without -// updating the go/types importers. - -const ( - ObjAlias CodeObj = iota - ObjConst - ObjType - ObjFunc - ObjVar - ObjStub -) diff --git a/vendor/golang.org/x/tools/internal/pkgbits/decoder.go b/vendor/golang.org/x/tools/internal/pkgbits/decoder.go deleted file mode 100644 index b92e8e6eb32..00000000000 --- a/vendor/golang.org/x/tools/internal/pkgbits/decoder.go +++ /dev/null @@ -1,517 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package pkgbits - -import ( - "encoding/binary" - "errors" - "fmt" - "go/constant" - "go/token" - "io" - "math/big" - "os" - "runtime" - "strings" -) - -// A PkgDecoder provides methods for decoding a package's Unified IR -// export data. -type PkgDecoder struct { - // version is the file format version. - version uint32 - - // sync indicates whether the file uses sync markers. - sync bool - - // pkgPath is the package path for the package to be decoded. - // - // TODO(mdempsky): Remove; unneeded since CL 391014. - pkgPath string - - // elemData is the full data payload of the encoded package. - // Elements are densely and contiguously packed together. - // - // The last 8 bytes of elemData are the package fingerprint. - elemData string - - // elemEnds stores the byte-offset end positions of element - // bitstreams within elemData. - // - // For example, element I's bitstream data starts at elemEnds[I-1] - // (or 0, if I==0) and ends at elemEnds[I]. - // - // Note: elemEnds is indexed by absolute indices, not - // section-relative indices. - elemEnds []uint32 - - // elemEndsEnds stores the index-offset end positions of relocation - // sections within elemEnds. - // - // For example, section K's end positions start at elemEndsEnds[K-1] - // (or 0, if K==0) and end at elemEndsEnds[K]. - elemEndsEnds [numRelocs]uint32 - - scratchRelocEnt []RelocEnt -} - -// PkgPath returns the package path for the package -// -// TODO(mdempsky): Remove; unneeded since CL 391014. -func (pr *PkgDecoder) PkgPath() string { return pr.pkgPath } - -// SyncMarkers reports whether pr uses sync markers. -func (pr *PkgDecoder) SyncMarkers() bool { return pr.sync } - -// NewPkgDecoder returns a PkgDecoder initialized to read the Unified -// IR export data from input. pkgPath is the package path for the -// compilation unit that produced the export data. -// -// TODO(mdempsky): Remove pkgPath parameter; unneeded since CL 391014. -func NewPkgDecoder(pkgPath, input string) PkgDecoder { - pr := PkgDecoder{ - pkgPath: pkgPath, - } - - // TODO(mdempsky): Implement direct indexing of input string to - // avoid copying the position information. - - r := strings.NewReader(input) - - assert(binary.Read(r, binary.LittleEndian, &pr.version) == nil) - - switch pr.version { - default: - panic(fmt.Errorf("unsupported version: %v", pr.version)) - case 0: - // no flags - case 1: - var flags uint32 - assert(binary.Read(r, binary.LittleEndian, &flags) == nil) - pr.sync = flags&flagSyncMarkers != 0 - } - - assert(binary.Read(r, binary.LittleEndian, pr.elemEndsEnds[:]) == nil) - - pr.elemEnds = make([]uint32, pr.elemEndsEnds[len(pr.elemEndsEnds)-1]) - assert(binary.Read(r, binary.LittleEndian, pr.elemEnds[:]) == nil) - - pos, err := r.Seek(0, io.SeekCurrent) - assert(err == nil) - - pr.elemData = input[pos:] - assert(len(pr.elemData)-8 == int(pr.elemEnds[len(pr.elemEnds)-1])) - - return pr -} - -// NumElems returns the number of elements in section k. -func (pr *PkgDecoder) NumElems(k RelocKind) int { - count := int(pr.elemEndsEnds[k]) - if k > 0 { - count -= int(pr.elemEndsEnds[k-1]) - } - return count -} - -// TotalElems returns the total number of elements across all sections. -func (pr *PkgDecoder) TotalElems() int { - return len(pr.elemEnds) -} - -// Fingerprint returns the package fingerprint. -func (pr *PkgDecoder) Fingerprint() [8]byte { - var fp [8]byte - copy(fp[:], pr.elemData[len(pr.elemData)-8:]) - return fp -} - -// AbsIdx returns the absolute index for the given (section, index) -// pair. -func (pr *PkgDecoder) AbsIdx(k RelocKind, idx Index) int { - absIdx := int(idx) - if k > 0 { - absIdx += int(pr.elemEndsEnds[k-1]) - } - if absIdx >= int(pr.elemEndsEnds[k]) { - errorf("%v:%v is out of bounds; %v", k, idx, pr.elemEndsEnds) - } - return absIdx -} - -// DataIdx returns the raw element bitstream for the given (section, -// index) pair. -func (pr *PkgDecoder) DataIdx(k RelocKind, idx Index) string { - absIdx := pr.AbsIdx(k, idx) - - var start uint32 - if absIdx > 0 { - start = pr.elemEnds[absIdx-1] - } - end := pr.elemEnds[absIdx] - - return pr.elemData[start:end] -} - -// StringIdx returns the string value for the given string index. -func (pr *PkgDecoder) StringIdx(idx Index) string { - return pr.DataIdx(RelocString, idx) -} - -// NewDecoder returns a Decoder for the given (section, index) pair, -// and decodes the given SyncMarker from the element bitstream. -func (pr *PkgDecoder) NewDecoder(k RelocKind, idx Index, marker SyncMarker) Decoder { - r := pr.NewDecoderRaw(k, idx) - r.Sync(marker) - return r -} - -// TempDecoder returns a Decoder for the given (section, index) pair, -// and decodes the given SyncMarker from the element bitstream. -// If possible the Decoder should be RetireDecoder'd when it is no longer -// needed, this will avoid heap allocations. -func (pr *PkgDecoder) TempDecoder(k RelocKind, idx Index, marker SyncMarker) Decoder { - r := pr.TempDecoderRaw(k, idx) - r.Sync(marker) - return r -} - -func (pr *PkgDecoder) RetireDecoder(d *Decoder) { - pr.scratchRelocEnt = d.Relocs - d.Relocs = nil -} - -// NewDecoderRaw returns a Decoder for the given (section, index) pair. -// -// Most callers should use NewDecoder instead. -func (pr *PkgDecoder) NewDecoderRaw(k RelocKind, idx Index) Decoder { - r := Decoder{ - common: pr, - k: k, - Idx: idx, - } - - // TODO(mdempsky) r.data.Reset(...) after #44505 is resolved. - r.Data = *strings.NewReader(pr.DataIdx(k, idx)) - - r.Sync(SyncRelocs) - r.Relocs = make([]RelocEnt, r.Len()) - for i := range r.Relocs { - r.Sync(SyncReloc) - r.Relocs[i] = RelocEnt{RelocKind(r.Len()), Index(r.Len())} - } - - return r -} - -func (pr *PkgDecoder) TempDecoderRaw(k RelocKind, idx Index) Decoder { - r := Decoder{ - common: pr, - k: k, - Idx: idx, - } - - r.Data.Reset(pr.DataIdx(k, idx)) - r.Sync(SyncRelocs) - l := r.Len() - if cap(pr.scratchRelocEnt) >= l { - r.Relocs = pr.scratchRelocEnt[:l] - pr.scratchRelocEnt = nil - } else { - r.Relocs = make([]RelocEnt, l) - } - for i := range r.Relocs { - r.Sync(SyncReloc) - r.Relocs[i] = RelocEnt{RelocKind(r.Len()), Index(r.Len())} - } - - return r -} - -// A Decoder provides methods for decoding an individual element's -// bitstream data. -type Decoder struct { - common *PkgDecoder - - Relocs []RelocEnt - Data strings.Reader - - k RelocKind - Idx Index -} - -func (r *Decoder) checkErr(err error) { - if err != nil { - errorf("unexpected decoding error: %w", err) - } -} - -func (r *Decoder) rawUvarint() uint64 { - x, err := readUvarint(&r.Data) - r.checkErr(err) - return x -} - -// readUvarint is a type-specialized copy of encoding/binary.ReadUvarint. -// This avoids the interface conversion and thus has better escape properties, -// which flows up the stack. -func readUvarint(r *strings.Reader) (uint64, error) { - var x uint64 - var s uint - for i := 0; i < binary.MaxVarintLen64; i++ { - b, err := r.ReadByte() - if err != nil { - if i > 0 && err == io.EOF { - err = io.ErrUnexpectedEOF - } - return x, err - } - if b < 0x80 { - if i == binary.MaxVarintLen64-1 && b > 1 { - return x, overflow - } - return x | uint64(b)<> 1) - if ux&1 != 0 { - x = ^x - } - return x -} - -func (r *Decoder) rawReloc(k RelocKind, idx int) Index { - e := r.Relocs[idx] - assert(e.Kind == k) - return e.Idx -} - -// Sync decodes a sync marker from the element bitstream and asserts -// that it matches the expected marker. -// -// If r.common.sync is false, then Sync is a no-op. -func (r *Decoder) Sync(mWant SyncMarker) { - if !r.common.sync { - return - } - - pos, _ := r.Data.Seek(0, io.SeekCurrent) - mHave := SyncMarker(r.rawUvarint()) - writerPCs := make([]int, r.rawUvarint()) - for i := range writerPCs { - writerPCs[i] = int(r.rawUvarint()) - } - - if mHave == mWant { - return - } - - // There's some tension here between printing: - // - // (1) full file paths that tools can recognize (e.g., so emacs - // hyperlinks the "file:line" text for easy navigation), or - // - // (2) short file paths that are easier for humans to read (e.g., by - // omitting redundant or irrelevant details, so it's easier to - // focus on the useful bits that remain). - // - // The current formatting favors the former, as it seems more - // helpful in practice. But perhaps the formatting could be improved - // to better address both concerns. For example, use relative file - // paths if they would be shorter, or rewrite file paths to contain - // "$GOROOT" (like objabi.AbsFile does) if tools can be taught how - // to reliably expand that again. - - fmt.Printf("export data desync: package %q, section %v, index %v, offset %v\n", r.common.pkgPath, r.k, r.Idx, pos) - - fmt.Printf("\nfound %v, written at:\n", mHave) - if len(writerPCs) == 0 { - fmt.Printf("\t[stack trace unavailable; recompile package %q with -d=syncframes]\n", r.common.pkgPath) - } - for _, pc := range writerPCs { - fmt.Printf("\t%s\n", r.common.StringIdx(r.rawReloc(RelocString, pc))) - } - - fmt.Printf("\nexpected %v, reading at:\n", mWant) - var readerPCs [32]uintptr // TODO(mdempsky): Dynamically size? - n := runtime.Callers(2, readerPCs[:]) - for _, pc := range fmtFrames(readerPCs[:n]...) { - fmt.Printf("\t%s\n", pc) - } - - // We already printed a stack trace for the reader, so now we can - // simply exit. Printing a second one with panic or base.Fatalf - // would just be noise. - os.Exit(1) -} - -// Bool decodes and returns a bool value from the element bitstream. -func (r *Decoder) Bool() bool { - r.Sync(SyncBool) - x, err := r.Data.ReadByte() - r.checkErr(err) - assert(x < 2) - return x != 0 -} - -// Int64 decodes and returns an int64 value from the element bitstream. -func (r *Decoder) Int64() int64 { - r.Sync(SyncInt64) - return r.rawVarint() -} - -// Uint64 decodes and returns a uint64 value from the element bitstream. -func (r *Decoder) Uint64() uint64 { - r.Sync(SyncUint64) - return r.rawUvarint() -} - -// Len decodes and returns a non-negative int value from the element bitstream. -func (r *Decoder) Len() int { x := r.Uint64(); v := int(x); assert(uint64(v) == x); return v } - -// Int decodes and returns an int value from the element bitstream. -func (r *Decoder) Int() int { x := r.Int64(); v := int(x); assert(int64(v) == x); return v } - -// Uint decodes and returns a uint value from the element bitstream. -func (r *Decoder) Uint() uint { x := r.Uint64(); v := uint(x); assert(uint64(v) == x); return v } - -// Code decodes a Code value from the element bitstream and returns -// its ordinal value. It's the caller's responsibility to convert the -// result to an appropriate Code type. -// -// TODO(mdempsky): Ideally this method would have signature "Code[T -// Code] T" instead, but we don't allow generic methods and the -// compiler can't depend on generics yet anyway. -func (r *Decoder) Code(mark SyncMarker) int { - r.Sync(mark) - return r.Len() -} - -// Reloc decodes a relocation of expected section k from the element -// bitstream and returns an index to the referenced element. -func (r *Decoder) Reloc(k RelocKind) Index { - r.Sync(SyncUseReloc) - return r.rawReloc(k, r.Len()) -} - -// String decodes and returns a string value from the element -// bitstream. -func (r *Decoder) String() string { - r.Sync(SyncString) - return r.common.StringIdx(r.Reloc(RelocString)) -} - -// Strings decodes and returns a variable-length slice of strings from -// the element bitstream. -func (r *Decoder) Strings() []string { - res := make([]string, r.Len()) - for i := range res { - res[i] = r.String() - } - return res -} - -// Value decodes and returns a constant.Value from the element -// bitstream. -func (r *Decoder) Value() constant.Value { - r.Sync(SyncValue) - isComplex := r.Bool() - val := r.scalar() - if isComplex { - val = constant.BinaryOp(val, token.ADD, constant.MakeImag(r.scalar())) - } - return val -} - -func (r *Decoder) scalar() constant.Value { - switch tag := CodeVal(r.Code(SyncVal)); tag { - default: - panic(fmt.Errorf("unexpected scalar tag: %v", tag)) - - case ValBool: - return constant.MakeBool(r.Bool()) - case ValString: - return constant.MakeString(r.String()) - case ValInt64: - return constant.MakeInt64(r.Int64()) - case ValBigInt: - return constant.Make(r.bigInt()) - case ValBigRat: - num := r.bigInt() - denom := r.bigInt() - return constant.Make(new(big.Rat).SetFrac(num, denom)) - case ValBigFloat: - return constant.Make(r.bigFloat()) - } -} - -func (r *Decoder) bigInt() *big.Int { - v := new(big.Int).SetBytes([]byte(r.String())) - if r.Bool() { - v.Neg(v) - } - return v -} - -func (r *Decoder) bigFloat() *big.Float { - v := new(big.Float).SetPrec(512) - assert(v.UnmarshalText([]byte(r.String())) == nil) - return v -} - -// @@@ Helpers - -// TODO(mdempsky): These should probably be removed. I think they're a -// smell that the export data format is not yet quite right. - -// PeekPkgPath returns the package path for the specified package -// index. -func (pr *PkgDecoder) PeekPkgPath(idx Index) string { - var path string - { - r := pr.TempDecoder(RelocPkg, idx, SyncPkgDef) - path = r.String() - pr.RetireDecoder(&r) - } - if path == "" { - path = pr.pkgPath - } - return path -} - -// PeekObj returns the package path, object name, and CodeObj for the -// specified object index. -func (pr *PkgDecoder) PeekObj(idx Index) (string, string, CodeObj) { - var ridx Index - var name string - var rcode int - { - r := pr.TempDecoder(RelocName, idx, SyncObject1) - r.Sync(SyncSym) - r.Sync(SyncPkg) - ridx = r.Reloc(RelocPkg) - name = r.String() - rcode = r.Code(SyncCodeObj) - pr.RetireDecoder(&r) - } - - path := pr.PeekPkgPath(ridx) - assert(name != "") - - tag := CodeObj(rcode) - - return path, name, tag -} diff --git a/vendor/golang.org/x/tools/internal/pkgbits/doc.go b/vendor/golang.org/x/tools/internal/pkgbits/doc.go deleted file mode 100644 index c8a2796b5e4..00000000000 --- a/vendor/golang.org/x/tools/internal/pkgbits/doc.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package pkgbits implements low-level coding abstractions for -// Unified IR's export data format. -// -// At a low-level, a package is a collection of bitstream elements. -// Each element has a "kind" and a dense, non-negative index. -// Elements can be randomly accessed given their kind and index. -// -// Individual elements are sequences of variable-length values (e.g., -// integers, booleans, strings, go/constant values, cross-references -// to other elements). Package pkgbits provides APIs for encoding and -// decoding these low-level values, but the details of mapping -// higher-level Go constructs into elements is left to higher-level -// abstractions. -// -// Elements may cross-reference each other with "relocations." For -// example, an element representing a pointer type has a relocation -// referring to the element type. -// -// Go constructs may be composed as a constellation of multiple -// elements. For example, a declared function may have one element to -// describe the object (e.g., its name, type, position), and a -// separate element to describe its function body. This allows readers -// some flexibility in efficiently seeking or re-reading data (e.g., -// inlining requires re-reading the function body for each inlined -// call, without needing to re-read the object-level details). -// -// This is a copy of internal/pkgbits in the Go implementation. -package pkgbits diff --git a/vendor/golang.org/x/tools/internal/pkgbits/encoder.go b/vendor/golang.org/x/tools/internal/pkgbits/encoder.go deleted file mode 100644 index 6482617a4fc..00000000000 --- a/vendor/golang.org/x/tools/internal/pkgbits/encoder.go +++ /dev/null @@ -1,383 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package pkgbits - -import ( - "bytes" - "crypto/md5" - "encoding/binary" - "go/constant" - "io" - "math/big" - "runtime" -) - -// currentVersion is the current version number. -// -// - v0: initial prototype -// -// - v1: adds the flags uint32 word -const currentVersion uint32 = 1 - -// A PkgEncoder provides methods for encoding a package's Unified IR -// export data. -type PkgEncoder struct { - // elems holds the bitstream for previously encoded elements. - elems [numRelocs][]string - - // stringsIdx maps previously encoded strings to their index within - // the RelocString section, to allow deduplication. That is, - // elems[RelocString][stringsIdx[s]] == s (if present). - stringsIdx map[string]Index - - // syncFrames is the number of frames to write at each sync - // marker. A negative value means sync markers are omitted. - syncFrames int -} - -// SyncMarkers reports whether pw uses sync markers. -func (pw *PkgEncoder) SyncMarkers() bool { return pw.syncFrames >= 0 } - -// NewPkgEncoder returns an initialized PkgEncoder. -// -// syncFrames is the number of caller frames that should be serialized -// at Sync points. Serializing additional frames results in larger -// export data files, but can help diagnosing desync errors in -// higher-level Unified IR reader/writer code. If syncFrames is -// negative, then sync markers are omitted entirely. -func NewPkgEncoder(syncFrames int) PkgEncoder { - return PkgEncoder{ - stringsIdx: make(map[string]Index), - syncFrames: syncFrames, - } -} - -// DumpTo writes the package's encoded data to out0 and returns the -// package fingerprint. -func (pw *PkgEncoder) DumpTo(out0 io.Writer) (fingerprint [8]byte) { - h := md5.New() - out := io.MultiWriter(out0, h) - - writeUint32 := func(x uint32) { - assert(binary.Write(out, binary.LittleEndian, x) == nil) - } - - writeUint32(currentVersion) - - var flags uint32 - if pw.SyncMarkers() { - flags |= flagSyncMarkers - } - writeUint32(flags) - - // Write elemEndsEnds. - var sum uint32 - for _, elems := range &pw.elems { - sum += uint32(len(elems)) - writeUint32(sum) - } - - // Write elemEnds. - sum = 0 - for _, elems := range &pw.elems { - for _, elem := range elems { - sum += uint32(len(elem)) - writeUint32(sum) - } - } - - // Write elemData. - for _, elems := range &pw.elems { - for _, elem := range elems { - _, err := io.WriteString(out, elem) - assert(err == nil) - } - } - - // Write fingerprint. - copy(fingerprint[:], h.Sum(nil)) - _, err := out0.Write(fingerprint[:]) - assert(err == nil) - - return -} - -// StringIdx adds a string value to the strings section, if not -// already present, and returns its index. -func (pw *PkgEncoder) StringIdx(s string) Index { - if idx, ok := pw.stringsIdx[s]; ok { - assert(pw.elems[RelocString][idx] == s) - return idx - } - - idx := Index(len(pw.elems[RelocString])) - pw.elems[RelocString] = append(pw.elems[RelocString], s) - pw.stringsIdx[s] = idx - return idx -} - -// NewEncoder returns an Encoder for a new element within the given -// section, and encodes the given SyncMarker as the start of the -// element bitstream. -func (pw *PkgEncoder) NewEncoder(k RelocKind, marker SyncMarker) Encoder { - e := pw.NewEncoderRaw(k) - e.Sync(marker) - return e -} - -// NewEncoderRaw returns an Encoder for a new element within the given -// section. -// -// Most callers should use NewEncoder instead. -func (pw *PkgEncoder) NewEncoderRaw(k RelocKind) Encoder { - idx := Index(len(pw.elems[k])) - pw.elems[k] = append(pw.elems[k], "") // placeholder - - return Encoder{ - p: pw, - k: k, - Idx: idx, - } -} - -// An Encoder provides methods for encoding an individual element's -// bitstream data. -type Encoder struct { - p *PkgEncoder - - Relocs []RelocEnt - RelocMap map[RelocEnt]uint32 - Data bytes.Buffer // accumulated element bitstream data - - encodingRelocHeader bool - - k RelocKind - Idx Index // index within relocation section -} - -// Flush finalizes the element's bitstream and returns its Index. -func (w *Encoder) Flush() Index { - var sb bytes.Buffer // TODO(mdempsky): strings.Builder after #44505 is resolved - - // Backup the data so we write the relocations at the front. - var tmp bytes.Buffer - io.Copy(&tmp, &w.Data) - - // TODO(mdempsky): Consider writing these out separately so they're - // easier to strip, along with function bodies, so that we can prune - // down to just the data that's relevant to go/types. - if w.encodingRelocHeader { - panic("encodingRelocHeader already true; recursive flush?") - } - w.encodingRelocHeader = true - w.Sync(SyncRelocs) - w.Len(len(w.Relocs)) - for _, rEnt := range w.Relocs { - w.Sync(SyncReloc) - w.Len(int(rEnt.Kind)) - w.Len(int(rEnt.Idx)) - } - - io.Copy(&sb, &w.Data) - io.Copy(&sb, &tmp) - w.p.elems[w.k][w.Idx] = sb.String() - - return w.Idx -} - -func (w *Encoder) checkErr(err error) { - if err != nil { - errorf("unexpected encoding error: %v", err) - } -} - -func (w *Encoder) rawUvarint(x uint64) { - var buf [binary.MaxVarintLen64]byte - n := binary.PutUvarint(buf[:], x) - _, err := w.Data.Write(buf[:n]) - w.checkErr(err) -} - -func (w *Encoder) rawVarint(x int64) { - // Zig-zag encode. - ux := uint64(x) << 1 - if x < 0 { - ux = ^ux - } - - w.rawUvarint(ux) -} - -func (w *Encoder) rawReloc(r RelocKind, idx Index) int { - e := RelocEnt{r, idx} - if w.RelocMap != nil { - if i, ok := w.RelocMap[e]; ok { - return int(i) - } - } else { - w.RelocMap = make(map[RelocEnt]uint32) - } - - i := len(w.Relocs) - w.RelocMap[e] = uint32(i) - w.Relocs = append(w.Relocs, e) - return i -} - -func (w *Encoder) Sync(m SyncMarker) { - if !w.p.SyncMarkers() { - return - } - - // Writing out stack frame string references requires working - // relocations, but writing out the relocations themselves involves - // sync markers. To prevent infinite recursion, we simply trim the - // stack frame for sync markers within the relocation header. - var frames []string - if !w.encodingRelocHeader && w.p.syncFrames > 0 { - pcs := make([]uintptr, w.p.syncFrames) - n := runtime.Callers(2, pcs) - frames = fmtFrames(pcs[:n]...) - } - - // TODO(mdempsky): Save space by writing out stack frames as a - // linked list so we can share common stack frames. - w.rawUvarint(uint64(m)) - w.rawUvarint(uint64(len(frames))) - for _, frame := range frames { - w.rawUvarint(uint64(w.rawReloc(RelocString, w.p.StringIdx(frame)))) - } -} - -// Bool encodes and writes a bool value into the element bitstream, -// and then returns the bool value. -// -// For simple, 2-alternative encodings, the idiomatic way to call Bool -// is something like: -// -// if w.Bool(x != 0) { -// // alternative #1 -// } else { -// // alternative #2 -// } -// -// For multi-alternative encodings, use Code instead. -func (w *Encoder) Bool(b bool) bool { - w.Sync(SyncBool) - var x byte - if b { - x = 1 - } - err := w.Data.WriteByte(x) - w.checkErr(err) - return b -} - -// Int64 encodes and writes an int64 value into the element bitstream. -func (w *Encoder) Int64(x int64) { - w.Sync(SyncInt64) - w.rawVarint(x) -} - -// Uint64 encodes and writes a uint64 value into the element bitstream. -func (w *Encoder) Uint64(x uint64) { - w.Sync(SyncUint64) - w.rawUvarint(x) -} - -// Len encodes and writes a non-negative int value into the element bitstream. -func (w *Encoder) Len(x int) { assert(x >= 0); w.Uint64(uint64(x)) } - -// Int encodes and writes an int value into the element bitstream. -func (w *Encoder) Int(x int) { w.Int64(int64(x)) } - -// Uint encodes and writes a uint value into the element bitstream. -func (w *Encoder) Uint(x uint) { w.Uint64(uint64(x)) } - -// Reloc encodes and writes a relocation for the given (section, -// index) pair into the element bitstream. -// -// Note: Only the index is formally written into the element -// bitstream, so bitstream decoders must know from context which -// section an encoded relocation refers to. -func (w *Encoder) Reloc(r RelocKind, idx Index) { - w.Sync(SyncUseReloc) - w.Len(w.rawReloc(r, idx)) -} - -// Code encodes and writes a Code value into the element bitstream. -func (w *Encoder) Code(c Code) { - w.Sync(c.Marker()) - w.Len(c.Value()) -} - -// String encodes and writes a string value into the element -// bitstream. -// -// Internally, strings are deduplicated by adding them to the strings -// section (if not already present), and then writing a relocation -// into the element bitstream. -func (w *Encoder) String(s string) { - w.Sync(SyncString) - w.Reloc(RelocString, w.p.StringIdx(s)) -} - -// Strings encodes and writes a variable-length slice of strings into -// the element bitstream. -func (w *Encoder) Strings(ss []string) { - w.Len(len(ss)) - for _, s := range ss { - w.String(s) - } -} - -// Value encodes and writes a constant.Value into the element -// bitstream. -func (w *Encoder) Value(val constant.Value) { - w.Sync(SyncValue) - if w.Bool(val.Kind() == constant.Complex) { - w.scalar(constant.Real(val)) - w.scalar(constant.Imag(val)) - } else { - w.scalar(val) - } -} - -func (w *Encoder) scalar(val constant.Value) { - switch v := constant.Val(val).(type) { - default: - errorf("unhandled %v (%v)", val, val.Kind()) - case bool: - w.Code(ValBool) - w.Bool(v) - case string: - w.Code(ValString) - w.String(v) - case int64: - w.Code(ValInt64) - w.Int64(v) - case *big.Int: - w.Code(ValBigInt) - w.bigInt(v) - case *big.Rat: - w.Code(ValBigRat) - w.bigInt(v.Num()) - w.bigInt(v.Denom()) - case *big.Float: - w.Code(ValBigFloat) - w.bigFloat(v) - } -} - -func (w *Encoder) bigInt(v *big.Int) { - b := v.Bytes() - w.String(string(b)) // TODO: More efficient encoding. - w.Bool(v.Sign() < 0) -} - -func (w *Encoder) bigFloat(v *big.Float) { - b := v.Append(nil, 'p', -1) - w.String(string(b)) // TODO: More efficient encoding. -} diff --git a/vendor/golang.org/x/tools/internal/pkgbits/flags.go b/vendor/golang.org/x/tools/internal/pkgbits/flags.go deleted file mode 100644 index 654222745fa..00000000000 --- a/vendor/golang.org/x/tools/internal/pkgbits/flags.go +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package pkgbits - -const ( - flagSyncMarkers = 1 << iota // file format contains sync markers -) diff --git a/vendor/golang.org/x/tools/internal/pkgbits/frames_go1.go b/vendor/golang.org/x/tools/internal/pkgbits/frames_go1.go deleted file mode 100644 index 5294f6a63ed..00000000000 --- a/vendor/golang.org/x/tools/internal/pkgbits/frames_go1.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !go1.7 -// +build !go1.7 - -// TODO(mdempsky): Remove after #44505 is resolved - -package pkgbits - -import "runtime" - -func walkFrames(pcs []uintptr, visit frameVisitor) { - for _, pc := range pcs { - fn := runtime.FuncForPC(pc) - file, line := fn.FileLine(pc) - - visit(file, line, fn.Name(), pc-fn.Entry()) - } -} diff --git a/vendor/golang.org/x/tools/internal/pkgbits/frames_go17.go b/vendor/golang.org/x/tools/internal/pkgbits/frames_go17.go deleted file mode 100644 index 2324ae7adfe..00000000000 --- a/vendor/golang.org/x/tools/internal/pkgbits/frames_go17.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build go1.7 -// +build go1.7 - -package pkgbits - -import "runtime" - -// walkFrames calls visit for each call frame represented by pcs. -// -// pcs should be a slice of PCs, as returned by runtime.Callers. -func walkFrames(pcs []uintptr, visit frameVisitor) { - if len(pcs) == 0 { - return - } - - frames := runtime.CallersFrames(pcs) - for { - frame, more := frames.Next() - visit(frame.File, frame.Line, frame.Function, frame.PC-frame.Entry) - if !more { - return - } - } -} diff --git a/vendor/golang.org/x/tools/internal/pkgbits/reloc.go b/vendor/golang.org/x/tools/internal/pkgbits/reloc.go deleted file mode 100644 index fcdfb97ca99..00000000000 --- a/vendor/golang.org/x/tools/internal/pkgbits/reloc.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package pkgbits - -// A RelocKind indicates a particular section within a unified IR export. -type RelocKind int32 - -// An Index represents a bitstream element index within a particular -// section. -type Index int32 - -// A relocEnt (relocation entry) is an entry in an element's local -// reference table. -// -// TODO(mdempsky): Rename this too. -type RelocEnt struct { - Kind RelocKind - Idx Index -} - -// Reserved indices within the meta relocation section. -const ( - PublicRootIdx Index = 0 - PrivateRootIdx Index = 1 -) - -const ( - RelocString RelocKind = iota - RelocMeta - RelocPosBase - RelocPkg - RelocName - RelocType - RelocObj - RelocObjExt - RelocObjDict - RelocBody - - numRelocs = iota -) diff --git a/vendor/golang.org/x/tools/internal/pkgbits/support.go b/vendor/golang.org/x/tools/internal/pkgbits/support.go deleted file mode 100644 index ad26d3b28ca..00000000000 --- a/vendor/golang.org/x/tools/internal/pkgbits/support.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package pkgbits - -import "fmt" - -func assert(b bool) { - if !b { - panic("assertion failed") - } -} - -func errorf(format string, args ...interface{}) { - panic(fmt.Errorf(format, args...)) -} diff --git a/vendor/golang.org/x/tools/internal/pkgbits/sync.go b/vendor/golang.org/x/tools/internal/pkgbits/sync.go deleted file mode 100644 index 5bd51ef7170..00000000000 --- a/vendor/golang.org/x/tools/internal/pkgbits/sync.go +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package pkgbits - -import ( - "fmt" - "strings" -) - -// fmtFrames formats a backtrace for reporting reader/writer desyncs. -func fmtFrames(pcs ...uintptr) []string { - res := make([]string, 0, len(pcs)) - walkFrames(pcs, func(file string, line int, name string, offset uintptr) { - // Trim package from function name. It's just redundant noise. - name = strings.TrimPrefix(name, "cmd/compile/internal/noder.") - - res = append(res, fmt.Sprintf("%s:%v: %s +0x%v", file, line, name, offset)) - }) - return res -} - -type frameVisitor func(file string, line int, name string, offset uintptr) - -// SyncMarker is an enum type that represents markers that may be -// written to export data to ensure the reader and writer stay -// synchronized. -type SyncMarker int - -//go:generate stringer -type=SyncMarker -trimprefix=Sync - -const ( - _ SyncMarker = iota - - // Public markers (known to go/types importers). - - // Low-level coding markers. - SyncEOF - SyncBool - SyncInt64 - SyncUint64 - SyncString - SyncValue - SyncVal - SyncRelocs - SyncReloc - SyncUseReloc - - // Higher-level object and type markers. - SyncPublic - SyncPos - SyncPosBase - SyncObject - SyncObject1 - SyncPkg - SyncPkgDef - SyncMethod - SyncType - SyncTypeIdx - SyncTypeParamNames - SyncSignature - SyncParams - SyncParam - SyncCodeObj - SyncSym - SyncLocalIdent - SyncSelector - - // Private markers (only known to cmd/compile). - SyncPrivate - - SyncFuncExt - SyncVarExt - SyncTypeExt - SyncPragma - - SyncExprList - SyncExprs - SyncExpr - SyncExprType - SyncAssign - SyncOp - SyncFuncLit - SyncCompLit - - SyncDecl - SyncFuncBody - SyncOpenScope - SyncCloseScope - SyncCloseAnotherScope - SyncDeclNames - SyncDeclName - - SyncStmts - SyncBlockStmt - SyncIfStmt - SyncForStmt - SyncSwitchStmt - SyncRangeStmt - SyncCaseClause - SyncCommClause - SyncSelectStmt - SyncDecls - SyncLabeledStmt - SyncUseObjLocal - SyncAddLocal - SyncLinkname - SyncStmt1 - SyncStmtsEnd - SyncLabel - SyncOptLabel -) diff --git a/vendor/golang.org/x/tools/internal/pkgbits/syncmarker_string.go b/vendor/golang.org/x/tools/internal/pkgbits/syncmarker_string.go deleted file mode 100644 index 4a5b0ca5f2f..00000000000 --- a/vendor/golang.org/x/tools/internal/pkgbits/syncmarker_string.go +++ /dev/null @@ -1,89 +0,0 @@ -// Code generated by "stringer -type=SyncMarker -trimprefix=Sync"; DO NOT EDIT. - -package pkgbits - -import "strconv" - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[SyncEOF-1] - _ = x[SyncBool-2] - _ = x[SyncInt64-3] - _ = x[SyncUint64-4] - _ = x[SyncString-5] - _ = x[SyncValue-6] - _ = x[SyncVal-7] - _ = x[SyncRelocs-8] - _ = x[SyncReloc-9] - _ = x[SyncUseReloc-10] - _ = x[SyncPublic-11] - _ = x[SyncPos-12] - _ = x[SyncPosBase-13] - _ = x[SyncObject-14] - _ = x[SyncObject1-15] - _ = x[SyncPkg-16] - _ = x[SyncPkgDef-17] - _ = x[SyncMethod-18] - _ = x[SyncType-19] - _ = x[SyncTypeIdx-20] - _ = x[SyncTypeParamNames-21] - _ = x[SyncSignature-22] - _ = x[SyncParams-23] - _ = x[SyncParam-24] - _ = x[SyncCodeObj-25] - _ = x[SyncSym-26] - _ = x[SyncLocalIdent-27] - _ = x[SyncSelector-28] - _ = x[SyncPrivate-29] - _ = x[SyncFuncExt-30] - _ = x[SyncVarExt-31] - _ = x[SyncTypeExt-32] - _ = x[SyncPragma-33] - _ = x[SyncExprList-34] - _ = x[SyncExprs-35] - _ = x[SyncExpr-36] - _ = x[SyncExprType-37] - _ = x[SyncAssign-38] - _ = x[SyncOp-39] - _ = x[SyncFuncLit-40] - _ = x[SyncCompLit-41] - _ = x[SyncDecl-42] - _ = x[SyncFuncBody-43] - _ = x[SyncOpenScope-44] - _ = x[SyncCloseScope-45] - _ = x[SyncCloseAnotherScope-46] - _ = x[SyncDeclNames-47] - _ = x[SyncDeclName-48] - _ = x[SyncStmts-49] - _ = x[SyncBlockStmt-50] - _ = x[SyncIfStmt-51] - _ = x[SyncForStmt-52] - _ = x[SyncSwitchStmt-53] - _ = x[SyncRangeStmt-54] - _ = x[SyncCaseClause-55] - _ = x[SyncCommClause-56] - _ = x[SyncSelectStmt-57] - _ = x[SyncDecls-58] - _ = x[SyncLabeledStmt-59] - _ = x[SyncUseObjLocal-60] - _ = x[SyncAddLocal-61] - _ = x[SyncLinkname-62] - _ = x[SyncStmt1-63] - _ = x[SyncStmtsEnd-64] - _ = x[SyncLabel-65] - _ = x[SyncOptLabel-66] -} - -const _SyncMarker_name = "EOFBoolInt64Uint64StringValueValRelocsRelocUseRelocPublicPosPosBaseObjectObject1PkgPkgDefMethodTypeTypeIdxTypeParamNamesSignatureParamsParamCodeObjSymLocalIdentSelectorPrivateFuncExtVarExtTypeExtPragmaExprListExprsExprExprTypeAssignOpFuncLitCompLitDeclFuncBodyOpenScopeCloseScopeCloseAnotherScopeDeclNamesDeclNameStmtsBlockStmtIfStmtForStmtSwitchStmtRangeStmtCaseClauseCommClauseSelectStmtDeclsLabeledStmtUseObjLocalAddLocalLinknameStmt1StmtsEndLabelOptLabel" - -var _SyncMarker_index = [...]uint16{0, 3, 7, 12, 18, 24, 29, 32, 38, 43, 51, 57, 60, 67, 73, 80, 83, 89, 95, 99, 106, 120, 129, 135, 140, 147, 150, 160, 168, 175, 182, 188, 195, 201, 209, 214, 218, 226, 232, 234, 241, 248, 252, 260, 269, 279, 296, 305, 313, 318, 327, 333, 340, 350, 359, 369, 379, 389, 394, 405, 416, 424, 432, 437, 445, 450, 458} - -func (i SyncMarker) String() string { - i -= 1 - if i < 0 || i >= SyncMarker(len(_SyncMarker_index)-1) { - return "SyncMarker(" + strconv.FormatInt(int64(i+1), 10) + ")" - } - return _SyncMarker_name[_SyncMarker_index[i]:_SyncMarker_index[i+1]] -} diff --git a/vendor/golang.org/x/tools/internal/tokeninternal/tokeninternal.go b/vendor/golang.org/x/tools/internal/tokeninternal/tokeninternal.go deleted file mode 100644 index a3fb2d4f29d..00000000000 --- a/vendor/golang.org/x/tools/internal/tokeninternal/tokeninternal.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// package tokeninternal provides access to some internal features of the token -// package. -package tokeninternal - -import ( - "go/token" - "sync" - "unsafe" -) - -// GetLines returns the table of line-start offsets from a token.File. -func GetLines(file *token.File) []int { - // token.File has a Lines method on Go 1.21 and later. - if file, ok := (interface{})(file).(interface{ Lines() []int }); ok { - return file.Lines() - } - - // This declaration must match that of token.File. - // This creates a risk of dependency skew. - // For now we check that the size of the two - // declarations is the same, on the (fragile) assumption - // that future changes would add fields. - type tokenFile119 struct { - _ string - _ int - _ int - mu sync.Mutex // we're not complete monsters - lines []int - _ []struct{} - } - type tokenFile118 struct { - _ *token.FileSet // deleted in go1.19 - tokenFile119 - } - - type uP = unsafe.Pointer - switch unsafe.Sizeof(*file) { - case unsafe.Sizeof(tokenFile118{}): - var ptr *tokenFile118 - *(*uP)(uP(&ptr)) = uP(file) - ptr.mu.Lock() - defer ptr.mu.Unlock() - return ptr.lines - - case unsafe.Sizeof(tokenFile119{}): - var ptr *tokenFile119 - *(*uP)(uP(&ptr)) = uP(file) - ptr.mu.Lock() - defer ptr.mu.Unlock() - return ptr.lines - - default: - panic("unexpected token.File size") - } -} diff --git a/vendor/golang.org/x/tools/internal/typeparams/common.go b/vendor/golang.org/x/tools/internal/typeparams/common.go deleted file mode 100644 index 25a1426d30e..00000000000 --- a/vendor/golang.org/x/tools/internal/typeparams/common.go +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package typeparams contains common utilities for writing tools that interact -// with generic Go code, as introduced with Go 1.18. -// -// Many of the types and functions in this package are proxies for the new APIs -// introduced in the standard library with Go 1.18. For example, the -// typeparams.Union type is an alias for go/types.Union, and the ForTypeSpec -// function returns the value of the go/ast.TypeSpec.TypeParams field. At Go -// versions older than 1.18 these helpers are implemented as stubs, allowing -// users of this package to write code that handles generic constructs inline, -// even if the Go version being used to compile does not support generics. -// -// Additionally, this package contains common utilities for working with the -// new generic constructs, to supplement the standard library APIs. Notably, -// the StructuralTerms API computes a minimal representation of the structural -// restrictions on a type parameter. -// -// An external version of these APIs is available in the -// golang.org/x/exp/typeparams module. -package typeparams - -import ( - "go/ast" - "go/token" - "go/types" -) - -// UnpackIndexExpr extracts data from AST nodes that represent index -// expressions. -// -// For an ast.IndexExpr, the resulting indices slice will contain exactly one -// index expression. For an ast.IndexListExpr (go1.18+), it may have a variable -// number of index expressions. -// -// For nodes that don't represent index expressions, the first return value of -// UnpackIndexExpr will be nil. -func UnpackIndexExpr(n ast.Node) (x ast.Expr, lbrack token.Pos, indices []ast.Expr, rbrack token.Pos) { - switch e := n.(type) { - case *ast.IndexExpr: - return e.X, e.Lbrack, []ast.Expr{e.Index}, e.Rbrack - case *IndexListExpr: - return e.X, e.Lbrack, e.Indices, e.Rbrack - } - return nil, token.NoPos, nil, token.NoPos -} - -// PackIndexExpr returns an *ast.IndexExpr or *ast.IndexListExpr, depending on -// the cardinality of indices. Calling PackIndexExpr with len(indices) == 0 -// will panic. -func PackIndexExpr(x ast.Expr, lbrack token.Pos, indices []ast.Expr, rbrack token.Pos) ast.Expr { - switch len(indices) { - case 0: - panic("empty indices") - case 1: - return &ast.IndexExpr{ - X: x, - Lbrack: lbrack, - Index: indices[0], - Rbrack: rbrack, - } - default: - return &IndexListExpr{ - X: x, - Lbrack: lbrack, - Indices: indices, - Rbrack: rbrack, - } - } -} - -// IsTypeParam reports whether t is a type parameter. -func IsTypeParam(t types.Type) bool { - _, ok := t.(*TypeParam) - return ok -} - -// OriginMethod returns the origin method associated with the method fn. -// For methods on a non-generic receiver base type, this is just -// fn. However, for methods with a generic receiver, OriginMethod returns the -// corresponding method in the method set of the origin type. -// -// As a special case, if fn is not a method (has no receiver), OriginMethod -// returns fn. -func OriginMethod(fn *types.Func) *types.Func { - recv := fn.Type().(*types.Signature).Recv() - if recv == nil { - - return fn - } - base := recv.Type() - p, isPtr := base.(*types.Pointer) - if isPtr { - base = p.Elem() - } - named, isNamed := base.(*types.Named) - if !isNamed { - // Receiver is a *types.Interface. - return fn - } - if ForNamed(named).Len() == 0 { - // Receiver base has no type parameters, so we can avoid the lookup below. - return fn - } - orig := NamedTypeOrigin(named) - gfn, _, _ := types.LookupFieldOrMethod(orig, true, fn.Pkg(), fn.Name()) - return gfn.(*types.Func) -} - -// GenericAssignableTo is a generalization of types.AssignableTo that -// implements the following rule for uninstantiated generic types: -// -// If V and T are generic named types, then V is considered assignable to T if, -// for every possible instantation of V[A_1, ..., A_N], the instantiation -// T[A_1, ..., A_N] is valid and V[A_1, ..., A_N] implements T[A_1, ..., A_N]. -// -// If T has structural constraints, they must be satisfied by V. -// -// For example, consider the following type declarations: -// -// type Interface[T any] interface { -// Accept(T) -// } -// -// type Container[T any] struct { -// Element T -// } -// -// func (c Container[T]) Accept(t T) { c.Element = t } -// -// In this case, GenericAssignableTo reports that instantiations of Container -// are assignable to the corresponding instantiation of Interface. -func GenericAssignableTo(ctxt *Context, V, T types.Type) bool { - // If V and T are not both named, or do not have matching non-empty type - // parameter lists, fall back on types.AssignableTo. - - VN, Vnamed := V.(*types.Named) - TN, Tnamed := T.(*types.Named) - if !Vnamed || !Tnamed { - return types.AssignableTo(V, T) - } - - vtparams := ForNamed(VN) - ttparams := ForNamed(TN) - if vtparams.Len() == 0 || vtparams.Len() != ttparams.Len() || NamedTypeArgs(VN).Len() != 0 || NamedTypeArgs(TN).Len() != 0 { - return types.AssignableTo(V, T) - } - - // V and T have the same (non-zero) number of type params. Instantiate both - // with the type parameters of V. This must always succeed for V, and will - // succeed for T if and only if the type set of each type parameter of V is a - // subset of the type set of the corresponding type parameter of T, meaning - // that every instantiation of V corresponds to a valid instantiation of T. - - // Minor optimization: ensure we share a context across the two - // instantiations below. - if ctxt == nil { - ctxt = NewContext() - } - - var targs []types.Type - for i := 0; i < vtparams.Len(); i++ { - targs = append(targs, vtparams.At(i)) - } - - vinst, err := Instantiate(ctxt, V, targs, true) - if err != nil { - panic("type parameters should satisfy their own constraints") - } - - tinst, err := Instantiate(ctxt, T, targs, true) - if err != nil { - return false - } - - return types.AssignableTo(vinst, tinst) -} diff --git a/vendor/golang.org/x/tools/internal/typeparams/coretype.go b/vendor/golang.org/x/tools/internal/typeparams/coretype.go deleted file mode 100644 index 993135ec90e..00000000000 --- a/vendor/golang.org/x/tools/internal/typeparams/coretype.go +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package typeparams - -import ( - "go/types" -) - -// CoreType returns the core type of T or nil if T does not have a core type. -// -// See https://go.dev/ref/spec#Core_types for the definition of a core type. -func CoreType(T types.Type) types.Type { - U := T.Underlying() - if _, ok := U.(*types.Interface); !ok { - return U // for non-interface types, - } - - terms, err := _NormalTerms(U) - if len(terms) == 0 || err != nil { - // len(terms) -> empty type set of interface. - // err != nil => U is invalid, exceeds complexity bounds, or has an empty type set. - return nil // no core type. - } - - U = terms[0].Type().Underlying() - var identical int // i in [0,identical) => Identical(U, terms[i].Type().Underlying()) - for identical = 1; identical < len(terms); identical++ { - if !types.Identical(U, terms[identical].Type().Underlying()) { - break - } - } - - if identical == len(terms) { - // https://go.dev/ref/spec#Core_types - // "There is a single type U which is the underlying type of all types in the type set of T" - return U - } - ch, ok := U.(*types.Chan) - if !ok { - return nil // no core type as identical < len(terms) and U is not a channel. - } - // https://go.dev/ref/spec#Core_types - // "the type chan E if T contains only bidirectional channels, or the type chan<- E or - // <-chan E depending on the direction of the directional channels present." - for chans := identical; chans < len(terms); chans++ { - curr, ok := terms[chans].Type().Underlying().(*types.Chan) - if !ok { - return nil - } - if !types.Identical(ch.Elem(), curr.Elem()) { - return nil // channel elements are not identical. - } - if ch.Dir() == types.SendRecv { - // ch is bidirectional. We can safely always use curr's direction. - ch = curr - } else if curr.Dir() != types.SendRecv && ch.Dir() != curr.Dir() { - // ch and curr are not bidirectional and not the same direction. - return nil - } - } - return ch -} - -// _NormalTerms returns a slice of terms representing the normalized structural -// type restrictions of a type, if any. -// -// For all types other than *types.TypeParam, *types.Interface, and -// *types.Union, this is just a single term with Tilde() == false and -// Type() == typ. For *types.TypeParam, *types.Interface, and *types.Union, see -// below. -// -// Structural type restrictions of a type parameter are created via -// non-interface types embedded in its constraint interface (directly, or via a -// chain of interface embeddings). For example, in the declaration type -// T[P interface{~int; m()}] int the structural restriction of the type -// parameter P is ~int. -// -// With interface embedding and unions, the specification of structural type -// restrictions may be arbitrarily complex. For example, consider the -// following: -// -// type A interface{ ~string|~[]byte } -// -// type B interface{ int|string } -// -// type C interface { ~string|~int } -// -// type T[P interface{ A|B; C }] int -// -// In this example, the structural type restriction of P is ~string|int: A|B -// expands to ~string|~[]byte|int|string, which reduces to ~string|~[]byte|int, -// which when intersected with C (~string|~int) yields ~string|int. -// -// _NormalTerms computes these expansions and reductions, producing a -// "normalized" form of the embeddings. A structural restriction is normalized -// if it is a single union containing no interface terms, and is minimal in the -// sense that removing any term changes the set of types satisfying the -// constraint. It is left as a proof for the reader that, modulo sorting, there -// is exactly one such normalized form. -// -// Because the minimal representation always takes this form, _NormalTerms -// returns a slice of tilde terms corresponding to the terms of the union in -// the normalized structural restriction. An error is returned if the type is -// invalid, exceeds complexity bounds, or has an empty type set. In the latter -// case, _NormalTerms returns ErrEmptyTypeSet. -// -// _NormalTerms makes no guarantees about the order of terms, except that it -// is deterministic. -func _NormalTerms(typ types.Type) ([]*Term, error) { - switch typ := typ.(type) { - case *TypeParam: - return StructuralTerms(typ) - case *Union: - return UnionTermSet(typ) - case *types.Interface: - return InterfaceTermSet(typ) - default: - return []*Term{NewTerm(false, typ)}, nil - } -} diff --git a/vendor/golang.org/x/tools/internal/typeparams/enabled_go117.go b/vendor/golang.org/x/tools/internal/typeparams/enabled_go117.go deleted file mode 100644 index 18212390e19..00000000000 --- a/vendor/golang.org/x/tools/internal/typeparams/enabled_go117.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !go1.18 -// +build !go1.18 - -package typeparams - -// Enabled reports whether type parameters are enabled in the current build -// environment. -const Enabled = false diff --git a/vendor/golang.org/x/tools/internal/typeparams/enabled_go118.go b/vendor/golang.org/x/tools/internal/typeparams/enabled_go118.go deleted file mode 100644 index d67148823c4..00000000000 --- a/vendor/golang.org/x/tools/internal/typeparams/enabled_go118.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build go1.18 -// +build go1.18 - -package typeparams - -// Note: this constant is in a separate file as this is the only acceptable -// diff between the <1.18 API of this package and the 1.18 API. - -// Enabled reports whether type parameters are enabled in the current build -// environment. -const Enabled = true diff --git a/vendor/golang.org/x/tools/internal/typeparams/normalize.go b/vendor/golang.org/x/tools/internal/typeparams/normalize.go deleted file mode 100644 index 9c631b6512d..00000000000 --- a/vendor/golang.org/x/tools/internal/typeparams/normalize.go +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package typeparams - -import ( - "errors" - "fmt" - "go/types" - "os" - "strings" -) - -//go:generate go run copytermlist.go - -const debug = false - -var ErrEmptyTypeSet = errors.New("empty type set") - -// StructuralTerms returns a slice of terms representing the normalized -// structural type restrictions of a type parameter, if any. -// -// Structural type restrictions of a type parameter are created via -// non-interface types embedded in its constraint interface (directly, or via a -// chain of interface embeddings). For example, in the declaration -// -// type T[P interface{~int; m()}] int -// -// the structural restriction of the type parameter P is ~int. -// -// With interface embedding and unions, the specification of structural type -// restrictions may be arbitrarily complex. For example, consider the -// following: -// -// type A interface{ ~string|~[]byte } -// -// type B interface{ int|string } -// -// type C interface { ~string|~int } -// -// type T[P interface{ A|B; C }] int -// -// In this example, the structural type restriction of P is ~string|int: A|B -// expands to ~string|~[]byte|int|string, which reduces to ~string|~[]byte|int, -// which when intersected with C (~string|~int) yields ~string|int. -// -// StructuralTerms computes these expansions and reductions, producing a -// "normalized" form of the embeddings. A structural restriction is normalized -// if it is a single union containing no interface terms, and is minimal in the -// sense that removing any term changes the set of types satisfying the -// constraint. It is left as a proof for the reader that, modulo sorting, there -// is exactly one such normalized form. -// -// Because the minimal representation always takes this form, StructuralTerms -// returns a slice of tilde terms corresponding to the terms of the union in -// the normalized structural restriction. An error is returned if the -// constraint interface is invalid, exceeds complexity bounds, or has an empty -// type set. In the latter case, StructuralTerms returns ErrEmptyTypeSet. -// -// StructuralTerms makes no guarantees about the order of terms, except that it -// is deterministic. -func StructuralTerms(tparam *TypeParam) ([]*Term, error) { - constraint := tparam.Constraint() - if constraint == nil { - return nil, fmt.Errorf("%s has nil constraint", tparam) - } - iface, _ := constraint.Underlying().(*types.Interface) - if iface == nil { - return nil, fmt.Errorf("constraint is %T, not *types.Interface", constraint.Underlying()) - } - return InterfaceTermSet(iface) -} - -// InterfaceTermSet computes the normalized terms for a constraint interface, -// returning an error if the term set cannot be computed or is empty. In the -// latter case, the error will be ErrEmptyTypeSet. -// -// See the documentation of StructuralTerms for more information on -// normalization. -func InterfaceTermSet(iface *types.Interface) ([]*Term, error) { - return computeTermSet(iface) -} - -// UnionTermSet computes the normalized terms for a union, returning an error -// if the term set cannot be computed or is empty. In the latter case, the -// error will be ErrEmptyTypeSet. -// -// See the documentation of StructuralTerms for more information on -// normalization. -func UnionTermSet(union *Union) ([]*Term, error) { - return computeTermSet(union) -} - -func computeTermSet(typ types.Type) ([]*Term, error) { - tset, err := computeTermSetInternal(typ, make(map[types.Type]*termSet), 0) - if err != nil { - return nil, err - } - if tset.terms.isEmpty() { - return nil, ErrEmptyTypeSet - } - if tset.terms.isAll() { - return nil, nil - } - var terms []*Term - for _, term := range tset.terms { - terms = append(terms, NewTerm(term.tilde, term.typ)) - } - return terms, nil -} - -// A termSet holds the normalized set of terms for a given type. -// -// The name termSet is intentionally distinct from 'type set': a type set is -// all types that implement a type (and includes method restrictions), whereas -// a term set just represents the structural restrictions on a type. -type termSet struct { - complete bool - terms termlist -} - -func indentf(depth int, format string, args ...interface{}) { - fmt.Fprintf(os.Stderr, strings.Repeat(".", depth)+format+"\n", args...) -} - -func computeTermSetInternal(t types.Type, seen map[types.Type]*termSet, depth int) (res *termSet, err error) { - if t == nil { - panic("nil type") - } - - if debug { - indentf(depth, "%s", t.String()) - defer func() { - if err != nil { - indentf(depth, "=> %s", err) - } else { - indentf(depth, "=> %s", res.terms.String()) - } - }() - } - - const maxTermCount = 100 - if tset, ok := seen[t]; ok { - if !tset.complete { - return nil, fmt.Errorf("cycle detected in the declaration of %s", t) - } - return tset, nil - } - - // Mark the current type as seen to avoid infinite recursion. - tset := new(termSet) - defer func() { - tset.complete = true - }() - seen[t] = tset - - switch u := t.Underlying().(type) { - case *types.Interface: - // The term set of an interface is the intersection of the term sets of its - // embedded types. - tset.terms = allTermlist - for i := 0; i < u.NumEmbeddeds(); i++ { - embedded := u.EmbeddedType(i) - if _, ok := embedded.Underlying().(*TypeParam); ok { - return nil, fmt.Errorf("invalid embedded type %T", embedded) - } - tset2, err := computeTermSetInternal(embedded, seen, depth+1) - if err != nil { - return nil, err - } - tset.terms = tset.terms.intersect(tset2.terms) - } - case *Union: - // The term set of a union is the union of term sets of its terms. - tset.terms = nil - for i := 0; i < u.Len(); i++ { - t := u.Term(i) - var terms termlist - switch t.Type().Underlying().(type) { - case *types.Interface: - tset2, err := computeTermSetInternal(t.Type(), seen, depth+1) - if err != nil { - return nil, err - } - terms = tset2.terms - case *TypeParam, *Union: - // A stand-alone type parameter or union is not permitted as union - // term. - return nil, fmt.Errorf("invalid union term %T", t) - default: - if t.Type() == types.Typ[types.Invalid] { - continue - } - terms = termlist{{t.Tilde(), t.Type()}} - } - tset.terms = tset.terms.union(terms) - if len(tset.terms) > maxTermCount { - return nil, fmt.Errorf("exceeded max term count %d", maxTermCount) - } - } - case *TypeParam: - panic("unreachable") - default: - // For all other types, the term set is just a single non-tilde term - // holding the type itself. - if u != types.Typ[types.Invalid] { - tset.terms = termlist{{false, t}} - } - } - return tset, nil -} - -// under is a facade for the go/types internal function of the same name. It is -// used by typeterm.go. -func under(t types.Type) types.Type { - return t.Underlying() -} diff --git a/vendor/golang.org/x/tools/internal/typeparams/termlist.go b/vendor/golang.org/x/tools/internal/typeparams/termlist.go deleted file mode 100644 index 933106a23dd..00000000000 --- a/vendor/golang.org/x/tools/internal/typeparams/termlist.go +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Code generated by copytermlist.go DO NOT EDIT. - -package typeparams - -import ( - "bytes" - "go/types" -) - -// A termlist represents the type set represented by the union -// t1 ∪ y2 ∪ ... tn of the type sets of the terms t1 to tn. -// A termlist is in normal form if all terms are disjoint. -// termlist operations don't require the operands to be in -// normal form. -type termlist []*term - -// allTermlist represents the set of all types. -// It is in normal form. -var allTermlist = termlist{new(term)} - -// String prints the termlist exactly (without normalization). -func (xl termlist) String() string { - if len(xl) == 0 { - return "∅" - } - var buf bytes.Buffer - for i, x := range xl { - if i > 0 { - buf.WriteString(" ∪ ") - } - buf.WriteString(x.String()) - } - return buf.String() -} - -// isEmpty reports whether the termlist xl represents the empty set of types. -func (xl termlist) isEmpty() bool { - // If there's a non-nil term, the entire list is not empty. - // If the termlist is in normal form, this requires at most - // one iteration. - for _, x := range xl { - if x != nil { - return false - } - } - return true -} - -// isAll reports whether the termlist xl represents the set of all types. -func (xl termlist) isAll() bool { - // If there's a 𝓤 term, the entire list is 𝓤. - // If the termlist is in normal form, this requires at most - // one iteration. - for _, x := range xl { - if x != nil && x.typ == nil { - return true - } - } - return false -} - -// norm returns the normal form of xl. -func (xl termlist) norm() termlist { - // Quadratic algorithm, but good enough for now. - // TODO(gri) fix asymptotic performance - used := make([]bool, len(xl)) - var rl termlist - for i, xi := range xl { - if xi == nil || used[i] { - continue - } - for j := i + 1; j < len(xl); j++ { - xj := xl[j] - if xj == nil || used[j] { - continue - } - if u1, u2 := xi.union(xj); u2 == nil { - // If we encounter a 𝓤 term, the entire list is 𝓤. - // Exit early. - // (Note that this is not just an optimization; - // if we continue, we may end up with a 𝓤 term - // and other terms and the result would not be - // in normal form.) - if u1.typ == nil { - return allTermlist - } - xi = u1 - used[j] = true // xj is now unioned into xi - ignore it in future iterations - } - } - rl = append(rl, xi) - } - return rl -} - -// union returns the union xl ∪ yl. -func (xl termlist) union(yl termlist) termlist { - return append(xl, yl...).norm() -} - -// intersect returns the intersection xl ∩ yl. -func (xl termlist) intersect(yl termlist) termlist { - if xl.isEmpty() || yl.isEmpty() { - return nil - } - - // Quadratic algorithm, but good enough for now. - // TODO(gri) fix asymptotic performance - var rl termlist - for _, x := range xl { - for _, y := range yl { - if r := x.intersect(y); r != nil { - rl = append(rl, r) - } - } - } - return rl.norm() -} - -// equal reports whether xl and yl represent the same type set. -func (xl termlist) equal(yl termlist) bool { - // TODO(gri) this should be more efficient - return xl.subsetOf(yl) && yl.subsetOf(xl) -} - -// includes reports whether t ∈ xl. -func (xl termlist) includes(t types.Type) bool { - for _, x := range xl { - if x.includes(t) { - return true - } - } - return false -} - -// supersetOf reports whether y ⊆ xl. -func (xl termlist) supersetOf(y *term) bool { - for _, x := range xl { - if y.subsetOf(x) { - return true - } - } - return false -} - -// subsetOf reports whether xl ⊆ yl. -func (xl termlist) subsetOf(yl termlist) bool { - if yl.isEmpty() { - return xl.isEmpty() - } - - // each term x of xl must be a subset of yl - for _, x := range xl { - if !yl.supersetOf(x) { - return false // x is not a subset yl - } - } - return true -} diff --git a/vendor/golang.org/x/tools/internal/typeparams/typeparams_go117.go b/vendor/golang.org/x/tools/internal/typeparams/typeparams_go117.go deleted file mode 100644 index b4788978ff4..00000000000 --- a/vendor/golang.org/x/tools/internal/typeparams/typeparams_go117.go +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !go1.18 -// +build !go1.18 - -package typeparams - -import ( - "go/ast" - "go/token" - "go/types" -) - -func unsupported() { - panic("type parameters are unsupported at this go version") -} - -// IndexListExpr is a placeholder type, as type parameters are not supported at -// this Go version. Its methods panic on use. -type IndexListExpr struct { - ast.Expr - X ast.Expr // expression - Lbrack token.Pos // position of "[" - Indices []ast.Expr // index expressions - Rbrack token.Pos // position of "]" -} - -// ForTypeSpec returns an empty field list, as type parameters on not supported -// at this Go version. -func ForTypeSpec(*ast.TypeSpec) *ast.FieldList { - return nil -} - -// ForFuncType returns an empty field list, as type parameters are not -// supported at this Go version. -func ForFuncType(*ast.FuncType) *ast.FieldList { - return nil -} - -// TypeParam is a placeholder type, as type parameters are not supported at -// this Go version. Its methods panic on use. -type TypeParam struct{ types.Type } - -func (*TypeParam) Index() int { unsupported(); return 0 } -func (*TypeParam) Constraint() types.Type { unsupported(); return nil } -func (*TypeParam) Obj() *types.TypeName { unsupported(); return nil } - -// TypeParamList is a placeholder for an empty type parameter list. -type TypeParamList struct{} - -func (*TypeParamList) Len() int { return 0 } -func (*TypeParamList) At(int) *TypeParam { unsupported(); return nil } - -// TypeList is a placeholder for an empty type list. -type TypeList struct{} - -func (*TypeList) Len() int { return 0 } -func (*TypeList) At(int) types.Type { unsupported(); return nil } - -// NewTypeParam is unsupported at this Go version, and panics. -func NewTypeParam(name *types.TypeName, constraint types.Type) *TypeParam { - unsupported() - return nil -} - -// SetTypeParamConstraint is unsupported at this Go version, and panics. -func SetTypeParamConstraint(tparam *TypeParam, constraint types.Type) { - unsupported() -} - -// NewSignatureType calls types.NewSignature, panicking if recvTypeParams or -// typeParams is non-empty. -func NewSignatureType(recv *types.Var, recvTypeParams, typeParams []*TypeParam, params, results *types.Tuple, variadic bool) *types.Signature { - if len(recvTypeParams) != 0 || len(typeParams) != 0 { - panic("signatures cannot have type parameters at this Go version") - } - return types.NewSignature(recv, params, results, variadic) -} - -// ForSignature returns an empty slice. -func ForSignature(*types.Signature) *TypeParamList { - return nil -} - -// RecvTypeParams returns a nil slice. -func RecvTypeParams(sig *types.Signature) *TypeParamList { - return nil -} - -// IsComparable returns false, as no interfaces are type-restricted at this Go -// version. -func IsComparable(*types.Interface) bool { - return false -} - -// IsMethodSet returns true, as no interfaces are type-restricted at this Go -// version. -func IsMethodSet(*types.Interface) bool { - return true -} - -// IsImplicit returns false, as no interfaces are implicit at this Go version. -func IsImplicit(*types.Interface) bool { - return false -} - -// MarkImplicit does nothing, because this Go version does not have implicit -// interfaces. -func MarkImplicit(*types.Interface) {} - -// ForNamed returns an empty type parameter list, as type parameters are not -// supported at this Go version. -func ForNamed(*types.Named) *TypeParamList { - return nil -} - -// SetForNamed panics if tparams is non-empty. -func SetForNamed(_ *types.Named, tparams []*TypeParam) { - if len(tparams) > 0 { - unsupported() - } -} - -// NamedTypeArgs returns nil. -func NamedTypeArgs(*types.Named) *TypeList { - return nil -} - -// NamedTypeOrigin is the identity method at this Go version. -func NamedTypeOrigin(named *types.Named) types.Type { - return named -} - -// Term holds information about a structural type restriction. -type Term struct { - tilde bool - typ types.Type -} - -func (m *Term) Tilde() bool { return m.tilde } -func (m *Term) Type() types.Type { return m.typ } -func (m *Term) String() string { - pre := "" - if m.tilde { - pre = "~" - } - return pre + m.typ.String() -} - -// NewTerm is unsupported at this Go version, and panics. -func NewTerm(tilde bool, typ types.Type) *Term { - return &Term{tilde, typ} -} - -// Union is a placeholder type, as type parameters are not supported at this Go -// version. Its methods panic on use. -type Union struct{ types.Type } - -func (*Union) Len() int { return 0 } -func (*Union) Term(i int) *Term { unsupported(); return nil } - -// NewUnion is unsupported at this Go version, and panics. -func NewUnion(terms []*Term) *Union { - unsupported() - return nil -} - -// InitInstanceInfo is a noop at this Go version. -func InitInstanceInfo(*types.Info) {} - -// Instance is a placeholder type, as type parameters are not supported at this -// Go version. -type Instance struct { - TypeArgs *TypeList - Type types.Type -} - -// GetInstances returns a nil map, as type parameters are not supported at this -// Go version. -func GetInstances(info *types.Info) map[*ast.Ident]Instance { return nil } - -// Context is a placeholder type, as type parameters are not supported at -// this Go version. -type Context struct{} - -// NewContext returns a placeholder Context instance. -func NewContext() *Context { - return &Context{} -} - -// Instantiate is unsupported on this Go version, and panics. -func Instantiate(ctxt *Context, typ types.Type, targs []types.Type, validate bool) (types.Type, error) { - unsupported() - return nil, nil -} diff --git a/vendor/golang.org/x/tools/internal/typeparams/typeparams_go118.go b/vendor/golang.org/x/tools/internal/typeparams/typeparams_go118.go deleted file mode 100644 index 114a36b866b..00000000000 --- a/vendor/golang.org/x/tools/internal/typeparams/typeparams_go118.go +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build go1.18 -// +build go1.18 - -package typeparams - -import ( - "go/ast" - "go/types" -) - -// IndexListExpr is an alias for ast.IndexListExpr. -type IndexListExpr = ast.IndexListExpr - -// ForTypeSpec returns n.TypeParams. -func ForTypeSpec(n *ast.TypeSpec) *ast.FieldList { - if n == nil { - return nil - } - return n.TypeParams -} - -// ForFuncType returns n.TypeParams. -func ForFuncType(n *ast.FuncType) *ast.FieldList { - if n == nil { - return nil - } - return n.TypeParams -} - -// TypeParam is an alias for types.TypeParam -type TypeParam = types.TypeParam - -// TypeParamList is an alias for types.TypeParamList -type TypeParamList = types.TypeParamList - -// TypeList is an alias for types.TypeList -type TypeList = types.TypeList - -// NewTypeParam calls types.NewTypeParam. -func NewTypeParam(name *types.TypeName, constraint types.Type) *TypeParam { - return types.NewTypeParam(name, constraint) -} - -// SetTypeParamConstraint calls tparam.SetConstraint(constraint). -func SetTypeParamConstraint(tparam *TypeParam, constraint types.Type) { - tparam.SetConstraint(constraint) -} - -// NewSignatureType calls types.NewSignatureType. -func NewSignatureType(recv *types.Var, recvTypeParams, typeParams []*TypeParam, params, results *types.Tuple, variadic bool) *types.Signature { - return types.NewSignatureType(recv, recvTypeParams, typeParams, params, results, variadic) -} - -// ForSignature returns sig.TypeParams() -func ForSignature(sig *types.Signature) *TypeParamList { - return sig.TypeParams() -} - -// RecvTypeParams returns sig.RecvTypeParams(). -func RecvTypeParams(sig *types.Signature) *TypeParamList { - return sig.RecvTypeParams() -} - -// IsComparable calls iface.IsComparable(). -func IsComparable(iface *types.Interface) bool { - return iface.IsComparable() -} - -// IsMethodSet calls iface.IsMethodSet(). -func IsMethodSet(iface *types.Interface) bool { - return iface.IsMethodSet() -} - -// IsImplicit calls iface.IsImplicit(). -func IsImplicit(iface *types.Interface) bool { - return iface.IsImplicit() -} - -// MarkImplicit calls iface.MarkImplicit(). -func MarkImplicit(iface *types.Interface) { - iface.MarkImplicit() -} - -// ForNamed extracts the (possibly empty) type parameter object list from -// named. -func ForNamed(named *types.Named) *TypeParamList { - return named.TypeParams() -} - -// SetForNamed sets the type params tparams on n. Each tparam must be of -// dynamic type *types.TypeParam. -func SetForNamed(n *types.Named, tparams []*TypeParam) { - n.SetTypeParams(tparams) -} - -// NamedTypeArgs returns named.TypeArgs(). -func NamedTypeArgs(named *types.Named) *TypeList { - return named.TypeArgs() -} - -// NamedTypeOrigin returns named.Orig(). -func NamedTypeOrigin(named *types.Named) types.Type { - return named.Origin() -} - -// Term is an alias for types.Term. -type Term = types.Term - -// NewTerm calls types.NewTerm. -func NewTerm(tilde bool, typ types.Type) *Term { - return types.NewTerm(tilde, typ) -} - -// Union is an alias for types.Union -type Union = types.Union - -// NewUnion calls types.NewUnion. -func NewUnion(terms []*Term) *Union { - return types.NewUnion(terms) -} - -// InitInstanceInfo initializes info to record information about type and -// function instances. -func InitInstanceInfo(info *types.Info) { - info.Instances = make(map[*ast.Ident]types.Instance) -} - -// Instance is an alias for types.Instance. -type Instance = types.Instance - -// GetInstances returns info.Instances. -func GetInstances(info *types.Info) map[*ast.Ident]Instance { - return info.Instances -} - -// Context is an alias for types.Context. -type Context = types.Context - -// NewContext calls types.NewContext. -func NewContext() *Context { - return types.NewContext() -} - -// Instantiate calls types.Instantiate. -func Instantiate(ctxt *Context, typ types.Type, targs []types.Type, validate bool) (types.Type, error) { - return types.Instantiate(ctxt, typ, targs, validate) -} diff --git a/vendor/golang.org/x/tools/internal/typeparams/typeterm.go b/vendor/golang.org/x/tools/internal/typeparams/typeterm.go deleted file mode 100644 index 7ddee28d987..00000000000 --- a/vendor/golang.org/x/tools/internal/typeparams/typeterm.go +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Code generated by copytermlist.go DO NOT EDIT. - -package typeparams - -import "go/types" - -// A term describes elementary type sets: -// -// ∅: (*term)(nil) == ∅ // set of no types (empty set) -// 𝓤: &term{} == 𝓤 // set of all types (𝓤niverse) -// T: &term{false, T} == {T} // set of type T -// ~t: &term{true, t} == {t' | under(t') == t} // set of types with underlying type t -// -type term struct { - tilde bool // valid if typ != nil - typ types.Type -} - -func (x *term) String() string { - switch { - case x == nil: - return "∅" - case x.typ == nil: - return "𝓤" - case x.tilde: - return "~" + x.typ.String() - default: - return x.typ.String() - } -} - -// equal reports whether x and y represent the same type set. -func (x *term) equal(y *term) bool { - // easy cases - switch { - case x == nil || y == nil: - return x == y - case x.typ == nil || y.typ == nil: - return x.typ == y.typ - } - // ∅ ⊂ x, y ⊂ 𝓤 - - return x.tilde == y.tilde && types.Identical(x.typ, y.typ) -} - -// union returns the union x ∪ y: zero, one, or two non-nil terms. -func (x *term) union(y *term) (_, _ *term) { - // easy cases - switch { - case x == nil && y == nil: - return nil, nil // ∅ ∪ ∅ == ∅ - case x == nil: - return y, nil // ∅ ∪ y == y - case y == nil: - return x, nil // x ∪ ∅ == x - case x.typ == nil: - return x, nil // 𝓤 ∪ y == 𝓤 - case y.typ == nil: - return y, nil // x ∪ 𝓤 == 𝓤 - } - // ∅ ⊂ x, y ⊂ 𝓤 - - if x.disjoint(y) { - return x, y // x ∪ y == (x, y) if x ∩ y == ∅ - } - // x.typ == y.typ - - // ~t ∪ ~t == ~t - // ~t ∪ T == ~t - // T ∪ ~t == ~t - // T ∪ T == T - if x.tilde || !y.tilde { - return x, nil - } - return y, nil -} - -// intersect returns the intersection x ∩ y. -func (x *term) intersect(y *term) *term { - // easy cases - switch { - case x == nil || y == nil: - return nil // ∅ ∩ y == ∅ and ∩ ∅ == ∅ - case x.typ == nil: - return y // 𝓤 ∩ y == y - case y.typ == nil: - return x // x ∩ 𝓤 == x - } - // ∅ ⊂ x, y ⊂ 𝓤 - - if x.disjoint(y) { - return nil // x ∩ y == ∅ if x ∩ y == ∅ - } - // x.typ == y.typ - - // ~t ∩ ~t == ~t - // ~t ∩ T == T - // T ∩ ~t == T - // T ∩ T == T - if !x.tilde || y.tilde { - return x - } - return y -} - -// includes reports whether t ∈ x. -func (x *term) includes(t types.Type) bool { - // easy cases - switch { - case x == nil: - return false // t ∈ ∅ == false - case x.typ == nil: - return true // t ∈ 𝓤 == true - } - // ∅ ⊂ x ⊂ 𝓤 - - u := t - if x.tilde { - u = under(u) - } - return types.Identical(x.typ, u) -} - -// subsetOf reports whether x ⊆ y. -func (x *term) subsetOf(y *term) bool { - // easy cases - switch { - case x == nil: - return true // ∅ ⊆ y == true - case y == nil: - return false // x ⊆ ∅ == false since x != ∅ - case y.typ == nil: - return true // x ⊆ 𝓤 == true - case x.typ == nil: - return false // 𝓤 ⊆ y == false since y != 𝓤 - } - // ∅ ⊂ x, y ⊂ 𝓤 - - if x.disjoint(y) { - return false // x ⊆ y == false if x ∩ y == ∅ - } - // x.typ == y.typ - - // ~t ⊆ ~t == true - // ~t ⊆ T == false - // T ⊆ ~t == true - // T ⊆ T == true - return !x.tilde || y.tilde -} - -// disjoint reports whether x ∩ y == ∅. -// x.typ and y.typ must not be nil. -func (x *term) disjoint(y *term) bool { - if debug && (x.typ == nil || y.typ == nil) { - panic("invalid argument(s)") - } - ux := x.typ - if y.tilde { - ux = under(ux) - } - uy := y.typ - if x.tilde { - uy = under(uy) - } - return !types.Identical(ux, uy) -} diff --git a/vendor/golang.org/x/mod/LICENSE b/vendor/golang.org/x/xerrors/LICENSE similarity index 96% rename from vendor/golang.org/x/mod/LICENSE rename to vendor/golang.org/x/xerrors/LICENSE index 6a66aea5eaf..e4a47e17f14 100644 --- a/vendor/golang.org/x/mod/LICENSE +++ b/vendor/golang.org/x/xerrors/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2009 The Go Authors. All rights reserved. +Copyright (c) 2019 The Go Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are diff --git a/vendor/golang.org/x/mod/PATENTS b/vendor/golang.org/x/xerrors/PATENTS similarity index 100% rename from vendor/golang.org/x/mod/PATENTS rename to vendor/golang.org/x/xerrors/PATENTS diff --git a/vendor/golang.org/x/xerrors/README b/vendor/golang.org/x/xerrors/README new file mode 100644 index 00000000000..aac7867a560 --- /dev/null +++ b/vendor/golang.org/x/xerrors/README @@ -0,0 +1,2 @@ +This repository holds the transition packages for the new Go 1.13 error values. +See golang.org/design/29934-error-values. diff --git a/vendor/golang.org/x/xerrors/adaptor.go b/vendor/golang.org/x/xerrors/adaptor.go new file mode 100644 index 00000000000..4317f248331 --- /dev/null +++ b/vendor/golang.org/x/xerrors/adaptor.go @@ -0,0 +1,193 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xerrors + +import ( + "bytes" + "fmt" + "io" + "reflect" + "strconv" +) + +// FormatError calls the FormatError method of f with an errors.Printer +// configured according to s and verb, and writes the result to s. +func FormatError(f Formatter, s fmt.State, verb rune) { + // Assuming this function is only called from the Format method, and given + // that FormatError takes precedence over Format, it cannot be called from + // any package that supports errors.Formatter. It is therefore safe to + // disregard that State may be a specific printer implementation and use one + // of our choice instead. + + // limitations: does not support printing error as Go struct. + + var ( + sep = " " // separator before next error + p = &state{State: s} + direct = true + ) + + var err error = f + + switch verb { + // Note that this switch must match the preference order + // for ordinary string printing (%#v before %+v, and so on). + + case 'v': + if s.Flag('#') { + if stringer, ok := err.(fmt.GoStringer); ok { + io.WriteString(&p.buf, stringer.GoString()) + goto exit + } + // proceed as if it were %v + } else if s.Flag('+') { + p.printDetail = true + sep = "\n - " + } + case 's': + case 'q', 'x', 'X': + // Use an intermediate buffer in the rare cases that precision, + // truncation, or one of the alternative verbs (q, x, and X) are + // specified. + direct = false + + default: + p.buf.WriteString("%!") + p.buf.WriteRune(verb) + p.buf.WriteByte('(') + switch { + case err != nil: + p.buf.WriteString(reflect.TypeOf(f).String()) + default: + p.buf.WriteString("") + } + p.buf.WriteByte(')') + io.Copy(s, &p.buf) + return + } + +loop: + for { + switch v := err.(type) { + case Formatter: + err = v.FormatError((*printer)(p)) + case fmt.Formatter: + v.Format(p, 'v') + break loop + default: + io.WriteString(&p.buf, v.Error()) + break loop + } + if err == nil { + break + } + if p.needColon || !p.printDetail { + p.buf.WriteByte(':') + p.needColon = false + } + p.buf.WriteString(sep) + p.inDetail = false + p.needNewline = false + } + +exit: + width, okW := s.Width() + prec, okP := s.Precision() + + if !direct || (okW && width > 0) || okP { + // Construct format string from State s. + format := []byte{'%'} + if s.Flag('-') { + format = append(format, '-') + } + if s.Flag('+') { + format = append(format, '+') + } + if s.Flag(' ') { + format = append(format, ' ') + } + if okW { + format = strconv.AppendInt(format, int64(width), 10) + } + if okP { + format = append(format, '.') + format = strconv.AppendInt(format, int64(prec), 10) + } + format = append(format, string(verb)...) + fmt.Fprintf(s, string(format), p.buf.String()) + } else { + io.Copy(s, &p.buf) + } +} + +var detailSep = []byte("\n ") + +// state tracks error printing state. It implements fmt.State. +type state struct { + fmt.State + buf bytes.Buffer + + printDetail bool + inDetail bool + needColon bool + needNewline bool +} + +func (s *state) Write(b []byte) (n int, err error) { + if s.printDetail { + if len(b) == 0 { + return 0, nil + } + if s.inDetail && s.needColon { + s.needNewline = true + if b[0] == '\n' { + b = b[1:] + } + } + k := 0 + for i, c := range b { + if s.needNewline { + if s.inDetail && s.needColon { + s.buf.WriteByte(':') + s.needColon = false + } + s.buf.Write(detailSep) + s.needNewline = false + } + if c == '\n' { + s.buf.Write(b[k:i]) + k = i + 1 + s.needNewline = true + } + } + s.buf.Write(b[k:]) + if !s.inDetail { + s.needColon = true + } + } else if !s.inDetail { + s.buf.Write(b) + } + return len(b), nil +} + +// printer wraps a state to implement an xerrors.Printer. +type printer state + +func (s *printer) Print(args ...interface{}) { + if !s.inDetail || s.printDetail { + fmt.Fprint((*state)(s), args...) + } +} + +func (s *printer) Printf(format string, args ...interface{}) { + if !s.inDetail || s.printDetail { + fmt.Fprintf((*state)(s), format, args...) + } +} + +func (s *printer) Detail() bool { + s.inDetail = true + return s.printDetail +} diff --git a/vendor/golang.org/x/xerrors/codereview.cfg b/vendor/golang.org/x/xerrors/codereview.cfg new file mode 100644 index 00000000000..3f8b14b64e8 --- /dev/null +++ b/vendor/golang.org/x/xerrors/codereview.cfg @@ -0,0 +1 @@ +issuerepo: golang/go diff --git a/vendor/golang.org/x/xerrors/doc.go b/vendor/golang.org/x/xerrors/doc.go new file mode 100644 index 00000000000..2ef99f5a87b --- /dev/null +++ b/vendor/golang.org/x/xerrors/doc.go @@ -0,0 +1,23 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package xerrors implements functions to manipulate errors. +// +// This package is based on the Go 2 proposal for error values: +// +// https://golang.org/design/29934-error-values +// +// These functions were incorporated into the standard library's errors package +// in Go 1.13: +// - Is +// - As +// - Unwrap +// +// Also, Errorf's %w verb was incorporated into fmt.Errorf. +// +// Use this package to get equivalent behavior in all supported Go versions. +// +// No other features of this package were included in Go 1.13, and at present +// there are no plans to include any of them. +package xerrors // import "golang.org/x/xerrors" diff --git a/vendor/golang.org/x/xerrors/errors.go b/vendor/golang.org/x/xerrors/errors.go new file mode 100644 index 00000000000..e88d3772d86 --- /dev/null +++ b/vendor/golang.org/x/xerrors/errors.go @@ -0,0 +1,33 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xerrors + +import "fmt" + +// errorString is a trivial implementation of error. +type errorString struct { + s string + frame Frame +} + +// New returns an error that formats as the given text. +// +// The returned error contains a Frame set to the caller's location and +// implements Formatter to show this information when printed with details. +func New(text string) error { + return &errorString{text, Caller(1)} +} + +func (e *errorString) Error() string { + return e.s +} + +func (e *errorString) Format(s fmt.State, v rune) { FormatError(e, s, v) } + +func (e *errorString) FormatError(p Printer) (next error) { + p.Print(e.s) + e.frame.Format(p) + return nil +} diff --git a/vendor/golang.org/x/xerrors/fmt.go b/vendor/golang.org/x/xerrors/fmt.go new file mode 100644 index 00000000000..27a5d70bd6e --- /dev/null +++ b/vendor/golang.org/x/xerrors/fmt.go @@ -0,0 +1,190 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xerrors + +import ( + "fmt" + "strings" + "unicode" + "unicode/utf8" + + "golang.org/x/xerrors/internal" +) + +const percentBangString = "%!" + +// Errorf formats according to a format specifier and returns the string as a +// value that satisfies error. +// +// The returned error includes the file and line number of the caller when +// formatted with additional detail enabled. If the last argument is an error +// the returned error's Format method will return it if the format string ends +// with ": %s", ": %v", or ": %w". If the last argument is an error and the +// format string ends with ": %w", the returned error implements an Unwrap +// method returning it. +// +// If the format specifier includes a %w verb with an error operand in a +// position other than at the end, the returned error will still implement an +// Unwrap method returning the operand, but the error's Format method will not +// return the wrapped error. +// +// It is invalid to include more than one %w verb or to supply it with an +// operand that does not implement the error interface. The %w verb is otherwise +// a synonym for %v. +// +// Note that as of Go 1.13, the fmt.Errorf function will do error formatting, +// but it will not capture a stack backtrace. +func Errorf(format string, a ...interface{}) error { + format = formatPlusW(format) + // Support a ": %[wsv]" suffix, which works well with xerrors.Formatter. + wrap := strings.HasSuffix(format, ": %w") + idx, format2, ok := parsePercentW(format) + percentWElsewhere := !wrap && idx >= 0 + if !percentWElsewhere && (wrap || strings.HasSuffix(format, ": %s") || strings.HasSuffix(format, ": %v")) { + err := errorAt(a, len(a)-1) + if err == nil { + return &noWrapError{fmt.Sprintf(format, a...), nil, Caller(1)} + } + // TODO: this is not entirely correct. The error value could be + // printed elsewhere in format if it mixes numbered with unnumbered + // substitutions. With relatively small changes to doPrintf we can + // have it optionally ignore extra arguments and pass the argument + // list in its entirety. + msg := fmt.Sprintf(format[:len(format)-len(": %s")], a[:len(a)-1]...) + frame := Frame{} + if internal.EnableTrace { + frame = Caller(1) + } + if wrap { + return &wrapError{msg, err, frame} + } + return &noWrapError{msg, err, frame} + } + // Support %w anywhere. + // TODO: don't repeat the wrapped error's message when %w occurs in the middle. + msg := fmt.Sprintf(format2, a...) + if idx < 0 { + return &noWrapError{msg, nil, Caller(1)} + } + err := errorAt(a, idx) + if !ok || err == nil { + // Too many %ws or argument of %w is not an error. Approximate the Go + // 1.13 fmt.Errorf message. + return &noWrapError{fmt.Sprintf("%sw(%s)", percentBangString, msg), nil, Caller(1)} + } + frame := Frame{} + if internal.EnableTrace { + frame = Caller(1) + } + return &wrapError{msg, err, frame} +} + +func errorAt(args []interface{}, i int) error { + if i < 0 || i >= len(args) { + return nil + } + err, ok := args[i].(error) + if !ok { + return nil + } + return err +} + +// formatPlusW is used to avoid the vet check that will barf at %w. +func formatPlusW(s string) string { + return s +} + +// Return the index of the only %w in format, or -1 if none. +// Also return a rewritten format string with %w replaced by %v, and +// false if there is more than one %w. +// TODO: handle "%[N]w". +func parsePercentW(format string) (idx int, newFormat string, ok bool) { + // Loosely copied from golang.org/x/tools/go/analysis/passes/printf/printf.go. + idx = -1 + ok = true + n := 0 + sz := 0 + var isW bool + for i := 0; i < len(format); i += sz { + if format[i] != '%' { + sz = 1 + continue + } + // "%%" is not a format directive. + if i+1 < len(format) && format[i+1] == '%' { + sz = 2 + continue + } + sz, isW = parsePrintfVerb(format[i:]) + if isW { + if idx >= 0 { + ok = false + } else { + idx = n + } + // "Replace" the last character, the 'w', with a 'v'. + p := i + sz - 1 + format = format[:p] + "v" + format[p+1:] + } + n++ + } + return idx, format, ok +} + +// Parse the printf verb starting with a % at s[0]. +// Return how many bytes it occupies and whether the verb is 'w'. +func parsePrintfVerb(s string) (int, bool) { + // Assume only that the directive is a sequence of non-letters followed by a single letter. + sz := 0 + var r rune + for i := 1; i < len(s); i += sz { + r, sz = utf8.DecodeRuneInString(s[i:]) + if unicode.IsLetter(r) { + return i + sz, r == 'w' + } + } + return len(s), false +} + +type noWrapError struct { + msg string + err error + frame Frame +} + +func (e *noWrapError) Error() string { + return fmt.Sprint(e) +} + +func (e *noWrapError) Format(s fmt.State, v rune) { FormatError(e, s, v) } + +func (e *noWrapError) FormatError(p Printer) (next error) { + p.Print(e.msg) + e.frame.Format(p) + return e.err +} + +type wrapError struct { + msg string + err error + frame Frame +} + +func (e *wrapError) Error() string { + return fmt.Sprint(e) +} + +func (e *wrapError) Format(s fmt.State, v rune) { FormatError(e, s, v) } + +func (e *wrapError) FormatError(p Printer) (next error) { + p.Print(e.msg) + e.frame.Format(p) + return e.err +} + +func (e *wrapError) Unwrap() error { + return e.err +} diff --git a/vendor/golang.org/x/xerrors/format.go b/vendor/golang.org/x/xerrors/format.go new file mode 100644 index 00000000000..1bc9c26b97f --- /dev/null +++ b/vendor/golang.org/x/xerrors/format.go @@ -0,0 +1,34 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xerrors + +// A Formatter formats error messages. +type Formatter interface { + error + + // FormatError prints the receiver's first error and returns the next error in + // the error chain, if any. + FormatError(p Printer) (next error) +} + +// A Printer formats error messages. +// +// The most common implementation of Printer is the one provided by package fmt +// during Printf (as of Go 1.13). Localization packages such as golang.org/x/text/message +// typically provide their own implementations. +type Printer interface { + // Print appends args to the message output. + Print(args ...interface{}) + + // Printf writes a formatted string. + Printf(format string, args ...interface{}) + + // Detail reports whether error detail is requested. + // After the first call to Detail, all text written to the Printer + // is formatted as additional detail, or ignored when + // detail has not been requested. + // If Detail returns false, the caller can avoid printing the detail at all. + Detail() bool +} diff --git a/vendor/golang.org/x/xerrors/frame.go b/vendor/golang.org/x/xerrors/frame.go new file mode 100644 index 00000000000..0de628ec501 --- /dev/null +++ b/vendor/golang.org/x/xerrors/frame.go @@ -0,0 +1,56 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xerrors + +import ( + "runtime" +) + +// A Frame contains part of a call stack. +type Frame struct { + // Make room for three PCs: the one we were asked for, what it called, + // and possibly a PC for skipPleaseUseCallersFrames. See: + // https://go.googlesource.com/go/+/032678e0fb/src/runtime/extern.go#169 + frames [3]uintptr +} + +// Caller returns a Frame that describes a frame on the caller's stack. +// The argument skip is the number of frames to skip over. +// Caller(0) returns the frame for the caller of Caller. +func Caller(skip int) Frame { + var s Frame + runtime.Callers(skip+1, s.frames[:]) + return s +} + +// location reports the file, line, and function of a frame. +// +// The returned function may be "" even if file and line are not. +func (f Frame) location() (function, file string, line int) { + frames := runtime.CallersFrames(f.frames[:]) + if _, ok := frames.Next(); !ok { + return "", "", 0 + } + fr, ok := frames.Next() + if !ok { + return "", "", 0 + } + return fr.Function, fr.File, fr.Line +} + +// Format prints the stack as error detail. +// It should be called from an error's Format implementation +// after printing any other error detail. +func (f Frame) Format(p Printer) { + if p.Detail() { + function, file, line := f.location() + if function != "" { + p.Printf("%s\n ", function) + } + if file != "" { + p.Printf("%s:%d\n", file, line) + } + } +} diff --git a/vendor/golang.org/x/xerrors/internal/internal.go b/vendor/golang.org/x/xerrors/internal/internal.go new file mode 100644 index 00000000000..89f4eca5df7 --- /dev/null +++ b/vendor/golang.org/x/xerrors/internal/internal.go @@ -0,0 +1,8 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package internal + +// EnableTrace indicates whether stack information should be recorded in errors. +var EnableTrace = true diff --git a/vendor/golang.org/x/xerrors/wrap.go b/vendor/golang.org/x/xerrors/wrap.go new file mode 100644 index 00000000000..9842758ca7c --- /dev/null +++ b/vendor/golang.org/x/xerrors/wrap.go @@ -0,0 +1,112 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xerrors + +import ( + "reflect" +) + +// A Wrapper provides context around another error. +type Wrapper interface { + // Unwrap returns the next error in the error chain. + // If there is no next error, Unwrap returns nil. + Unwrap() error +} + +// Opaque returns an error with the same error formatting as err +// but that does not match err and cannot be unwrapped. +func Opaque(err error) error { + return noWrapper{err} +} + +type noWrapper struct { + error +} + +func (e noWrapper) FormatError(p Printer) (next error) { + if f, ok := e.error.(Formatter); ok { + return f.FormatError(p) + } + p.Print(e.error) + return nil +} + +// Unwrap returns the result of calling the Unwrap method on err, if err implements +// Unwrap. Otherwise, Unwrap returns nil. +// +// Deprecated: As of Go 1.13, use errors.Unwrap instead. +func Unwrap(err error) error { + u, ok := err.(Wrapper) + if !ok { + return nil + } + return u.Unwrap() +} + +// Is reports whether any error in err's chain matches target. +// +// An error is considered to match a target if it is equal to that target or if +// it implements a method Is(error) bool such that Is(target) returns true. +// +// Deprecated: As of Go 1.13, use errors.Is instead. +func Is(err, target error) bool { + if target == nil { + return err == target + } + + isComparable := reflect.TypeOf(target).Comparable() + for { + if isComparable && err == target { + return true + } + if x, ok := err.(interface{ Is(error) bool }); ok && x.Is(target) { + return true + } + // TODO: consider supporing target.Is(err). This would allow + // user-definable predicates, but also may allow for coping with sloppy + // APIs, thereby making it easier to get away with them. + if err = Unwrap(err); err == nil { + return false + } + } +} + +// As finds the first error in err's chain that matches the type to which target +// points, and if so, sets the target to its value and returns true. An error +// matches a type if it is assignable to the target type, or if it has a method +// As(interface{}) bool such that As(target) returns true. As will panic if target +// is not a non-nil pointer to a type which implements error or is of interface type. +// +// The As method should set the target to its value and return true if err +// matches the type to which target points. +// +// Deprecated: As of Go 1.13, use errors.As instead. +func As(err error, target interface{}) bool { + if target == nil { + panic("errors: target cannot be nil") + } + val := reflect.ValueOf(target) + typ := val.Type() + if typ.Kind() != reflect.Ptr || val.IsNil() { + panic("errors: target must be a non-nil pointer") + } + if e := typ.Elem(); e.Kind() != reflect.Interface && !e.Implements(errorType) { + panic("errors: *target must be interface or implement error") + } + targetType := typ.Elem() + for err != nil { + if reflect.TypeOf(err).AssignableTo(targetType) { + val.Elem().Set(reflect.ValueOf(err)) + return true + } + if x, ok := err.(interface{ As(interface{}) bool }); ok && x.As(target) { + return true + } + err = Unwrap(err) + } + return false +} + +var errorType = reflect.TypeOf((*error)(nil)).Elem() diff --git a/vendor/google.golang.org/api/googleapi/googleapi.go b/vendor/google.golang.org/api/googleapi/googleapi.go index d1784f1a349..b328a7976ab 100644 --- a/vendor/google.golang.org/api/googleapi/googleapi.go +++ b/vendor/google.golang.org/api/googleapi/googleapi.go @@ -15,6 +15,7 @@ import ( "net/http" "net/url" "strings" + "time" "google.golang.org/api/internal/third_party/uritemplates" ) @@ -78,6 +79,9 @@ type Error struct { Header http.Header Errors []ErrorItem + // err is typically a wrapped apierror.APIError, see + // google-api-go-client/internal/gensupport/error.go. + err error } // ErrorItem is a detailed error code & message from the Google API frontend. @@ -121,6 +125,15 @@ func (e *Error) Error() string { return buf.String() } +// Wrap allows an existing Error to wrap another error. See also [Error.Unwrap]. +func (e *Error) Wrap(err error) { + e.err = err +} + +func (e *Error) Unwrap() error { + return e.err +} + type errorReply struct { Error *Error `json:"error"` } @@ -140,6 +153,7 @@ func CheckResponse(res *http.Response) error { jerr.Error.Code = res.StatusCode } jerr.Error.Body = string(slurp) + jerr.Error.Header = res.Header return jerr.Error } } @@ -172,8 +186,9 @@ func CheckMediaResponse(res *http.Response) error { } slurp, _ := ioutil.ReadAll(io.LimitReader(res.Body, 1<<20)) return &Error{ - Code: res.StatusCode, - Body: string(slurp), + Code: res.StatusCode, + Body: string(slurp), + Header: res.Header, } } @@ -245,12 +260,30 @@ func ChunkSize(size int) MediaOption { return chunkSizeOption(size) } +type chunkRetryDeadlineOption time.Duration + +func (cd chunkRetryDeadlineOption) setOptions(o *MediaOptions) { + o.ChunkRetryDeadline = time.Duration(cd) +} + +// ChunkRetryDeadline returns a MediaOption which sets a per-chunk retry +// deadline. If a single chunk has been attempting to upload for longer than +// this time and the request fails, it will no longer be retried, and the error +// will be returned to the caller. +// This is only applicable for files which are large enough to require +// a multi-chunk resumable upload. +// The default value is 32s. +// To set a deadline on the entire upload, use context timeout or cancellation. +func ChunkRetryDeadline(deadline time.Duration) MediaOption { + return chunkRetryDeadlineOption(deadline) +} + // MediaOptions stores options for customizing media upload. It is not used by developers directly. type MediaOptions struct { ContentType string ForceEmptyContentType bool - - ChunkSize int + ChunkSize int + ChunkRetryDeadline time.Duration } // ProcessMediaOptions stores options from opts in a MediaOptions. @@ -362,11 +395,11 @@ func ConvertVariant(v map[string]interface{}, dst interface{}) bool { // For example, if your response has a "NextPageToken" and a slice of "Items" with "Id" fields, // you could request just those fields like this: // -// svc.Events.List().Fields("nextPageToken", "items/id").Do() +// svc.Events.List().Fields("nextPageToken", "items/id").Do() // // or if you were also interested in each Item's "Updated" field, you can combine them like this: // -// svc.Events.List().Fields("nextPageToken", "items(id,updated)").Do() +// svc.Events.List().Fields("nextPageToken", "items(id,updated)").Do() // // Another way to find field names is through the Google API explorer: // https://developers.google.com/apis-explorer/#p/ @@ -391,6 +424,14 @@ type CallOption interface { Get() (key, value string) } +// A MultiCallOption is an option argument to an API call and can be passed +// anywhere a CallOption is accepted. It additionally supports returning a slice +// of values for a given key. +type MultiCallOption interface { + CallOption + GetMulti() (key string, value []string) +} + // QuotaUser returns a CallOption that will set the quota user for a call. // The quota user can be used by server-side applications to control accounting. // It can be an arbitrary string up to 40 characters, and will override UserIP @@ -417,4 +458,24 @@ type traceTok string func (t traceTok) Get() (string, string) { return "trace", "token:" + string(t) } +type queryParameter struct { + key string + values []string +} + +// QueryParameter allows setting the value(s) of an arbitrary key. +func QueryParameter(key string, values ...string) CallOption { + return queryParameter{key: key, values: append([]string{}, values...)} +} + +// Get will never actually be called -- GetMulti will. +func (q queryParameter) Get() (string, string) { + return "", "" +} + +// GetMulti returns the key and values values associated to that key. +func (q queryParameter) GetMulti() (string, []string) { + return q.key, q.values +} + // TODO: Fields too diff --git a/vendor/google.golang.org/api/googleapi/transport/apikey.go b/vendor/google.golang.org/api/googleapi/transport/apikey.go index 61720ec2ea1..f5d826c2a19 100644 --- a/vendor/google.golang.org/api/googleapi/transport/apikey.go +++ b/vendor/google.golang.org/api/googleapi/transport/apikey.go @@ -7,7 +7,7 @@ // // This package is DEPRECATED. Users should instead use, // -// service, err := NewService(..., option.WithAPIKey(...)) +// service, err := NewService(..., option.WithAPIKey(...)) package transport import ( diff --git a/vendor/google.golang.org/api/iamcredentials/v1/iamcredentials-api.json b/vendor/google.golang.org/api/iamcredentials/v1/iamcredentials-api.json new file mode 100644 index 00000000000..0c82b86a100 --- /dev/null +++ b/vendor/google.golang.org/api/iamcredentials/v1/iamcredentials-api.json @@ -0,0 +1,372 @@ +{ + "auth": { + "oauth2": { + "scopes": { + "https://www.googleapis.com/auth/cloud-platform": { + "description": "See, edit, configure, and delete your Google Cloud data and see the email address for your Google Account." + } + } + } + }, + "basePath": "", + "baseUrl": "https://iamcredentials.googleapis.com/", + "batchPath": "batch", + "canonicalName": "IAM Credentials", + "description": "Creates short-lived credentials for impersonating IAM service accounts. To enable this API, you must enable the IAM API (iam.googleapis.com). ", + "discoveryVersion": "v1", + "documentationLink": "https://cloud.google.com/iam/docs/creating-short-lived-service-account-credentials", + "fullyEncodeReservedExpansion": true, + "icons": { + "x16": "http://www.google.com/images/icons/product/search-16.gif", + "x32": "http://www.google.com/images/icons/product/search-32.gif" + }, + "id": "iamcredentials:v1", + "kind": "discovery#restDescription", + "mtlsRootUrl": "https://iamcredentials.mtls.googleapis.com/", + "name": "iamcredentials", + "ownerDomain": "google.com", + "ownerName": "Google", + "parameters": { + "$.xgafv": { + "description": "V1 error format.", + "enum": [ + "1", + "2" + ], + "enumDescriptions": [ + "v1 error format", + "v2 error format" + ], + "location": "query", + "type": "string" + }, + "access_token": { + "description": "OAuth access token.", + "location": "query", + "type": "string" + }, + "alt": { + "default": "json", + "description": "Data format for response.", + "enum": [ + "json", + "media", + "proto" + ], + "enumDescriptions": [ + "Responses with Content-Type of application/json", + "Media download with context-dependent Content-Type", + "Responses with Content-Type of application/x-protobuf" + ], + "location": "query", + "type": "string" + }, + "callback": { + "description": "JSONP", + "location": "query", + "type": "string" + }, + "fields": { + "description": "Selector specifying which fields to include in a partial response.", + "location": "query", + "type": "string" + }, + "key": { + "description": "API key. Your API key identifies your project and provides you with API access, quota, and reports. Required unless you provide an OAuth 2.0 token.", + "location": "query", + "type": "string" + }, + "oauth_token": { + "description": "OAuth 2.0 token for the current user.", + "location": "query", + "type": "string" + }, + "prettyPrint": { + "default": "true", + "description": "Returns response with indentations and line breaks.", + "location": "query", + "type": "boolean" + }, + "quotaUser": { + "description": "Available to use for quota purposes for server-side applications. Can be any arbitrary string assigned to a user, but should not exceed 40 characters.", + "location": "query", + "type": "string" + }, + "uploadType": { + "description": "Legacy upload protocol for media (e.g. \"media\", \"multipart\").", + "location": "query", + "type": "string" + }, + "upload_protocol": { + "description": "Upload protocol for media (e.g. \"raw\", \"multipart\").", + "location": "query", + "type": "string" + } + }, + "protocol": "rest", + "resources": { + "projects": { + "resources": { + "serviceAccounts": { + "methods": { + "generateAccessToken": { + "description": "Generates an OAuth 2.0 access token for a service account.", + "flatPath": "v1/projects/{projectsId}/serviceAccounts/{serviceAccountsId}:generateAccessToken", + "httpMethod": "POST", + "id": "iamcredentials.projects.serviceAccounts.generateAccessToken", + "parameterOrder": [ + "name" + ], + "parameters": { + "name": { + "description": "Required. The resource name of the service account for which the credentials are requested, in the following format: `projects/-/serviceAccounts/{ACCOUNT_EMAIL_OR_UNIQUEID}`. The `-` wildcard character is required; replacing it with a project ID is invalid.", + "location": "path", + "pattern": "^projects/[^/]+/serviceAccounts/[^/]+$", + "required": true, + "type": "string" + } + }, + "path": "v1/{+name}:generateAccessToken", + "request": { + "$ref": "GenerateAccessTokenRequest" + }, + "response": { + "$ref": "GenerateAccessTokenResponse" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform" + ] + }, + "generateIdToken": { + "description": "Generates an OpenID Connect ID token for a service account.", + "flatPath": "v1/projects/{projectsId}/serviceAccounts/{serviceAccountsId}:generateIdToken", + "httpMethod": "POST", + "id": "iamcredentials.projects.serviceAccounts.generateIdToken", + "parameterOrder": [ + "name" + ], + "parameters": { + "name": { + "description": "Required. The resource name of the service account for which the credentials are requested, in the following format: `projects/-/serviceAccounts/{ACCOUNT_EMAIL_OR_UNIQUEID}`. The `-` wildcard character is required; replacing it with a project ID is invalid.", + "location": "path", + "pattern": "^projects/[^/]+/serviceAccounts/[^/]+$", + "required": true, + "type": "string" + } + }, + "path": "v1/{+name}:generateIdToken", + "request": { + "$ref": "GenerateIdTokenRequest" + }, + "response": { + "$ref": "GenerateIdTokenResponse" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform" + ] + }, + "signBlob": { + "description": "Signs a blob using a service account's system-managed private key.", + "flatPath": "v1/projects/{projectsId}/serviceAccounts/{serviceAccountsId}:signBlob", + "httpMethod": "POST", + "id": "iamcredentials.projects.serviceAccounts.signBlob", + "parameterOrder": [ + "name" + ], + "parameters": { + "name": { + "description": "Required. The resource name of the service account for which the credentials are requested, in the following format: `projects/-/serviceAccounts/{ACCOUNT_EMAIL_OR_UNIQUEID}`. The `-` wildcard character is required; replacing it with a project ID is invalid.", + "location": "path", + "pattern": "^projects/[^/]+/serviceAccounts/[^/]+$", + "required": true, + "type": "string" + } + }, + "path": "v1/{+name}:signBlob", + "request": { + "$ref": "SignBlobRequest" + }, + "response": { + "$ref": "SignBlobResponse" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform" + ] + }, + "signJwt": { + "description": "Signs a JWT using a service account's system-managed private key.", + "flatPath": "v1/projects/{projectsId}/serviceAccounts/{serviceAccountsId}:signJwt", + "httpMethod": "POST", + "id": "iamcredentials.projects.serviceAccounts.signJwt", + "parameterOrder": [ + "name" + ], + "parameters": { + "name": { + "description": "Required. The resource name of the service account for which the credentials are requested, in the following format: `projects/-/serviceAccounts/{ACCOUNT_EMAIL_OR_UNIQUEID}`. The `-` wildcard character is required; replacing it with a project ID is invalid.", + "location": "path", + "pattern": "^projects/[^/]+/serviceAccounts/[^/]+$", + "required": true, + "type": "string" + } + }, + "path": "v1/{+name}:signJwt", + "request": { + "$ref": "SignJwtRequest" + }, + "response": { + "$ref": "SignJwtResponse" + }, + "scopes": [ + "https://www.googleapis.com/auth/cloud-platform" + ] + } + } + } + } + } + }, + "revision": "20211203", + "rootUrl": "https://iamcredentials.googleapis.com/", + "schemas": { + "GenerateAccessTokenRequest": { + "id": "GenerateAccessTokenRequest", + "properties": { + "delegates": { + "description": "The sequence of service accounts in a delegation chain. This field is required for [delegated requests](https://cloud.google.com/iam/help/credentials/delegated-request). For [direct requests](https://cloud.google.com/iam/help/credentials/direct-request), which are more common, do not specify this field. Each service account must be granted the `roles/iam.serviceAccountTokenCreator` role on its next service account in the chain. The last service account in the chain must be granted the `roles/iam.serviceAccountTokenCreator` role on the service account that is specified in the `name` field of the request. The delegates must have the following format: `projects/-/serviceAccounts/{ACCOUNT_EMAIL_OR_UNIQUEID}`. The `-` wildcard character is required; replacing it with a project ID is invalid.", + "items": { + "type": "string" + }, + "type": "array" + }, + "lifetime": { + "description": "The desired lifetime duration of the access token in seconds. By default, the maximum allowed value is 1 hour. To set a lifetime of up to 12 hours, you can add the service account as an allowed value in an Organization Policy that enforces the `constraints/iam.allowServiceAccountCredentialLifetimeExtension` constraint. See detailed instructions at https://cloud.google.com/iam/help/credentials/lifetime If a value is not specified, the token's lifetime will be set to a default value of 1 hour.", + "format": "google-duration", + "type": "string" + }, + "scope": { + "description": "Required. Code to identify the scopes to be included in the OAuth 2.0 access token. See https://developers.google.com/identity/protocols/googlescopes for more information. At least one value required.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "GenerateAccessTokenResponse": { + "id": "GenerateAccessTokenResponse", + "properties": { + "accessToken": { + "description": "The OAuth 2.0 access token.", + "type": "string" + }, + "expireTime": { + "description": "Token expiration time. The expiration time is always set.", + "format": "google-datetime", + "type": "string" + } + }, + "type": "object" + }, + "GenerateIdTokenRequest": { + "id": "GenerateIdTokenRequest", + "properties": { + "audience": { + "description": "Required. The audience for the token, such as the API or account that this token grants access to.", + "type": "string" + }, + "delegates": { + "description": "The sequence of service accounts in a delegation chain. Each service account must be granted the `roles/iam.serviceAccountTokenCreator` role on its next service account in the chain. The last service account in the chain must be granted the `roles/iam.serviceAccountTokenCreator` role on the service account that is specified in the `name` field of the request. The delegates must have the following format: `projects/-/serviceAccounts/{ACCOUNT_EMAIL_OR_UNIQUEID}`. The `-` wildcard character is required; replacing it with a project ID is invalid.", + "items": { + "type": "string" + }, + "type": "array" + }, + "includeEmail": { + "description": "Include the service account email in the token. If set to `true`, the token will contain `email` and `email_verified` claims.", + "type": "boolean" + } + }, + "type": "object" + }, + "GenerateIdTokenResponse": { + "id": "GenerateIdTokenResponse", + "properties": { + "token": { + "description": "The OpenId Connect ID token.", + "type": "string" + } + }, + "type": "object" + }, + "SignBlobRequest": { + "id": "SignBlobRequest", + "properties": { + "delegates": { + "description": "The sequence of service accounts in a delegation chain. Each service account must be granted the `roles/iam.serviceAccountTokenCreator` role on its next service account in the chain. The last service account in the chain must be granted the `roles/iam.serviceAccountTokenCreator` role on the service account that is specified in the `name` field of the request. The delegates must have the following format: `projects/-/serviceAccounts/{ACCOUNT_EMAIL_OR_UNIQUEID}`. The `-` wildcard character is required; replacing it with a project ID is invalid.", + "items": { + "type": "string" + }, + "type": "array" + }, + "payload": { + "description": "Required. The bytes to sign.", + "format": "byte", + "type": "string" + } + }, + "type": "object" + }, + "SignBlobResponse": { + "id": "SignBlobResponse", + "properties": { + "keyId": { + "description": "The ID of the key used to sign the blob. The key used for signing will remain valid for at least 12 hours after the blob is signed. To verify the signature, you can retrieve the public key in several formats from the following endpoints: - RSA public key wrapped in an X.509 v3 certificate: `https://www.googleapis.com/service_accounts/v1/metadata/x509/{ACCOUNT_EMAIL}` - Raw key in JSON format: `https://www.googleapis.com/service_accounts/v1/metadata/raw/{ACCOUNT_EMAIL}` - JSON Web Key (JWK): `https://www.googleapis.com/service_accounts/v1/metadata/jwk/{ACCOUNT_EMAIL}`", + "type": "string" + }, + "signedBlob": { + "description": "The signature for the blob. Does not include the original blob. After the key pair referenced by the `key_id` response field expires, Google no longer exposes the public key that can be used to verify the blob. As a result, the receiver can no longer verify the signature.", + "format": "byte", + "type": "string" + } + }, + "type": "object" + }, + "SignJwtRequest": { + "id": "SignJwtRequest", + "properties": { + "delegates": { + "description": "The sequence of service accounts in a delegation chain. Each service account must be granted the `roles/iam.serviceAccountTokenCreator` role on its next service account in the chain. The last service account in the chain must be granted the `roles/iam.serviceAccountTokenCreator` role on the service account that is specified in the `name` field of the request. The delegates must have the following format: `projects/-/serviceAccounts/{ACCOUNT_EMAIL_OR_UNIQUEID}`. The `-` wildcard character is required; replacing it with a project ID is invalid.", + "items": { + "type": "string" + }, + "type": "array" + }, + "payload": { + "description": "Required. The JWT payload to sign. Must be a serialized JSON object that contains a JWT Claims Set. For example: `{\"sub\": \"user@example.com\", \"iat\": 313435}` If the JWT Claims Set contains an expiration time (`exp`) claim, it must be an integer timestamp that is not in the past and no more than 12 hours in the future.", + "type": "string" + } + }, + "type": "object" + }, + "SignJwtResponse": { + "id": "SignJwtResponse", + "properties": { + "keyId": { + "description": "The ID of the key used to sign the JWT. The key used for signing will remain valid for at least 12 hours after the JWT is signed. To verify the signature, you can retrieve the public key in several formats from the following endpoints: - RSA public key wrapped in an X.509 v3 certificate: `https://www.googleapis.com/service_accounts/v1/metadata/x509/{ACCOUNT_EMAIL}` - Raw key in JSON format: `https://www.googleapis.com/service_accounts/v1/metadata/raw/{ACCOUNT_EMAIL}` - JSON Web Key (JWK): `https://www.googleapis.com/service_accounts/v1/metadata/jwk/{ACCOUNT_EMAIL}`", + "type": "string" + }, + "signedJwt": { + "description": "The signed JWT. Contains the automatically generated header; the client-supplied payload; and the signature, which is generated using the key referenced by the `kid` field in the header. After the key pair referenced by the `key_id` response field expires, Google no longer exposes the public key that can be used to verify the JWT. As a result, the receiver can no longer verify the signature.", + "type": "string" + } + }, + "type": "object" + } + }, + "servicePath": "", + "title": "IAM Service Account Credentials API", + "version": "v1", + "version_module": true +} \ No newline at end of file diff --git a/vendor/google.golang.org/api/iamcredentials/v1/iamcredentials-gen.go b/vendor/google.golang.org/api/iamcredentials/v1/iamcredentials-gen.go new file mode 100644 index 00000000000..29302a1e993 --- /dev/null +++ b/vendor/google.golang.org/api/iamcredentials/v1/iamcredentials-gen.go @@ -0,0 +1,1094 @@ +// Copyright 2023 Google LLC. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Code generated file. DO NOT EDIT. + +// Package iamcredentials provides access to the IAM Service Account Credentials API. +// +// For product documentation, see: https://cloud.google.com/iam/docs/creating-short-lived-service-account-credentials +// +// # Creating a client +// +// Usage example: +// +// import "google.golang.org/api/iamcredentials/v1" +// ... +// ctx := context.Background() +// iamcredentialsService, err := iamcredentials.NewService(ctx) +// +// In this example, Google Application Default Credentials are used for authentication. +// +// For information on how to create and obtain Application Default Credentials, see https://developers.google.com/identity/protocols/application-default-credentials. +// +// # Other authentication options +// +// To use an API key for authentication (note: some APIs do not support API keys), use option.WithAPIKey: +// +// iamcredentialsService, err := iamcredentials.NewService(ctx, option.WithAPIKey("AIza...")) +// +// To use an OAuth token (e.g., a user token obtained via a three-legged OAuth flow), use option.WithTokenSource: +// +// config := &oauth2.Config{...} +// // ... +// token, err := config.Exchange(ctx, ...) +// iamcredentialsService, err := iamcredentials.NewService(ctx, option.WithTokenSource(config.TokenSource(ctx, token))) +// +// See https://godoc.org/google.golang.org/api/option/ for details on options. +package iamcredentials // import "google.golang.org/api/iamcredentials/v1" + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + "net/url" + "strconv" + "strings" + + googleapi "google.golang.org/api/googleapi" + internal "google.golang.org/api/internal" + gensupport "google.golang.org/api/internal/gensupport" + option "google.golang.org/api/option" + internaloption "google.golang.org/api/option/internaloption" + htransport "google.golang.org/api/transport/http" +) + +// Always reference these packages, just in case the auto-generated code +// below doesn't. +var _ = bytes.NewBuffer +var _ = strconv.Itoa +var _ = fmt.Sprintf +var _ = json.NewDecoder +var _ = io.Copy +var _ = url.Parse +var _ = gensupport.MarshalJSON +var _ = googleapi.Version +var _ = errors.New +var _ = strings.Replace +var _ = context.Canceled +var _ = internaloption.WithDefaultEndpoint + +const apiId = "iamcredentials:v1" +const apiName = "iamcredentials" +const apiVersion = "v1" +const basePath = "https://iamcredentials.googleapis.com/" +const mtlsBasePath = "https://iamcredentials.mtls.googleapis.com/" + +// OAuth2 scopes used by this API. +const ( + // See, edit, configure, and delete your Google Cloud data and see the + // email address for your Google Account. + CloudPlatformScope = "https://www.googleapis.com/auth/cloud-platform" +) + +// NewService creates a new Service. +func NewService(ctx context.Context, opts ...option.ClientOption) (*Service, error) { + scopesOption := internaloption.WithDefaultScopes( + "https://www.googleapis.com/auth/cloud-platform", + ) + // NOTE: prepend, so we don't override user-specified scopes. + opts = append([]option.ClientOption{scopesOption}, opts...) + opts = append(opts, internaloption.WithDefaultEndpoint(basePath)) + opts = append(opts, internaloption.WithDefaultMTLSEndpoint(mtlsBasePath)) + client, endpoint, err := htransport.NewClient(ctx, opts...) + if err != nil { + return nil, err + } + s, err := New(client) + if err != nil { + return nil, err + } + if endpoint != "" { + s.BasePath = endpoint + } + return s, nil +} + +// New creates a new Service. It uses the provided http.Client for requests. +// +// Deprecated: please use NewService instead. +// To provide a custom HTTP client, use option.WithHTTPClient. +// If you are using google.golang.org/api/googleapis/transport.APIKey, use option.WithAPIKey with NewService instead. +func New(client *http.Client) (*Service, error) { + if client == nil { + return nil, errors.New("client is nil") + } + s := &Service{client: client, BasePath: basePath} + s.Projects = NewProjectsService(s) + return s, nil +} + +type Service struct { + client *http.Client + BasePath string // API endpoint base URL + UserAgent string // optional additional User-Agent fragment + + Projects *ProjectsService +} + +func (s *Service) userAgent() string { + if s.UserAgent == "" { + return googleapi.UserAgent + } + return googleapi.UserAgent + " " + s.UserAgent +} + +func NewProjectsService(s *Service) *ProjectsService { + rs := &ProjectsService{s: s} + rs.ServiceAccounts = NewProjectsServiceAccountsService(s) + return rs +} + +type ProjectsService struct { + s *Service + + ServiceAccounts *ProjectsServiceAccountsService +} + +func NewProjectsServiceAccountsService(s *Service) *ProjectsServiceAccountsService { + rs := &ProjectsServiceAccountsService{s: s} + return rs +} + +type ProjectsServiceAccountsService struct { + s *Service +} + +type GenerateAccessTokenRequest struct { + // Delegates: The sequence of service accounts in a delegation chain. + // This field is required for delegated requests + // (https://cloud.google.com/iam/help/credentials/delegated-request). + // For direct requests + // (https://cloud.google.com/iam/help/credentials/direct-request), which + // are more common, do not specify this field. Each service account must + // be granted the `roles/iam.serviceAccountTokenCreator` role on its + // next service account in the chain. The last service account in the + // chain must be granted the `roles/iam.serviceAccountTokenCreator` role + // on the service account that is specified in the `name` field of the + // request. The delegates must have the following format: + // `projects/-/serviceAccounts/{ACCOUNT_EMAIL_OR_UNIQUEID}`. The `-` + // wildcard character is required; replacing it with a project ID is + // invalid. + Delegates []string `json:"delegates,omitempty"` + + // Lifetime: The desired lifetime duration of the access token in + // seconds. By default, the maximum allowed value is 1 hour. To set a + // lifetime of up to 12 hours, you can add the service account as an + // allowed value in an Organization Policy that enforces the + // `constraints/iam.allowServiceAccountCredentialLifetimeExtension` + // constraint. See detailed instructions at + // https://cloud.google.com/iam/help/credentials/lifetime If a value is + // not specified, the token's lifetime will be set to a default value of + // 1 hour. + Lifetime string `json:"lifetime,omitempty"` + + // Scope: Required. Code to identify the scopes to be included in the + // OAuth 2.0 access token. See + // https://developers.google.com/identity/protocols/googlescopes for + // more information. At least one value required. + Scope []string `json:"scope,omitempty"` + + // ForceSendFields is a list of field names (e.g. "Delegates") to + // unconditionally include in API requests. By default, fields with + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. + ForceSendFields []string `json:"-"` + + // NullFields is a list of field names (e.g. "Delegates") to include in + // API requests with the JSON null value. By default, fields with empty + // values are omitted from API requests. However, any field with an + // empty value appearing in NullFields will be sent to the server as + // null. It is an error if a field in this list has a non-empty value. + // This may be used to include null fields in Patch requests. + NullFields []string `json:"-"` +} + +func (s *GenerateAccessTokenRequest) MarshalJSON() ([]byte, error) { + type NoMethod GenerateAccessTokenRequest + raw := NoMethod(*s) + return gensupport.MarshalJSON(raw, s.ForceSendFields, s.NullFields) +} + +type GenerateAccessTokenResponse struct { + // AccessToken: The OAuth 2.0 access token. + AccessToken string `json:"accessToken,omitempty"` + + // ExpireTime: Token expiration time. The expiration time is always set. + ExpireTime string `json:"expireTime,omitempty"` + + // ServerResponse contains the HTTP response code and headers from the + // server. + googleapi.ServerResponse `json:"-"` + + // ForceSendFields is a list of field names (e.g. "AccessToken") to + // unconditionally include in API requests. By default, fields with + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. + ForceSendFields []string `json:"-"` + + // NullFields is a list of field names (e.g. "AccessToken") to include + // in API requests with the JSON null value. By default, fields with + // empty values are omitted from API requests. However, any field with + // an empty value appearing in NullFields will be sent to the server as + // null. It is an error if a field in this list has a non-empty value. + // This may be used to include null fields in Patch requests. + NullFields []string `json:"-"` +} + +func (s *GenerateAccessTokenResponse) MarshalJSON() ([]byte, error) { + type NoMethod GenerateAccessTokenResponse + raw := NoMethod(*s) + return gensupport.MarshalJSON(raw, s.ForceSendFields, s.NullFields) +} + +type GenerateIdTokenRequest struct { + // Audience: Required. The audience for the token, such as the API or + // account that this token grants access to. + Audience string `json:"audience,omitempty"` + + // Delegates: The sequence of service accounts in a delegation chain. + // Each service account must be granted the + // `roles/iam.serviceAccountTokenCreator` role on its next service + // account in the chain. The last service account in the chain must be + // granted the `roles/iam.serviceAccountTokenCreator` role on the + // service account that is specified in the `name` field of the request. + // The delegates must have the following format: + // `projects/-/serviceAccounts/{ACCOUNT_EMAIL_OR_UNIQUEID}`. The `-` + // wildcard character is required; replacing it with a project ID is + // invalid. + Delegates []string `json:"delegates,omitempty"` + + // IncludeEmail: Include the service account email in the token. If set + // to `true`, the token will contain `email` and `email_verified` + // claims. + IncludeEmail bool `json:"includeEmail,omitempty"` + + // ForceSendFields is a list of field names (e.g. "Audience") to + // unconditionally include in API requests. By default, fields with + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. + ForceSendFields []string `json:"-"` + + // NullFields is a list of field names (e.g. "Audience") to include in + // API requests with the JSON null value. By default, fields with empty + // values are omitted from API requests. However, any field with an + // empty value appearing in NullFields will be sent to the server as + // null. It is an error if a field in this list has a non-empty value. + // This may be used to include null fields in Patch requests. + NullFields []string `json:"-"` +} + +func (s *GenerateIdTokenRequest) MarshalJSON() ([]byte, error) { + type NoMethod GenerateIdTokenRequest + raw := NoMethod(*s) + return gensupport.MarshalJSON(raw, s.ForceSendFields, s.NullFields) +} + +type GenerateIdTokenResponse struct { + // Token: The OpenId Connect ID token. + Token string `json:"token,omitempty"` + + // ServerResponse contains the HTTP response code and headers from the + // server. + googleapi.ServerResponse `json:"-"` + + // ForceSendFields is a list of field names (e.g. "Token") to + // unconditionally include in API requests. By default, fields with + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. + ForceSendFields []string `json:"-"` + + // NullFields is a list of field names (e.g. "Token") to include in API + // requests with the JSON null value. By default, fields with empty + // values are omitted from API requests. However, any field with an + // empty value appearing in NullFields will be sent to the server as + // null. It is an error if a field in this list has a non-empty value. + // This may be used to include null fields in Patch requests. + NullFields []string `json:"-"` +} + +func (s *GenerateIdTokenResponse) MarshalJSON() ([]byte, error) { + type NoMethod GenerateIdTokenResponse + raw := NoMethod(*s) + return gensupport.MarshalJSON(raw, s.ForceSendFields, s.NullFields) +} + +type SignBlobRequest struct { + // Delegates: The sequence of service accounts in a delegation chain. + // Each service account must be granted the + // `roles/iam.serviceAccountTokenCreator` role on its next service + // account in the chain. The last service account in the chain must be + // granted the `roles/iam.serviceAccountTokenCreator` role on the + // service account that is specified in the `name` field of the request. + // The delegates must have the following format: + // `projects/-/serviceAccounts/{ACCOUNT_EMAIL_OR_UNIQUEID}`. The `-` + // wildcard character is required; replacing it with a project ID is + // invalid. + Delegates []string `json:"delegates,omitempty"` + + // Payload: Required. The bytes to sign. + Payload string `json:"payload,omitempty"` + + // ForceSendFields is a list of field names (e.g. "Delegates") to + // unconditionally include in API requests. By default, fields with + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. + ForceSendFields []string `json:"-"` + + // NullFields is a list of field names (e.g. "Delegates") to include in + // API requests with the JSON null value. By default, fields with empty + // values are omitted from API requests. However, any field with an + // empty value appearing in NullFields will be sent to the server as + // null. It is an error if a field in this list has a non-empty value. + // This may be used to include null fields in Patch requests. + NullFields []string `json:"-"` +} + +func (s *SignBlobRequest) MarshalJSON() ([]byte, error) { + type NoMethod SignBlobRequest + raw := NoMethod(*s) + return gensupport.MarshalJSON(raw, s.ForceSendFields, s.NullFields) +} + +type SignBlobResponse struct { + // KeyId: The ID of the key used to sign the blob. The key used for + // signing will remain valid for at least 12 hours after the blob is + // signed. To verify the signature, you can retrieve the public key in + // several formats from the following endpoints: - RSA public key + // wrapped in an X.509 v3 certificate: + // `https://www.googleapis.com/service_accounts/v1/metadata/x509/{ACCOUNT + // _EMAIL}` - Raw key in JSON format: + // `https://www.googleapis.com/service_accounts/v1/metadata/raw/{ACCOUNT_ + // EMAIL}` - JSON Web Key (JWK): + // `https://www.googleapis.com/service_accounts/v1/metadata/jwk/{ACCOUNT_ + // EMAIL}` + KeyId string `json:"keyId,omitempty"` + + // SignedBlob: The signature for the blob. Does not include the original + // blob. After the key pair referenced by the `key_id` response field + // expires, Google no longer exposes the public key that can be used to + // verify the blob. As a result, the receiver can no longer verify the + // signature. + SignedBlob string `json:"signedBlob,omitempty"` + + // ServerResponse contains the HTTP response code and headers from the + // server. + googleapi.ServerResponse `json:"-"` + + // ForceSendFields is a list of field names (e.g. "KeyId") to + // unconditionally include in API requests. By default, fields with + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. + ForceSendFields []string `json:"-"` + + // NullFields is a list of field names (e.g. "KeyId") to include in API + // requests with the JSON null value. By default, fields with empty + // values are omitted from API requests. However, any field with an + // empty value appearing in NullFields will be sent to the server as + // null. It is an error if a field in this list has a non-empty value. + // This may be used to include null fields in Patch requests. + NullFields []string `json:"-"` +} + +func (s *SignBlobResponse) MarshalJSON() ([]byte, error) { + type NoMethod SignBlobResponse + raw := NoMethod(*s) + return gensupport.MarshalJSON(raw, s.ForceSendFields, s.NullFields) +} + +type SignJwtRequest struct { + // Delegates: The sequence of service accounts in a delegation chain. + // Each service account must be granted the + // `roles/iam.serviceAccountTokenCreator` role on its next service + // account in the chain. The last service account in the chain must be + // granted the `roles/iam.serviceAccountTokenCreator` role on the + // service account that is specified in the `name` field of the request. + // The delegates must have the following format: + // `projects/-/serviceAccounts/{ACCOUNT_EMAIL_OR_UNIQUEID}`. The `-` + // wildcard character is required; replacing it with a project ID is + // invalid. + Delegates []string `json:"delegates,omitempty"` + + // Payload: Required. The JWT payload to sign. Must be a serialized JSON + // object that contains a JWT Claims Set. For example: `{"sub": + // "user@example.com", "iat": 313435}` If the JWT Claims Set contains an + // expiration time (`exp`) claim, it must be an integer timestamp that + // is not in the past and no more than 12 hours in the future. + Payload string `json:"payload,omitempty"` + + // ForceSendFields is a list of field names (e.g. "Delegates") to + // unconditionally include in API requests. By default, fields with + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. + ForceSendFields []string `json:"-"` + + // NullFields is a list of field names (e.g. "Delegates") to include in + // API requests with the JSON null value. By default, fields with empty + // values are omitted from API requests. However, any field with an + // empty value appearing in NullFields will be sent to the server as + // null. It is an error if a field in this list has a non-empty value. + // This may be used to include null fields in Patch requests. + NullFields []string `json:"-"` +} + +func (s *SignJwtRequest) MarshalJSON() ([]byte, error) { + type NoMethod SignJwtRequest + raw := NoMethod(*s) + return gensupport.MarshalJSON(raw, s.ForceSendFields, s.NullFields) +} + +type SignJwtResponse struct { + // KeyId: The ID of the key used to sign the JWT. The key used for + // signing will remain valid for at least 12 hours after the JWT is + // signed. To verify the signature, you can retrieve the public key in + // several formats from the following endpoints: - RSA public key + // wrapped in an X.509 v3 certificate: + // `https://www.googleapis.com/service_accounts/v1/metadata/x509/{ACCOUNT + // _EMAIL}` - Raw key in JSON format: + // `https://www.googleapis.com/service_accounts/v1/metadata/raw/{ACCOUNT_ + // EMAIL}` - JSON Web Key (JWK): + // `https://www.googleapis.com/service_accounts/v1/metadata/jwk/{ACCOUNT_ + // EMAIL}` + KeyId string `json:"keyId,omitempty"` + + // SignedJwt: The signed JWT. Contains the automatically generated + // header; the client-supplied payload; and the signature, which is + // generated using the key referenced by the `kid` field in the header. + // After the key pair referenced by the `key_id` response field expires, + // Google no longer exposes the public key that can be used to verify + // the JWT. As a result, the receiver can no longer verify the + // signature. + SignedJwt string `json:"signedJwt,omitempty"` + + // ServerResponse contains the HTTP response code and headers from the + // server. + googleapi.ServerResponse `json:"-"` + + // ForceSendFields is a list of field names (e.g. "KeyId") to + // unconditionally include in API requests. By default, fields with + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. + ForceSendFields []string `json:"-"` + + // NullFields is a list of field names (e.g. "KeyId") to include in API + // requests with the JSON null value. By default, fields with empty + // values are omitted from API requests. However, any field with an + // empty value appearing in NullFields will be sent to the server as + // null. It is an error if a field in this list has a non-empty value. + // This may be used to include null fields in Patch requests. + NullFields []string `json:"-"` +} + +func (s *SignJwtResponse) MarshalJSON() ([]byte, error) { + type NoMethod SignJwtResponse + raw := NoMethod(*s) + return gensupport.MarshalJSON(raw, s.ForceSendFields, s.NullFields) +} + +// method id "iamcredentials.projects.serviceAccounts.generateAccessToken": + +type ProjectsServiceAccountsGenerateAccessTokenCall struct { + s *Service + name string + generateaccesstokenrequest *GenerateAccessTokenRequest + urlParams_ gensupport.URLParams + ctx_ context.Context + header_ http.Header +} + +// GenerateAccessToken: Generates an OAuth 2.0 access token for a +// service account. +// +// - name: The resource name of the service account for which the +// credentials are requested, in the following format: +// `projects/-/serviceAccounts/{ACCOUNT_EMAIL_OR_UNIQUEID}`. The `-` +// wildcard character is required; replacing it with a project ID is +// invalid. +func (r *ProjectsServiceAccountsService) GenerateAccessToken(name string, generateaccesstokenrequest *GenerateAccessTokenRequest) *ProjectsServiceAccountsGenerateAccessTokenCall { + c := &ProjectsServiceAccountsGenerateAccessTokenCall{s: r.s, urlParams_: make(gensupport.URLParams)} + c.name = name + c.generateaccesstokenrequest = generateaccesstokenrequest + return c +} + +// Fields allows partial responses to be retrieved. See +// https://developers.google.com/gdata/docs/2.0/basics#PartialResponse +// for more information. +func (c *ProjectsServiceAccountsGenerateAccessTokenCall) Fields(s ...googleapi.Field) *ProjectsServiceAccountsGenerateAccessTokenCall { + c.urlParams_.Set("fields", googleapi.CombineFields(s)) + return c +} + +// Context sets the context to be used in this call's Do method. Any +// pending HTTP request will be aborted if the provided context is +// canceled. +func (c *ProjectsServiceAccountsGenerateAccessTokenCall) Context(ctx context.Context) *ProjectsServiceAccountsGenerateAccessTokenCall { + c.ctx_ = ctx + return c +} + +// Header returns an http.Header that can be modified by the caller to +// add HTTP headers to the request. +func (c *ProjectsServiceAccountsGenerateAccessTokenCall) Header() http.Header { + if c.header_ == nil { + c.header_ = make(http.Header) + } + return c.header_ +} + +func (c *ProjectsServiceAccountsGenerateAccessTokenCall) doRequest(alt string) (*http.Response, error) { + reqHeaders := make(http.Header) + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) + for k, v := range c.header_ { + reqHeaders[k] = v + } + reqHeaders.Set("User-Agent", c.s.userAgent()) + var body io.Reader = nil + body, err := googleapi.WithoutDataWrapper.JSONReader(c.generateaccesstokenrequest) + if err != nil { + return nil, err + } + reqHeaders.Set("Content-Type", "application/json") + c.urlParams_.Set("alt", alt) + c.urlParams_.Set("prettyPrint", "false") + urls := googleapi.ResolveRelative(c.s.BasePath, "v1/{+name}:generateAccessToken") + urls += "?" + c.urlParams_.Encode() + req, err := http.NewRequest("POST", urls, body) + if err != nil { + return nil, err + } + req.Header = reqHeaders + googleapi.Expand(req.URL, map[string]string{ + "name": c.name, + }) + return gensupport.SendRequest(c.ctx_, c.s.client, req) +} + +// Do executes the "iamcredentials.projects.serviceAccounts.generateAccessToken" call. +// Exactly one of *GenerateAccessTokenResponse or error will be non-nil. +// Any non-2xx status code is an error. Response headers are in either +// *GenerateAccessTokenResponse.ServerResponse.Header or (if a response +// was returned at all) in error.(*googleapi.Error).Header. Use +// googleapi.IsNotModified to check whether the returned error was +// because http.StatusNotModified was returned. +func (c *ProjectsServiceAccountsGenerateAccessTokenCall) Do(opts ...googleapi.CallOption) (*GenerateAccessTokenResponse, error) { + gensupport.SetOptions(c.urlParams_, opts...) + res, err := c.doRequest("json") + if res != nil && res.StatusCode == http.StatusNotModified { + if res.Body != nil { + res.Body.Close() + } + return nil, gensupport.WrapError(&googleapi.Error{ + Code: res.StatusCode, + Header: res.Header, + }) + } + if err != nil { + return nil, err + } + defer googleapi.CloseBody(res) + if err := googleapi.CheckResponse(res); err != nil { + return nil, gensupport.WrapError(err) + } + ret := &GenerateAccessTokenResponse{ + ServerResponse: googleapi.ServerResponse{ + Header: res.Header, + HTTPStatusCode: res.StatusCode, + }, + } + target := &ret + if err := gensupport.DecodeResponse(target, res); err != nil { + return nil, err + } + return ret, nil + // { + // "description": "Generates an OAuth 2.0 access token for a service account.", + // "flatPath": "v1/projects/{projectsId}/serviceAccounts/{serviceAccountsId}:generateAccessToken", + // "httpMethod": "POST", + // "id": "iamcredentials.projects.serviceAccounts.generateAccessToken", + // "parameterOrder": [ + // "name" + // ], + // "parameters": { + // "name": { + // "description": "Required. The resource name of the service account for which the credentials are requested, in the following format: `projects/-/serviceAccounts/{ACCOUNT_EMAIL_OR_UNIQUEID}`. The `-` wildcard character is required; replacing it with a project ID is invalid.", + // "location": "path", + // "pattern": "^projects/[^/]+/serviceAccounts/[^/]+$", + // "required": true, + // "type": "string" + // } + // }, + // "path": "v1/{+name}:generateAccessToken", + // "request": { + // "$ref": "GenerateAccessTokenRequest" + // }, + // "response": { + // "$ref": "GenerateAccessTokenResponse" + // }, + // "scopes": [ + // "https://www.googleapis.com/auth/cloud-platform" + // ] + // } + +} + +// method id "iamcredentials.projects.serviceAccounts.generateIdToken": + +type ProjectsServiceAccountsGenerateIdTokenCall struct { + s *Service + name string + generateidtokenrequest *GenerateIdTokenRequest + urlParams_ gensupport.URLParams + ctx_ context.Context + header_ http.Header +} + +// GenerateIdToken: Generates an OpenID Connect ID token for a service +// account. +// +// - name: The resource name of the service account for which the +// credentials are requested, in the following format: +// `projects/-/serviceAccounts/{ACCOUNT_EMAIL_OR_UNIQUEID}`. The `-` +// wildcard character is required; replacing it with a project ID is +// invalid. +func (r *ProjectsServiceAccountsService) GenerateIdToken(name string, generateidtokenrequest *GenerateIdTokenRequest) *ProjectsServiceAccountsGenerateIdTokenCall { + c := &ProjectsServiceAccountsGenerateIdTokenCall{s: r.s, urlParams_: make(gensupport.URLParams)} + c.name = name + c.generateidtokenrequest = generateidtokenrequest + return c +} + +// Fields allows partial responses to be retrieved. See +// https://developers.google.com/gdata/docs/2.0/basics#PartialResponse +// for more information. +func (c *ProjectsServiceAccountsGenerateIdTokenCall) Fields(s ...googleapi.Field) *ProjectsServiceAccountsGenerateIdTokenCall { + c.urlParams_.Set("fields", googleapi.CombineFields(s)) + return c +} + +// Context sets the context to be used in this call's Do method. Any +// pending HTTP request will be aborted if the provided context is +// canceled. +func (c *ProjectsServiceAccountsGenerateIdTokenCall) Context(ctx context.Context) *ProjectsServiceAccountsGenerateIdTokenCall { + c.ctx_ = ctx + return c +} + +// Header returns an http.Header that can be modified by the caller to +// add HTTP headers to the request. +func (c *ProjectsServiceAccountsGenerateIdTokenCall) Header() http.Header { + if c.header_ == nil { + c.header_ = make(http.Header) + } + return c.header_ +} + +func (c *ProjectsServiceAccountsGenerateIdTokenCall) doRequest(alt string) (*http.Response, error) { + reqHeaders := make(http.Header) + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) + for k, v := range c.header_ { + reqHeaders[k] = v + } + reqHeaders.Set("User-Agent", c.s.userAgent()) + var body io.Reader = nil + body, err := googleapi.WithoutDataWrapper.JSONReader(c.generateidtokenrequest) + if err != nil { + return nil, err + } + reqHeaders.Set("Content-Type", "application/json") + c.urlParams_.Set("alt", alt) + c.urlParams_.Set("prettyPrint", "false") + urls := googleapi.ResolveRelative(c.s.BasePath, "v1/{+name}:generateIdToken") + urls += "?" + c.urlParams_.Encode() + req, err := http.NewRequest("POST", urls, body) + if err != nil { + return nil, err + } + req.Header = reqHeaders + googleapi.Expand(req.URL, map[string]string{ + "name": c.name, + }) + return gensupport.SendRequest(c.ctx_, c.s.client, req) +} + +// Do executes the "iamcredentials.projects.serviceAccounts.generateIdToken" call. +// Exactly one of *GenerateIdTokenResponse or error will be non-nil. Any +// non-2xx status code is an error. Response headers are in either +// *GenerateIdTokenResponse.ServerResponse.Header or (if a response was +// returned at all) in error.(*googleapi.Error).Header. Use +// googleapi.IsNotModified to check whether the returned error was +// because http.StatusNotModified was returned. +func (c *ProjectsServiceAccountsGenerateIdTokenCall) Do(opts ...googleapi.CallOption) (*GenerateIdTokenResponse, error) { + gensupport.SetOptions(c.urlParams_, opts...) + res, err := c.doRequest("json") + if res != nil && res.StatusCode == http.StatusNotModified { + if res.Body != nil { + res.Body.Close() + } + return nil, gensupport.WrapError(&googleapi.Error{ + Code: res.StatusCode, + Header: res.Header, + }) + } + if err != nil { + return nil, err + } + defer googleapi.CloseBody(res) + if err := googleapi.CheckResponse(res); err != nil { + return nil, gensupport.WrapError(err) + } + ret := &GenerateIdTokenResponse{ + ServerResponse: googleapi.ServerResponse{ + Header: res.Header, + HTTPStatusCode: res.StatusCode, + }, + } + target := &ret + if err := gensupport.DecodeResponse(target, res); err != nil { + return nil, err + } + return ret, nil + // { + // "description": "Generates an OpenID Connect ID token for a service account.", + // "flatPath": "v1/projects/{projectsId}/serviceAccounts/{serviceAccountsId}:generateIdToken", + // "httpMethod": "POST", + // "id": "iamcredentials.projects.serviceAccounts.generateIdToken", + // "parameterOrder": [ + // "name" + // ], + // "parameters": { + // "name": { + // "description": "Required. The resource name of the service account for which the credentials are requested, in the following format: `projects/-/serviceAccounts/{ACCOUNT_EMAIL_OR_UNIQUEID}`. The `-` wildcard character is required; replacing it with a project ID is invalid.", + // "location": "path", + // "pattern": "^projects/[^/]+/serviceAccounts/[^/]+$", + // "required": true, + // "type": "string" + // } + // }, + // "path": "v1/{+name}:generateIdToken", + // "request": { + // "$ref": "GenerateIdTokenRequest" + // }, + // "response": { + // "$ref": "GenerateIdTokenResponse" + // }, + // "scopes": [ + // "https://www.googleapis.com/auth/cloud-platform" + // ] + // } + +} + +// method id "iamcredentials.projects.serviceAccounts.signBlob": + +type ProjectsServiceAccountsSignBlobCall struct { + s *Service + name string + signblobrequest *SignBlobRequest + urlParams_ gensupport.URLParams + ctx_ context.Context + header_ http.Header +} + +// SignBlob: Signs a blob using a service account's system-managed +// private key. +// +// - name: The resource name of the service account for which the +// credentials are requested, in the following format: +// `projects/-/serviceAccounts/{ACCOUNT_EMAIL_OR_UNIQUEID}`. The `-` +// wildcard character is required; replacing it with a project ID is +// invalid. +func (r *ProjectsServiceAccountsService) SignBlob(name string, signblobrequest *SignBlobRequest) *ProjectsServiceAccountsSignBlobCall { + c := &ProjectsServiceAccountsSignBlobCall{s: r.s, urlParams_: make(gensupport.URLParams)} + c.name = name + c.signblobrequest = signblobrequest + return c +} + +// Fields allows partial responses to be retrieved. See +// https://developers.google.com/gdata/docs/2.0/basics#PartialResponse +// for more information. +func (c *ProjectsServiceAccountsSignBlobCall) Fields(s ...googleapi.Field) *ProjectsServiceAccountsSignBlobCall { + c.urlParams_.Set("fields", googleapi.CombineFields(s)) + return c +} + +// Context sets the context to be used in this call's Do method. Any +// pending HTTP request will be aborted if the provided context is +// canceled. +func (c *ProjectsServiceAccountsSignBlobCall) Context(ctx context.Context) *ProjectsServiceAccountsSignBlobCall { + c.ctx_ = ctx + return c +} + +// Header returns an http.Header that can be modified by the caller to +// add HTTP headers to the request. +func (c *ProjectsServiceAccountsSignBlobCall) Header() http.Header { + if c.header_ == nil { + c.header_ = make(http.Header) + } + return c.header_ +} + +func (c *ProjectsServiceAccountsSignBlobCall) doRequest(alt string) (*http.Response, error) { + reqHeaders := make(http.Header) + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) + for k, v := range c.header_ { + reqHeaders[k] = v + } + reqHeaders.Set("User-Agent", c.s.userAgent()) + var body io.Reader = nil + body, err := googleapi.WithoutDataWrapper.JSONReader(c.signblobrequest) + if err != nil { + return nil, err + } + reqHeaders.Set("Content-Type", "application/json") + c.urlParams_.Set("alt", alt) + c.urlParams_.Set("prettyPrint", "false") + urls := googleapi.ResolveRelative(c.s.BasePath, "v1/{+name}:signBlob") + urls += "?" + c.urlParams_.Encode() + req, err := http.NewRequest("POST", urls, body) + if err != nil { + return nil, err + } + req.Header = reqHeaders + googleapi.Expand(req.URL, map[string]string{ + "name": c.name, + }) + return gensupport.SendRequest(c.ctx_, c.s.client, req) +} + +// Do executes the "iamcredentials.projects.serviceAccounts.signBlob" call. +// Exactly one of *SignBlobResponse or error will be non-nil. Any +// non-2xx status code is an error. Response headers are in either +// *SignBlobResponse.ServerResponse.Header or (if a response was +// returned at all) in error.(*googleapi.Error).Header. Use +// googleapi.IsNotModified to check whether the returned error was +// because http.StatusNotModified was returned. +func (c *ProjectsServiceAccountsSignBlobCall) Do(opts ...googleapi.CallOption) (*SignBlobResponse, error) { + gensupport.SetOptions(c.urlParams_, opts...) + res, err := c.doRequest("json") + if res != nil && res.StatusCode == http.StatusNotModified { + if res.Body != nil { + res.Body.Close() + } + return nil, gensupport.WrapError(&googleapi.Error{ + Code: res.StatusCode, + Header: res.Header, + }) + } + if err != nil { + return nil, err + } + defer googleapi.CloseBody(res) + if err := googleapi.CheckResponse(res); err != nil { + return nil, gensupport.WrapError(err) + } + ret := &SignBlobResponse{ + ServerResponse: googleapi.ServerResponse{ + Header: res.Header, + HTTPStatusCode: res.StatusCode, + }, + } + target := &ret + if err := gensupport.DecodeResponse(target, res); err != nil { + return nil, err + } + return ret, nil + // { + // "description": "Signs a blob using a service account's system-managed private key.", + // "flatPath": "v1/projects/{projectsId}/serviceAccounts/{serviceAccountsId}:signBlob", + // "httpMethod": "POST", + // "id": "iamcredentials.projects.serviceAccounts.signBlob", + // "parameterOrder": [ + // "name" + // ], + // "parameters": { + // "name": { + // "description": "Required. The resource name of the service account for which the credentials are requested, in the following format: `projects/-/serviceAccounts/{ACCOUNT_EMAIL_OR_UNIQUEID}`. The `-` wildcard character is required; replacing it with a project ID is invalid.", + // "location": "path", + // "pattern": "^projects/[^/]+/serviceAccounts/[^/]+$", + // "required": true, + // "type": "string" + // } + // }, + // "path": "v1/{+name}:signBlob", + // "request": { + // "$ref": "SignBlobRequest" + // }, + // "response": { + // "$ref": "SignBlobResponse" + // }, + // "scopes": [ + // "https://www.googleapis.com/auth/cloud-platform" + // ] + // } + +} + +// method id "iamcredentials.projects.serviceAccounts.signJwt": + +type ProjectsServiceAccountsSignJwtCall struct { + s *Service + name string + signjwtrequest *SignJwtRequest + urlParams_ gensupport.URLParams + ctx_ context.Context + header_ http.Header +} + +// SignJwt: Signs a JWT using a service account's system-managed private +// key. +// +// - name: The resource name of the service account for which the +// credentials are requested, in the following format: +// `projects/-/serviceAccounts/{ACCOUNT_EMAIL_OR_UNIQUEID}`. The `-` +// wildcard character is required; replacing it with a project ID is +// invalid. +func (r *ProjectsServiceAccountsService) SignJwt(name string, signjwtrequest *SignJwtRequest) *ProjectsServiceAccountsSignJwtCall { + c := &ProjectsServiceAccountsSignJwtCall{s: r.s, urlParams_: make(gensupport.URLParams)} + c.name = name + c.signjwtrequest = signjwtrequest + return c +} + +// Fields allows partial responses to be retrieved. See +// https://developers.google.com/gdata/docs/2.0/basics#PartialResponse +// for more information. +func (c *ProjectsServiceAccountsSignJwtCall) Fields(s ...googleapi.Field) *ProjectsServiceAccountsSignJwtCall { + c.urlParams_.Set("fields", googleapi.CombineFields(s)) + return c +} + +// Context sets the context to be used in this call's Do method. Any +// pending HTTP request will be aborted if the provided context is +// canceled. +func (c *ProjectsServiceAccountsSignJwtCall) Context(ctx context.Context) *ProjectsServiceAccountsSignJwtCall { + c.ctx_ = ctx + return c +} + +// Header returns an http.Header that can be modified by the caller to +// add HTTP headers to the request. +func (c *ProjectsServiceAccountsSignJwtCall) Header() http.Header { + if c.header_ == nil { + c.header_ = make(http.Header) + } + return c.header_ +} + +func (c *ProjectsServiceAccountsSignJwtCall) doRequest(alt string) (*http.Response, error) { + reqHeaders := make(http.Header) + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) + for k, v := range c.header_ { + reqHeaders[k] = v + } + reqHeaders.Set("User-Agent", c.s.userAgent()) + var body io.Reader = nil + body, err := googleapi.WithoutDataWrapper.JSONReader(c.signjwtrequest) + if err != nil { + return nil, err + } + reqHeaders.Set("Content-Type", "application/json") + c.urlParams_.Set("alt", alt) + c.urlParams_.Set("prettyPrint", "false") + urls := googleapi.ResolveRelative(c.s.BasePath, "v1/{+name}:signJwt") + urls += "?" + c.urlParams_.Encode() + req, err := http.NewRequest("POST", urls, body) + if err != nil { + return nil, err + } + req.Header = reqHeaders + googleapi.Expand(req.URL, map[string]string{ + "name": c.name, + }) + return gensupport.SendRequest(c.ctx_, c.s.client, req) +} + +// Do executes the "iamcredentials.projects.serviceAccounts.signJwt" call. +// Exactly one of *SignJwtResponse or error will be non-nil. Any non-2xx +// status code is an error. Response headers are in either +// *SignJwtResponse.ServerResponse.Header or (if a response was returned +// at all) in error.(*googleapi.Error).Header. Use +// googleapi.IsNotModified to check whether the returned error was +// because http.StatusNotModified was returned. +func (c *ProjectsServiceAccountsSignJwtCall) Do(opts ...googleapi.CallOption) (*SignJwtResponse, error) { + gensupport.SetOptions(c.urlParams_, opts...) + res, err := c.doRequest("json") + if res != nil && res.StatusCode == http.StatusNotModified { + if res.Body != nil { + res.Body.Close() + } + return nil, gensupport.WrapError(&googleapi.Error{ + Code: res.StatusCode, + Header: res.Header, + }) + } + if err != nil { + return nil, err + } + defer googleapi.CloseBody(res) + if err := googleapi.CheckResponse(res); err != nil { + return nil, gensupport.WrapError(err) + } + ret := &SignJwtResponse{ + ServerResponse: googleapi.ServerResponse{ + Header: res.Header, + HTTPStatusCode: res.StatusCode, + }, + } + target := &ret + if err := gensupport.DecodeResponse(target, res); err != nil { + return nil, err + } + return ret, nil + // { + // "description": "Signs a JWT using a service account's system-managed private key.", + // "flatPath": "v1/projects/{projectsId}/serviceAccounts/{serviceAccountsId}:signJwt", + // "httpMethod": "POST", + // "id": "iamcredentials.projects.serviceAccounts.signJwt", + // "parameterOrder": [ + // "name" + // ], + // "parameters": { + // "name": { + // "description": "Required. The resource name of the service account for which the credentials are requested, in the following format: `projects/-/serviceAccounts/{ACCOUNT_EMAIL_OR_UNIQUEID}`. The `-` wildcard character is required; replacing it with a project ID is invalid.", + // "location": "path", + // "pattern": "^projects/[^/]+/serviceAccounts/[^/]+$", + // "required": true, + // "type": "string" + // } + // }, + // "path": "v1/{+name}:signJwt", + // "request": { + // "$ref": "SignJwtRequest" + // }, + // "response": { + // "$ref": "SignJwtResponse" + // }, + // "scopes": [ + // "https://www.googleapis.com/auth/cloud-platform" + // ] + // } + +} diff --git a/vendor/google.golang.org/api/internal/cert/default_cert.go b/vendor/google.golang.org/api/internal/cert/default_cert.go new file mode 100644 index 00000000000..21d0251531c --- /dev/null +++ b/vendor/google.golang.org/api/internal/cert/default_cert.go @@ -0,0 +1,58 @@ +// Copyright 2020 Google LLC. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package cert contains certificate tools for Google API clients. +// This package is intended to be used with crypto/tls.Config.GetClientCertificate. +// +// The certificates can be used to satisfy Google's Endpoint Validation. +// See https://cloud.google.com/endpoint-verification/docs/overview +// +// This package is not intended for use by end developers. Use the +// google.golang.org/api/option package to configure API clients. +package cert + +import ( + "crypto/tls" + "errors" + "sync" +) + +// defaultCertData holds all the variables pertaining to +// the default certficate source created by DefaultSource. +// +// A singleton model is used to allow the source to be reused +// by the transport layer. +type defaultCertData struct { + once sync.Once + source Source + err error +} + +var ( + defaultCert defaultCertData +) + +// Source is a function that can be passed into crypto/tls.Config.GetClientCertificate. +type Source func(*tls.CertificateRequestInfo) (*tls.Certificate, error) + +// errSourceUnavailable is a sentinel error to indicate certificate source is unavailable. +var errSourceUnavailable = errors.New("certificate source is unavailable") + +// DefaultSource returns a certificate source using the preferred EnterpriseCertificateProxySource. +// If EnterpriseCertificateProxySource is not available, fall back to the legacy SecureConnectSource. +// +// If neither source is available (due to missing configurations), a nil Source and a nil Error are +// returned to indicate that a default certificate source is unavailable. +func DefaultSource() (Source, error) { + defaultCert.once.Do(func() { + defaultCert.source, defaultCert.err = NewEnterpriseCertificateProxySource("") + if errors.Is(defaultCert.err, errSourceUnavailable) { + defaultCert.source, defaultCert.err = NewSecureConnectSource("") + if errors.Is(defaultCert.err, errSourceUnavailable) { + defaultCert.source, defaultCert.err = nil, nil + } + } + }) + return defaultCert.source, defaultCert.err +} diff --git a/vendor/google.golang.org/api/internal/cert/enterprise_cert.go b/vendor/google.golang.org/api/internal/cert/enterprise_cert.go new file mode 100644 index 00000000000..1061b5f05f3 --- /dev/null +++ b/vendor/google.golang.org/api/internal/cert/enterprise_cert.go @@ -0,0 +1,54 @@ +// Copyright 2022 Google LLC. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package cert contains certificate tools for Google API clients. +// This package is intended to be used with crypto/tls.Config.GetClientCertificate. +// +// The certificates can be used to satisfy Google's Endpoint Validation. +// See https://cloud.google.com/endpoint-verification/docs/overview +// +// This package is not intended for use by end developers. Use the +// google.golang.org/api/option package to configure API clients. +package cert + +import ( + "crypto/tls" + "errors" + + "github.com/googleapis/enterprise-certificate-proxy/client" +) + +type ecpSource struct { + key *client.Key +} + +// NewEnterpriseCertificateProxySource creates a certificate source +// using the Enterprise Certificate Proxy client, which delegates +// certifcate related operations to an OS-specific "signer binary" +// that communicates with the native keystore (ex. keychain on MacOS). +// +// The configFilePath points to a config file containing relevant parameters +// such as the certificate issuer and the location of the signer binary. +// If configFilePath is empty, the client will attempt to load the config from +// a well-known gcloud location. +func NewEnterpriseCertificateProxySource(configFilePath string) (Source, error) { + key, err := client.Cred(configFilePath) + if err != nil { + if errors.Is(err, client.ErrCredUnavailable) { + return nil, errSourceUnavailable + } + return nil, err + } + + return (&ecpSource{ + key: key, + }).getClientCertificate, nil +} + +func (s *ecpSource) getClientCertificate(info *tls.CertificateRequestInfo) (*tls.Certificate, error) { + var cert tls.Certificate + cert.PrivateKey = s.key + cert.Certificate = s.key.CertificateChain() + return &cert, nil +} diff --git a/vendor/google.golang.org/api/transport/cert/default_cert.go b/vendor/google.golang.org/api/internal/cert/secureconnect_cert.go similarity index 55% rename from vendor/google.golang.org/api/transport/cert/default_cert.go rename to vendor/google.golang.org/api/internal/cert/secureconnect_cert.go index 141ae457936..5913cab8017 100644 --- a/vendor/google.golang.org/api/transport/cert/default_cert.go +++ b/vendor/google.golang.org/api/internal/cert/secureconnect_cert.go @@ -1,4 +1,4 @@ -// Copyright 2020 Google LLC. +// Copyright 2022 Google LLC. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -32,65 +32,48 @@ const ( metadataFile = "context_aware_metadata.json" ) -// defaultCertData holds all the variables pertaining to -// the default certficate source created by DefaultSource. -type defaultCertData struct { - once sync.Once - source Source - err error - cachedCertMutex sync.Mutex - cachedCert *tls.Certificate -} - -var ( - defaultCert defaultCertData -) - -// Source is a function that can be passed into crypto/tls.Config.GetClientCertificate. -type Source func(*tls.CertificateRequestInfo) (*tls.Certificate, error) - -// DefaultSource returns a certificate source that execs the command specified -// in the file at ~/.secureConnect/context_aware_metadata.json -// -// If that file does not exist, a nil source is returned. -func DefaultSource() (Source, error) { - defaultCert.once.Do(func() { - defaultCert.source, defaultCert.err = newSecureConnectSource() - }) - return defaultCert.source, defaultCert.err -} - type secureConnectSource struct { metadata secureConnectMetadata + + // Cache the cert to avoid executing helper command repeatedly. + cachedCertMutex sync.Mutex + cachedCert *tls.Certificate } type secureConnectMetadata struct { Cmd []string `json:"cert_provider_command"` } -// newSecureConnectSource creates a secureConnectSource by reading the well-known file. -func newSecureConnectSource() (Source, error) { - user, err := user.Current() - if err != nil { - // Ignore. - return nil, nil - } - filename := filepath.Join(user.HomeDir, metadataPath, metadataFile) - file, err := ioutil.ReadFile(filename) - if os.IsNotExist(err) { - // Ignore. - return nil, nil +// NewSecureConnectSource creates a certificate source using +// the Secure Connect Helper and its associated metadata file. +// +// The configFilePath points to the location of the context aware metadata file. +// If configFilePath is empty, use the default context aware metadata location. +func NewSecureConnectSource(configFilePath string) (Source, error) { + if configFilePath == "" { + user, err := user.Current() + if err != nil { + // Error locating the default config means Secure Connect is not supported. + return nil, errSourceUnavailable + } + configFilePath = filepath.Join(user.HomeDir, metadataPath, metadataFile) } + + file, err := ioutil.ReadFile(configFilePath) if err != nil { + if errors.Is(err, os.ErrNotExist) { + // Config file missing means Secure Connect is not supported. + return nil, errSourceUnavailable + } return nil, err } var metadata secureConnectMetadata if err := json.Unmarshal(file, &metadata); err != nil { - return nil, fmt.Errorf("cert: could not parse JSON in %q: %v", filename, err) + return nil, fmt.Errorf("cert: could not parse JSON in %q: %w", configFilePath, err) } if err := validateMetadata(metadata); err != nil { - return nil, fmt.Errorf("cert: invalid config in %q: %v", filename, err) + return nil, fmt.Errorf("cert: invalid config in %q: %w", configFilePath, err) } return (&secureConnectSource{ metadata: metadata, @@ -105,22 +88,25 @@ func validateMetadata(metadata secureConnectMetadata) error { } func (s *secureConnectSource) getClientCertificate(info *tls.CertificateRequestInfo) (*tls.Certificate, error) { - defaultCert.cachedCertMutex.Lock() - defer defaultCert.cachedCertMutex.Unlock() - if defaultCert.cachedCert != nil && !isCertificateExpired(defaultCert.cachedCert) { - return defaultCert.cachedCert, nil + s.cachedCertMutex.Lock() + defer s.cachedCertMutex.Unlock() + if s.cachedCert != nil && !isCertificateExpired(s.cachedCert) { + return s.cachedCert, nil + } + // Expand OS environment variables in the cert provider command such as "$HOME". + for i := 0; i < len(s.metadata.Cmd); i++ { + s.metadata.Cmd[i] = os.ExpandEnv(s.metadata.Cmd[i]) } command := s.metadata.Cmd data, err := exec.Command(command[0], command[1:]...).Output() if err != nil { - // TODO(cbro): read stderr for error message? Might contain sensitive info. return nil, err } cert, err := tls.X509KeyPair(data, data) if err != nil { return nil, err } - defaultCert.cachedCert = &cert + s.cachedCert = &cert return &cert, nil } diff --git a/vendor/google.golang.org/api/internal/creds.go b/vendor/google.golang.org/api/internal/creds.go index c93daa98c32..63c66092203 100644 --- a/vendor/google.golang.org/api/internal/creds.go +++ b/vendor/google.golang.org/api/internal/creds.go @@ -6,9 +6,15 @@ package internal import ( "context" + "crypto/tls" "encoding/json" + "errors" "fmt" "io/ioutil" + "net" + "net/http" + "os" + "time" "golang.org/x/oauth2" "google.golang.org/api/internal/impersonate" @@ -16,6 +22,8 @@ import ( "golang.org/x/oauth2/google" ) +const quotaProjectEnvVar = "GOOGLE_CLOUD_QUOTA_PROJECT" + // Creds returns credential information obtained from DialSettings, or if none, then // it returns default credential information. func Creds(ctx context.Context, ds *DialSettings) (*google.Credentials, error) { @@ -30,6 +38,9 @@ func Creds(ctx context.Context, ds *DialSettings) (*google.Credentials, error) { } func baseCreds(ctx context.Context, ds *DialSettings) (*google.Credentials, error) { + if ds.InternalCredentials != nil { + return ds.InternalCredentials, nil + } if ds.Credentials != nil { return ds.Credentials, nil } @@ -62,54 +73,104 @@ const ( serviceAccountKey = "service_account" ) -// credentialsFromJSON returns a google.Credentials based on the input. +// credentialsFromJSON returns a google.Credentials from the JSON data +// +// - A self-signed JWT flow will be executed if the following conditions are +// met: // -// - If the JSON is a service account and no scopes provided, returns self-signed JWT auth flow -// - Otherwise, returns OAuth 2.0 flow. +// (1) At least one of the following is true: +// (a) No scope is provided +// (b) Scope for self-signed JWT flow is enabled +// (c) Audiences are explicitly provided by users +// (2) No service account impersontation +// +// - Otherwise, executes standard OAuth 2.0 flow +// More details: google.aip.dev/auth/4111 func credentialsFromJSON(ctx context.Context, data []byte, ds *DialSettings) (*google.Credentials, error) { - cred, err := google.CredentialsFromJSON(ctx, data, ds.GetScopes()...) + var params google.CredentialsParams + params.Scopes = ds.GetScopes() + + // Determine configurations for the OAuth2 transport, which is separate from the API transport. + // The OAuth2 transport and endpoint will be configured for mTLS if applicable. + clientCertSource, oauth2Endpoint, err := GetClientCertificateSourceAndEndpoint(oauth2DialSettings(ds)) if err != nil { return nil, err } - if len(data) > 0 && len(ds.Scopes) == 0 && (ds.DefaultAudience != "" || len(ds.Audiences) > 0) { - var f struct { - Type string `json:"type"` - // The rest JSON fields are omitted because they are not used. + params.TokenURL = oauth2Endpoint + if clientCertSource != nil { + tlsConfig := &tls.Config{ + GetClientCertificate: clientCertSource, } - if err := json.Unmarshal(cred.JSON, &f); err != nil { + ctx = context.WithValue(ctx, oauth2.HTTPClient, customHTTPClient(tlsConfig)) + } + + // By default, a standard OAuth 2.0 token source is created + cred, err := google.CredentialsFromJSONWithParams(ctx, data, params) + if err != nil { + return nil, err + } + + // Override the token source to use self-signed JWT if conditions are met + isJWTFlow, err := isSelfSignedJWTFlow(data, ds) + if err != nil { + return nil, err + } + if isJWTFlow { + ts, err := selfSignedJWTTokenSource(data, ds) + if err != nil { return nil, err } - if f.Type == serviceAccountKey { - ts, err := selfSignedJWTTokenSource(data, ds.DefaultAudience, ds.Audiences) - if err != nil { - return nil, err - } - cred.TokenSource = ts - } + cred.TokenSource = ts } + return cred, err } -func selfSignedJWTTokenSource(data []byte, defaultAudience string, audiences []string) (oauth2.TokenSource, error) { - audience := defaultAudience - if len(audiences) > 0 { - // TODO(shinfan): Update golang oauth to support multiple audiences. - if len(audiences) > 1 { - return nil, fmt.Errorf("multiple audiences support is not implemented") +func isSelfSignedJWTFlow(data []byte, ds *DialSettings) (bool, error) { + if (ds.EnableJwtWithScope || ds.HasCustomAudience()) && + ds.ImpersonationConfig == nil { + // Check if JSON is a service account and if so create a self-signed JWT. + var f struct { + Type string `json:"type"` + // The rest JSON fields are omitted because they are not used. } - audience = audiences[0] + if err := json.Unmarshal(data, &f); err != nil { + return false, err + } + return f.Type == serviceAccountKey, nil } - return google.JWTAccessTokenSourceFromJSON(data, audience) + return false, nil } -// QuotaProjectFromCreds returns the quota project from the JSON blob in the provided credentials. -// -// NOTE(cbro): consider promoting this to a field on google.Credentials. -func QuotaProjectFromCreds(cred *google.Credentials) string { +func selfSignedJWTTokenSource(data []byte, ds *DialSettings) (oauth2.TokenSource, error) { + if len(ds.GetScopes()) > 0 && !ds.HasCustomAudience() { + // Scopes are preferred in self-signed JWT unless the scope is not available + // or a custom audience is used. + return google.JWTAccessTokenSourceWithScope(data, ds.GetScopes()...) + } else if ds.GetAudience() != "" { + // Fallback to audience if scope is not provided + return google.JWTAccessTokenSourceFromJSON(data, ds.GetAudience()) + } else { + return nil, errors.New("neither scopes or audience are available for the self-signed JWT") + } +} + +// GetQuotaProject retrieves quota project with precedence being: client option, +// environment variable, creds file. +func GetQuotaProject(creds *google.Credentials, clientOpt string) string { + if clientOpt != "" { + return clientOpt + } + if env := os.Getenv(quotaProjectEnvVar); env != "" { + return env + } + if creds == nil { + return "" + } var v struct { QuotaProject string `json:"quota_project_id"` } - if err := json.Unmarshal(cred.JSON, &v); err != nil { + if err := json.Unmarshal(creds.JSON, &v); err != nil { return "" } return v.QuotaProject @@ -128,3 +189,35 @@ func impersonateCredentials(ctx context.Context, creds *google.Credentials, ds * ProjectID: creds.ProjectID, }, nil } + +// oauth2DialSettings returns the settings to be used by the OAuth2 transport, which is separate from the API transport. +func oauth2DialSettings(ds *DialSettings) *DialSettings { + var ods DialSettings + ods.DefaultEndpoint = google.Endpoint.TokenURL + ods.DefaultMTLSEndpoint = google.MTLSTokenURL + ods.ClientCertSource = ds.ClientCertSource + return &ods +} + +// customHTTPClient constructs an HTTPClient using the provided tlsConfig, to support mTLS. +func customHTTPClient(tlsConfig *tls.Config) *http.Client { + trans := baseTransport() + trans.TLSClientConfig = tlsConfig + return &http.Client{Transport: trans} +} + +func baseTransport() *http.Transport { + return &http.Transport{ + Proxy: http.ProxyFromEnvironment, + DialContext: (&net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + DualStack: true, + }).DialContext, + MaxIdleConns: 100, + MaxIdleConnsPerHost: 100, + IdleConnTimeout: 90 * time.Second, + TLSHandshakeTimeout: 10 * time.Second, + ExpectContinueTimeout: 1 * time.Second, + } +} diff --git a/vendor/google.golang.org/api/transport/internal/dca/dca.go b/vendor/google.golang.org/api/internal/dca.go similarity index 78% rename from vendor/google.golang.org/api/transport/internal/dca/dca.go rename to vendor/google.golang.org/api/internal/dca.go index b3be7e4e3a7..204a3fd2f3f 100644 --- a/vendor/google.golang.org/api/transport/internal/dca/dca.go +++ b/vendor/google.golang.org/api/internal/dca.go @@ -6,32 +6,33 @@ // Authentication according to https://google.aip.dev/auth/4114 // // The overall logic for DCA is as follows: -// 1. If both endpoint override and client certificate are specified, use them as is. -// 2. If user does not specify client certificate, we will attempt to use default -// client certificate. -// 3. If user does not specify endpoint override, we will use defaultMtlsEndpoint if -// client certificate is available and defaultEndpoint otherwise. +// 1. If both endpoint override and client certificate are specified, use them as is. +// 2. If user does not specify client certificate, we will attempt to use default +// client certificate. +// 3. If user does not specify endpoint override, we will use defaultMtlsEndpoint if +// client certificate is available and defaultEndpoint otherwise. // // Implications of the above logic: -// 1. If the user specifies a non-mTLS endpoint override but client certificate is -// available, we will pass along the cert anyway and let the server decide what to do. -// 2. If the user specifies an mTLS endpoint override but client certificate is not -// available, we will not fail-fast, but let backend throw error when connecting. +// 1. If the user specifies a non-mTLS endpoint override but client certificate is +// available, we will pass along the cert anyway and let the server decide what to do. +// 2. If the user specifies an mTLS endpoint override but client certificate is not +// available, we will not fail-fast, but let backend throw error when connecting. // // We would like to avoid introducing client-side logic that parses whether the // endpoint override is an mTLS url, since the url pattern may change at anytime. // // This package is not intended for use by end developers. Use the // google.golang.org/api/option package to configure API clients. -package dca + +// Package internal supports the options and transport packages. +package internal import ( "net/url" "os" "strings" - "google.golang.org/api/internal" - "google.golang.org/api/transport/cert" + "google.golang.org/api/internal/cert" ) const ( @@ -43,7 +44,7 @@ const ( // GetClientCertificateSourceAndEndpoint is a convenience function that invokes // getClientCertificateSource and getEndpoint sequentially and returns the client // cert source and endpoint as a tuple. -func GetClientCertificateSourceAndEndpoint(settings *internal.DialSettings) (cert.Source, string, error) { +func GetClientCertificateSourceAndEndpoint(settings *DialSettings) (cert.Source, string, error) { clientCertSource, err := getClientCertificateSource(settings) if err != nil { return nil, "", err @@ -65,11 +66,9 @@ func GetClientCertificateSourceAndEndpoint(settings *internal.DialSettings) (cer // Important Note: For now, the environment variable GOOGLE_API_USE_CLIENT_CERTIFICATE // must be set to "true" to allow certificate to be used (including user provided // certificates). For details, see AIP-4114. -func getClientCertificateSource(settings *internal.DialSettings) (cert.Source, error) { +func getClientCertificateSource(settings *DialSettings) (cert.Source, error) { if !isClientCertificateEnabled() { return nil, nil - } else if settings.HTTPClient != nil { - return nil, nil // HTTPClient is incompatible with ClientCertificateSource } else if settings.ClientCertSource != nil { return settings.ClientCertSource, nil } else { @@ -96,7 +95,7 @@ func isClientCertificateEnabled() bool { // URL (ex. https://...), then the user-provided address will be merged into // the default endpoint. For example, WithEndpoint("myhost:8000") and // WithDefaultEndpoint("https://foo.com/bar/baz") will return "https://myhost:8080/bar/baz" -func getEndpoint(settings *internal.DialSettings, clientCertSource cert.Source) (string, error) { +func getEndpoint(settings *DialSettings, clientCertSource cert.Source) (string, error) { if settings.Endpoint == "" { mtlsMode := getMTLSMode() if mtlsMode == mTLSModeAlways || (clientCertSource != nil && mtlsMode == mTLSModeAuto) { diff --git a/vendor/google.golang.org/api/internal/gensupport/error.go b/vendor/google.golang.org/api/internal/gensupport/error.go new file mode 100644 index 00000000000..886c6532b15 --- /dev/null +++ b/vendor/google.golang.org/api/internal/gensupport/error.go @@ -0,0 +1,24 @@ +// Copyright 2022 Google LLC. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package gensupport + +import ( + "errors" + + "github.com/googleapis/gax-go/v2/apierror" + "google.golang.org/api/googleapi" +) + +// WrapError creates an [apierror.APIError] from err, wraps it in err, and +// returns err. If err is not a [googleapi.Error] (or a +// [google.golang.org/grpc/status.Status]), it returns err without modification. +func WrapError(err error) error { + var herr *googleapi.Error + apiError, ok := apierror.ParseError(err, false) + if ok && errors.As(err, &herr) { + herr.Wrap(apiError) + } + return err +} diff --git a/vendor/google.golang.org/api/internal/gensupport/json.go b/vendor/google.golang.org/api/internal/gensupport/json.go index c01e32189f4..eab49a11eb1 100644 --- a/vendor/google.golang.org/api/internal/gensupport/json.go +++ b/vendor/google.golang.org/api/internal/gensupport/json.go @@ -13,9 +13,10 @@ import ( // MarshalJSON returns a JSON encoding of schema containing only selected fields. // A field is selected if any of the following is true: -// * it has a non-empty value -// * its field name is present in forceSendFields and it is not a nil pointer or nil interface -// * its field name is present in nullFields. +// - it has a non-empty value +// - its field name is present in forceSendFields and it is not a nil pointer or nil interface +// - its field name is present in nullFields. +// // The JSON key for each selected field is taken from the field's json: struct tag. func MarshalJSON(schema interface{}, forceSendFields, nullFields []string) ([]byte, error) { if len(forceSendFields) == 0 && len(nullFields) == 0 { @@ -85,7 +86,12 @@ func schemaToMap(schema interface{}, mustInclude, useNull map[string]bool, useNu if f.Type.Kind() == reflect.Map && useNullMaps[f.Name] != nil { ms, ok := v.Interface().(map[string]string) if !ok { - return nil, fmt.Errorf("field %q has keys in NullFields but is not a map[string]string", f.Name) + mi, err := initMapSlow(v, f.Name, useNullMaps) + if err != nil { + return nil, err + } + m[tag.apiName] = mi + continue } mi := map[string]interface{}{} for k, v := range ms { @@ -119,6 +125,25 @@ func schemaToMap(schema interface{}, mustInclude, useNull map[string]bool, useNu return m, nil } +// initMapSlow uses reflection to build up a map object. This is slower than +// the default behavior so it should be used only as a fallback. +func initMapSlow(rv reflect.Value, fieldName string, useNullMaps map[string]map[string]bool) (map[string]interface{}, error) { + mi := map[string]interface{}{} + iter := rv.MapRange() + for iter.Next() { + k, ok := iter.Key().Interface().(string) + if !ok { + return nil, fmt.Errorf("field %q has keys in NullFields but is not a map[string]any", fieldName) + } + v := iter.Value().Interface() + mi[k] = v + } + for k := range useNullMaps[fieldName] { + mi[k] = nil + } + return mi, nil +} + // formatAsString returns a string representation of v, dereferencing it first if possible. func formatAsString(v reflect.Value, kind reflect.Kind) string { if kind == reflect.Ptr && !v.IsNil() { diff --git a/vendor/google.golang.org/api/internal/gensupport/media.go b/vendor/google.golang.org/api/internal/gensupport/media.go index 0460ab59406..8356e7f27b0 100644 --- a/vendor/google.golang.org/api/internal/gensupport/media.go +++ b/vendor/google.golang.org/api/internal/gensupport/media.go @@ -15,93 +15,12 @@ import ( "net/textproto" "strings" "sync" + "time" + gax "github.com/googleapis/gax-go/v2" "google.golang.org/api/googleapi" ) -const sniffBuffSize = 512 - -func newContentSniffer(r io.Reader) *contentSniffer { - return &contentSniffer{r: r} -} - -// contentSniffer wraps a Reader, and reports the content type determined by sniffing up to 512 bytes from the Reader. -type contentSniffer struct { - r io.Reader - start []byte // buffer for the sniffed bytes. - err error // set to any error encountered while reading bytes to be sniffed. - - ctype string // set on first sniff. - sniffed bool // set to true on first sniff. -} - -func (cs *contentSniffer) Read(p []byte) (n int, err error) { - // Ensure that the content type is sniffed before any data is consumed from Reader. - _, _ = cs.ContentType() - - if len(cs.start) > 0 { - n := copy(p, cs.start) - cs.start = cs.start[n:] - return n, nil - } - - // We may have read some bytes into start while sniffing, even if the read ended in an error. - // We should first return those bytes, then the error. - if cs.err != nil { - return 0, cs.err - } - - // Now we have handled all bytes that were buffered while sniffing. Now just delegate to the underlying reader. - return cs.r.Read(p) -} - -// ContentType returns the sniffed content type, and whether the content type was successfully sniffed. -func (cs *contentSniffer) ContentType() (string, bool) { - if cs.sniffed { - return cs.ctype, cs.ctype != "" - } - cs.sniffed = true - // If ReadAll hits EOF, it returns err==nil. - cs.start, cs.err = ioutil.ReadAll(io.LimitReader(cs.r, sniffBuffSize)) - - // Don't try to detect the content type based on possibly incomplete data. - if cs.err != nil { - return "", false - } - - cs.ctype = http.DetectContentType(cs.start) - return cs.ctype, true -} - -// DetermineContentType determines the content type of the supplied reader. -// If the content type is already known, it can be specified via ctype. -// Otherwise, the content of media will be sniffed to determine the content type. -// If media implements googleapi.ContentTyper (deprecated), this will be used -// instead of sniffing the content. -// After calling DetectContentType the caller must not perform further reads on -// media, but rather read from the Reader that is returned. -func DetermineContentType(media io.Reader, ctype string) (io.Reader, string) { - // Note: callers could avoid calling DetectContentType if ctype != "", - // but doing the check inside this function reduces the amount of - // generated code. - if ctype != "" { - return media, ctype - } - - // For backwards compatibility, allow clients to set content - // type by providing a ContentTyper for media. - if typer, ok := media.(googleapi.ContentTyper); ok { - return media, typer.ContentType() - } - - sniffer := newContentSniffer(media) - if ctype, ok := sniffer.ContentType(); ok { - return sniffer, ctype - } - // If content type could not be sniffed, reads from sniffer will eventually fail with an error. - return sniffer, "" -} - type typeReader struct { io.Reader typ string @@ -217,12 +136,13 @@ func PrepareUpload(media io.Reader, chunkSize int) (r io.Reader, mb *MediaBuffer // code only. type MediaInfo struct { // At most one of Media and MediaBuffer will be set. - media io.Reader - buffer *MediaBuffer - singleChunk bool - mType string - size int64 // mediaSize, if known. Used only for calls to progressUpdater_. - progressUpdater googleapi.ProgressUpdater + media io.Reader + buffer *MediaBuffer + singleChunk bool + mType string + size int64 // mediaSize, if known. Used only for calls to progressUpdater_. + progressUpdater googleapi.ProgressUpdater + chunkRetryDeadline time.Duration } // NewInfoFromMedia should be invoked from the Media method of a call. It returns a @@ -232,8 +152,12 @@ func NewInfoFromMedia(r io.Reader, options []googleapi.MediaOption) *MediaInfo { mi := &MediaInfo{} opts := googleapi.ProcessMediaOptions(options) if !opts.ForceEmptyContentType { - r, mi.mType = DetermineContentType(r, opts.ContentType) + mi.mType = opts.ContentType + if mi.mType == "" { + r, mi.mType = gax.DetermineContentType(r) + } } + mi.chunkRetryDeadline = opts.ChunkRetryDeadline mi.media, mi.buffer, mi.singleChunk = PrepareUpload(r, opts.ChunkSize) return mi } @@ -242,7 +166,11 @@ func NewInfoFromMedia(r io.Reader, options []googleapi.MediaOption) *MediaInfo { // call. It returns a MediaInfo using the given reader, size and media type. func NewInfoFromResumableMedia(r io.ReaderAt, size int64, mediaType string) *MediaInfo { rdr := ReaderAtToReader(r, size) - rdr, mType := DetermineContentType(rdr, mediaType) + mType := mediaType + if mType == "" { + rdr, mType = gax.DetermineContentType(rdr) + } + return &MediaInfo{ size: size, mType: mType, @@ -286,13 +214,12 @@ func (mi *MediaInfo) UploadRequest(reqHeaders http.Header, body io.Reader) (newB // be retried because the data is stored in the MediaBuffer. media, _, _, _ = mi.buffer.Chunk() } + toCleanup := []io.Closer{} if media != nil { fb := readerFunc(body) fm := readerFunc(media) combined, ctype := CombineBodyMedia(body, "application/json", media, mi.mType) - toCleanup := []io.Closer{ - combined, - } + toCleanup = append(toCleanup, combined) if fb != nil && fm != nil { getBody = func() (io.ReadCloser, error) { rb := ioutil.NopCloser(fb()) @@ -306,18 +233,30 @@ func (mi *MediaInfo) UploadRequest(reqHeaders http.Header, body io.Reader) (newB return r, nil } } - cleanup = func() { - for _, closer := range toCleanup { - _ = closer.Close() - } - - } reqHeaders.Set("Content-Type", ctype) body = combined } if mi.buffer != nil && mi.mType != "" && !mi.singleChunk { + // This happens when initiating a resumable upload session. + // The initial request contains a JSON body rather than media. + // It can be retried with a getBody function that re-creates the request body. + fb := readerFunc(body) + if fb != nil { + getBody = func() (io.ReadCloser, error) { + rb := ioutil.NopCloser(fb()) + toCleanup = append(toCleanup, rb) + return rb, nil + } + } reqHeaders.Set("X-Upload-Content-Type", mi.mType) } + // Ensure that any bodies created in getBody are cleaned up. + cleanup = func() { + for _, closer := range toCleanup { + _ = closer.Close() + } + + } return body, getBody, cleanup } @@ -356,6 +295,7 @@ func (mi *MediaInfo) ResumableUpload(locURI string) *ResumableUpload { mi.progressUpdater(curr, mi.size) } }, + ChunkRetryDeadline: mi.chunkRetryDeadline, } } diff --git a/vendor/google.golang.org/api/internal/gensupport/params.go b/vendor/google.golang.org/api/internal/gensupport/params.go index 0e878a4255b..1a30d2ca252 100644 --- a/vendor/google.golang.org/api/internal/gensupport/params.go +++ b/vendor/google.golang.org/api/internal/gensupport/params.go @@ -37,15 +37,21 @@ func (u URLParams) SetMulti(key string, values []string) { u[key] = values } -// Encode encodes the values into ``URL encoded'' form +// Encode encodes the values into “URL encoded” form // ("bar=baz&foo=quux") sorted by key. func (u URLParams) Encode() string { return url.Values(u).Encode() } -// SetOptions sets the URL params and any additional call options. +// SetOptions sets the URL params and any additional `CallOption` or +// `MultiCallOption` passed in. func SetOptions(u URLParams, opts ...googleapi.CallOption) { for _, o := range opts { + m, ok := o.(googleapi.MultiCallOption) + if ok { + u.SetMulti(m.GetMulti()) + continue + } u.Set(o.Get()) } } diff --git a/vendor/google.golang.org/api/internal/gensupport/resumable.go b/vendor/google.golang.org/api/internal/gensupport/resumable.go index edc87ec24f6..f168ea6d2b7 100644 --- a/vendor/google.golang.org/api/internal/gensupport/resumable.go +++ b/vendor/google.golang.org/api/internal/gensupport/resumable.go @@ -10,34 +10,12 @@ import ( "fmt" "io" "net/http" + "strings" "sync" "time" - gax "github.com/googleapis/gax-go/v2" -) - -// Backoff is an interface around gax.Backoff's Pause method, allowing tests to provide their -// own implementation. -type Backoff interface { - Pause() time.Duration -} - -// These are declared as global variables so that tests can overwrite them. -var ( - retryDeadline = 32 * time.Second - backoff = func() Backoff { - return &gax.Backoff{Initial: 100 * time.Millisecond} - } - // isRetryable is a platform-specific hook, specified in retryable_linux.go - syscallRetryable func(error) bool = func(err error) bool { return false } -) - -const ( - // statusTooManyRequests is returned by the storage API if the - // per-project limits have been temporarily exceeded. The request - // should be retried. - // https://cloud.google.com/storage/docs/json_api/v1/status-codes#standardcodes - statusTooManyRequests = 429 + "github.com/google/uuid" + "google.golang.org/api/internal" ) // ResumableUpload is used by the generated APIs to provide resumable uploads. @@ -57,6 +35,18 @@ type ResumableUpload struct { // Callback is an optional function that will be periodically called with the cumulative number of bytes uploaded. Callback func(int64) + + // Retry optionally configures retries for requests made against the upload. + Retry *RetryConfig + + // ChunkRetryDeadline configures the per-chunk deadline after which no further + // retries should happen. + ChunkRetryDeadline time.Duration + + // Track current request invocation ID and attempt count for retry metric + // headers. + invocationID string + attempts int } // Progress returns the number of bytes uploaded at this point. @@ -91,6 +81,10 @@ func (rx *ResumableUpload) doUploadRequest(ctx context.Context, data io.Reader, req.Header.Set("Content-Type", rx.MediaType) req.Header.Set("User-Agent", rx.UserAgent) + baseXGoogHeader := "gl-go/" + GoVersion() + " gdcl/" + internal.Version + invocationHeader := fmt.Sprintf("gccl-invocation-id/%s gccl-attempt-count/%d", rx.invocationID, rx.attempts) + req.Header.Set("X-Goog-Api-Client", strings.Join([]string{baseXGoogHeader, invocationHeader}, " ")) + // Google's upload endpoint uses status code 308 for a // different purpose than the "308 Permanent Redirect" // since-standardized in RFC 7238. Because of the conflict in @@ -174,29 +168,69 @@ func (rx *ResumableUpload) Upload(ctx context.Context) (resp *http.Response, err } return nil, err } + // This case is very unlikely but possible only if rx.ChunkRetryDeadline is + // set to a very small value, in which case no requests will be sent before + // the deadline. Return an error to avoid causing a panic. + if resp == nil { + return nil, fmt.Errorf("upload request to %v not sent, choose larger value for ChunkRetryDealine", rx.URI) + } return resp, nil } + // Configure retryable error criteria. + errorFunc := rx.Retry.errorFunc() + + // Configure per-chunk retry deadline. + var retryDeadline time.Duration + if rx.ChunkRetryDeadline != 0 { + retryDeadline = rx.ChunkRetryDeadline + } else { + retryDeadline = defaultRetryDeadline + } // Send all chunks. for { var pause time.Duration - // Each chunk gets its own initialized-at-zero retry. - bo := backoff() - quitAfter := time.After(retryDeadline) + // Each chunk gets its own initialized-at-zero backoff and invocation ID. + bo := rx.Retry.backoff() + quitAfterTimer := time.NewTimer(retryDeadline) + rx.attempts = 1 + rx.invocationID = uuid.New().String() // Retry loop for a single chunk. for { + pauseTimer := time.NewTimer(pause) select { case <-ctx.Done(): + quitAfterTimer.Stop() + pauseTimer.Stop() if err == nil { err = ctx.Err() } return prepareReturn(resp, err) - case <-time.After(pause): - case <-quitAfter: + case <-pauseTimer.C: + case <-quitAfterTimer.C: + pauseTimer.Stop() return prepareReturn(resp, err) } + pauseTimer.Stop() + + // Check for context cancellation or timeout once more. If more than one + // case in the select statement above was satisfied at the same time, Go + // will choose one arbitrarily. + // That can cause an operation to go through even if the context was + // canceled before or the timeout was reached. + select { + case <-ctx.Done(): + quitAfterTimer.Stop() + if err == nil { + err = ctx.Err() + } + return prepareReturn(resp, err) + case <-quitAfterTimer.C: + return prepareReturn(resp, err) + default: + } resp, err = rx.transferChunk(ctx) @@ -206,10 +240,12 @@ func (rx *ResumableUpload) Upload(ctx context.Context) (resp *http.Response, err } // Check if we should retry the request. - if !shouldRetry(status, err) { + if !errorFunc(status, err) { + quitAfterTimer.Stop() break } + rx.attempts++ pause = bo.Pause() if resp != nil && resp.Body != nil { resp.Body.Close() @@ -226,33 +262,3 @@ func (rx *ResumableUpload) Upload(ctx context.Context) (resp *http.Response, err return prepareReturn(resp, err) } } - -// shouldRetry indicates whether an error is retryable for the purposes of this -// package, following guidance from -// https://cloud.google.com/storage/docs/exponential-backoff . -func shouldRetry(status int, err error) bool { - if 500 <= status && status <= 599 { - return true - } - if status == statusTooManyRequests { - return true - } - if err == io.ErrUnexpectedEOF { - return true - } - // Transient network errors should be retried. - if syscallRetryable(err) { - return true - } - if err, ok := err.(interface{ Temporary() bool }); ok { - if err.Temporary() { - return true - } - } - // If Go 1.13 error unwrapping is available, use this to examine wrapped - // errors. - if err, ok := err.(interface{ Unwrap() error }); ok { - return shouldRetry(status, err.Unwrap()) - } - return false -} diff --git a/vendor/google.golang.org/api/internal/gensupport/retry.go b/vendor/google.golang.org/api/internal/gensupport/retry.go new file mode 100644 index 00000000000..20b57d925f1 --- /dev/null +++ b/vendor/google.golang.org/api/internal/gensupport/retry.go @@ -0,0 +1,121 @@ +// Copyright 2021 Google LLC. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package gensupport + +import ( + "errors" + "io" + "net" + "strings" + "time" + + "github.com/googleapis/gax-go/v2" + "google.golang.org/api/googleapi" +) + +// Backoff is an interface around gax.Backoff's Pause method, allowing tests to provide their +// own implementation. +type Backoff interface { + Pause() time.Duration +} + +// These are declared as global variables so that tests can overwrite them. +var ( + // Default per-chunk deadline for resumable uploads. + defaultRetryDeadline = 32 * time.Second + // Default backoff timer. + backoff = func() Backoff { + return &gax.Backoff{Initial: 100 * time.Millisecond} + } + // syscallRetryable is a platform-specific hook, specified in retryable_linux.go + syscallRetryable func(error) bool = func(err error) bool { return false } +) + +const ( + // statusTooManyRequests is returned by the storage API if the + // per-project limits have been temporarily exceeded. The request + // should be retried. + // https://cloud.google.com/storage/docs/json_api/v1/status-codes#standardcodes + statusTooManyRequests = 429 + + // statusRequestTimeout is returned by the storage API if the + // upload connection was broken. The request should be retried. + statusRequestTimeout = 408 +) + +// shouldRetry indicates whether an error is retryable for the purposes of this +// package, unless a ShouldRetry func is specified by the RetryConfig instead. +// It follows guidance from +// https://cloud.google.com/storage/docs/exponential-backoff . +func shouldRetry(status int, err error) bool { + if 500 <= status && status <= 599 { + return true + } + if status == statusTooManyRequests || status == statusRequestTimeout { + return true + } + if err == io.ErrUnexpectedEOF { + return true + } + // Transient network errors should be retried. + if syscallRetryable(err) { + return true + } + if err, ok := err.(interface{ Temporary() bool }); ok { + if err.Temporary() { + return true + } + } + var opErr *net.OpError + if errors.As(err, &opErr) { + if strings.Contains(opErr.Error(), "use of closed network connection") { + // TODO: check against net.ErrClosed (go 1.16+) instead of string + return true + } + } + + // If Go 1.13 error unwrapping is available, use this to examine wrapped + // errors. + if err, ok := err.(interface{ Unwrap() error }); ok { + return shouldRetry(status, err.Unwrap()) + } + return false +} + +// RetryConfig allows configuration of backoff timing and retryable errors. +type RetryConfig struct { + Backoff *gax.Backoff + ShouldRetry func(err error) bool +} + +// Get a new backoff object based on the configured values. +func (r *RetryConfig) backoff() Backoff { + if r == nil || r.Backoff == nil { + return backoff() + } + return &gax.Backoff{ + Initial: r.Backoff.Initial, + Max: r.Backoff.Max, + Multiplier: r.Backoff.Multiplier, + } +} + +// This is kind of hacky; it is necessary because ShouldRetry expects to +// handle HTTP errors via googleapi.Error, but the error has not yet been +// wrapped with a googleapi.Error at this layer, and the ErrorFunc type +// in the manual layer does not pass in a status explicitly as it does +// here. So, we must wrap error status codes in a googleapi.Error so that +// ShouldRetry can parse this correctly. +func (r *RetryConfig) errorFunc() func(status int, err error) bool { + if r == nil || r.ShouldRetry == nil { + return shouldRetry + } + return func(status int, err error) bool { + if status >= 400 { + return r.ShouldRetry(&googleapi.Error{Code: status}) + } + return r.ShouldRetry(err) + } +} diff --git a/vendor/google.golang.org/api/internal/gensupport/retryable_linux.go b/vendor/google.golang.org/api/internal/gensupport/retryable_linux.go index fed998b5d07..a916c3da29b 100644 --- a/vendor/google.golang.org/api/internal/gensupport/retryable_linux.go +++ b/vendor/google.golang.org/api/internal/gensupport/retryable_linux.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux // +build linux package gensupport diff --git a/vendor/google.golang.org/api/internal/gensupport/send.go b/vendor/google.golang.org/api/internal/gensupport/send.go index 3338c8d193a..85c7bcbfdfc 100644 --- a/vendor/google.golang.org/api/internal/gensupport/send.go +++ b/vendor/google.golang.org/api/internal/gensupport/send.go @@ -8,25 +8,34 @@ import ( "context" "encoding/json" "errors" + "fmt" "net/http" + "strings" "time" + + "github.com/google/uuid" + "github.com/googleapis/gax-go/v2" ) -// Hook is the type of a function that is called once before each HTTP request -// that is sent by a generated API. It returns a function that is called after -// the request returns. -// Hooks are not called if the context is nil. -type Hook func(ctx context.Context, req *http.Request) func(resp *http.Response) - -var hooks []Hook - -// RegisterHook registers a Hook to be called before each HTTP request by a -// generated API. Hooks are called in the order they are registered. Each -// hook can return a function; if it is non-nil, it is called after the HTTP -// request returns. These functions are called in the reverse order. -// RegisterHook should not be called concurrently with itself or SendRequest. -func RegisterHook(h Hook) { - hooks = append(hooks, h) +// Use this error type to return an error which allows introspection of both +// the context error and the error from the service. +type wrappedCallErr struct { + ctxErr error + wrappedErr error +} + +func (e wrappedCallErr) Error() string { + return fmt.Sprintf("retry failed with %v; last error: %v", e.ctxErr, e.wrappedErr) +} + +func (e wrappedCallErr) Unwrap() error { + return e.wrappedErr +} + +// Is allows errors.Is to match the error from the call as well as context +// sentinel errors. +func (e wrappedCallErr) Is(target error) bool { + return errors.Is(e.ctxErr, target) || errors.Is(e.wrappedErr, target) } // SendRequest sends a single HTTP request using the given client. @@ -42,23 +51,7 @@ func SendRequest(ctx context.Context, client *http.Client, req *http.Request) (* if ctx == nil { return client.Do(req) } - // Call hooks in order of registration, store returned funcs. - post := make([]func(resp *http.Response), len(hooks)) - for i, h := range hooks { - fn := h(ctx, req) - post[i] = fn - } - - // Send request. - resp, err := send(ctx, client, req) - - // Call returned funcs in reverse order. - for i := len(post) - 1; i >= 0; i-- { - if fn := post[i]; fn != nil { - fn(resp) - } - } - return resp, err + return send(ctx, client, req) } func send(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) { @@ -83,7 +76,7 @@ func send(ctx context.Context, client *http.Client, req *http.Request) (*http.Re // If ctx is non-nil, it calls all hooks, then sends the request with // req.WithContext, then calls any functions returned by the hooks in // reverse order. -func SendRequestWithRetry(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) { +func SendRequestWithRetry(ctx context.Context, client *http.Client, req *http.Request, retry *RetryConfig) (*http.Response, error) { // Disallow Accept-Encoding because it interferes with the automatic gzip handling // done by the default http.Transport. See https://github.com/google/google-api-go-client/issues/219. if _, ok := req.Header["Accept-Encoding"]; ok { @@ -92,48 +85,62 @@ func SendRequestWithRetry(ctx context.Context, client *http.Client, req *http.Re if ctx == nil { return client.Do(req) } - // Call hooks in order of registration, store returned funcs. - post := make([]func(resp *http.Response), len(hooks)) - for i, h := range hooks { - fn := h(ctx, req) - post[i] = fn - } - - // Send request with retry. - resp, err := sendAndRetry(ctx, client, req) - - // Call returned funcs in reverse order. - for i := len(post) - 1; i >= 0; i-- { - if fn := post[i]; fn != nil { - fn(resp) - } - } - return resp, err + return sendAndRetry(ctx, client, req, retry) } -func sendAndRetry(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) { +func sendAndRetry(ctx context.Context, client *http.Client, req *http.Request, retry *RetryConfig) (*http.Response, error) { if client == nil { client = http.DefaultClient } var resp *http.Response var err error + attempts := 1 + invocationID := uuid.New().String() + baseXGoogHeader := req.Header.Get("X-Goog-Api-Client") // Loop to retry the request, up to the context deadline. var pause time.Duration - bo := backoff() + var bo Backoff + if retry != nil && retry.Backoff != nil { + bo = &gax.Backoff{ + Initial: retry.Backoff.Initial, + Max: retry.Backoff.Max, + Multiplier: retry.Backoff.Multiplier, + } + } else { + bo = backoff() + } + + var errorFunc = retry.errorFunc() for { + t := time.NewTimer(pause) select { case <-ctx.Done(): - // If we got an error, and the context has been canceled, - // the context's error is probably more useful. - if err == nil { - err = ctx.Err() + t.Stop() + // If we got an error and the context has been canceled, return an error acknowledging + // both the context cancelation and the service error. + if err != nil { + return resp, wrappedCallErr{ctx.Err(), err} + } + return resp, ctx.Err() + case <-t.C: + } + + if ctx.Err() != nil { + // Check for context cancellation once more. If more than one case in a + // select is satisfied at the same time, Go will choose one arbitrarily. + // That can cause an operation to go through even if the context was + // canceled before. + if err != nil { + return resp, wrappedCallErr{ctx.Err(), err} } - return resp, err - case <-time.After(pause): + return resp, ctx.Err() } + invocationHeader := fmt.Sprintf("gccl-invocation-id/%s gccl-attempt-count/%d", invocationID, attempts) + xGoogHeader := strings.Join([]string{invocationHeader, baseXGoogHeader}, " ") + req.Header.Set("X-Goog-Api-Client", xGoogHeader) resp, err = client.Do(req.WithContext(ctx)) @@ -145,9 +152,10 @@ func sendAndRetry(ctx context.Context, client *http.Client, req *http.Request) ( // Check if we can retry the request. A retry can only be done if the error // is retryable and the request body can be re-created using GetBody (this // will not be possible if the body was unbuffered). - if req.GetBody == nil || !shouldRetry(status, err) { + if req.GetBody == nil || !errorFunc(status, err) { break } + attempts++ var errBody error req.Body, errBody = req.GetBody() if errBody != nil { diff --git a/vendor/google.golang.org/api/internal/settings.go b/vendor/google.golang.org/api/internal/settings.go index 0ae1cb9778d..76efdb22772 100644 --- a/vendor/google.golang.org/api/internal/settings.go +++ b/vendor/google.golang.org/api/internal/settings.go @@ -19,31 +19,34 @@ import ( // DialSettings holds information needed to establish a connection with a // Google API service. type DialSettings struct { - Endpoint string - DefaultEndpoint string - DefaultMTLSEndpoint string - Scopes []string - DefaultScopes []string - TokenSource oauth2.TokenSource - Credentials *google.Credentials - CredentialsFile string // if set, Token Source is ignored. - CredentialsJSON []byte - UserAgent string - APIKey string - Audiences []string - DefaultAudience string - HTTPClient *http.Client - GRPCDialOpts []grpc.DialOption - GRPCConn *grpc.ClientConn - GRPCConnPool ConnPool - GRPCConnPoolSize int - NoAuth bool - TelemetryDisabled bool - ClientCertSource func(*tls.CertificateRequestInfo) (*tls.Certificate, error) - CustomClaims map[string]interface{} - SkipValidation bool - ImpersonationConfig *impersonate.Config - EnableDirectPath bool + Endpoint string + DefaultEndpoint string + DefaultMTLSEndpoint string + Scopes []string + DefaultScopes []string + EnableJwtWithScope bool + TokenSource oauth2.TokenSource + Credentials *google.Credentials + CredentialsFile string // if set, Token Source is ignored. + CredentialsJSON []byte + InternalCredentials *google.Credentials + UserAgent string + APIKey string + Audiences []string + DefaultAudience string + HTTPClient *http.Client + GRPCDialOpts []grpc.DialOption + GRPCConn *grpc.ClientConn + GRPCConnPool ConnPool + GRPCConnPoolSize int + NoAuth bool + TelemetryDisabled bool + ClientCertSource func(*tls.CertificateRequestInfo) (*tls.Certificate, error) + CustomClaims map[string]interface{} + SkipValidation bool + ImpersonationConfig *impersonate.Config + EnableDirectPath bool + AllowNonDefaultServiceAccount bool // Google API system parameters. For more information please read: // https://cloud.google.com/apis/docs/system-parameters @@ -60,6 +63,19 @@ func (ds *DialSettings) GetScopes() []string { return ds.DefaultScopes } +// GetAudience returns the user-provided audience, if set, or else falls back to the default audience. +func (ds *DialSettings) GetAudience() string { + if ds.HasCustomAudience() { + return ds.Audiences[0] + } + return ds.DefaultAudience +} + +// HasCustomAudience returns true if a custom audience is provided by users. +func (ds *DialSettings) HasCustomAudience() bool { + return len(ds.Audiences) > 0 +} + // Validate reports an error if ds is invalid. func (ds *DialSettings) Validate() error { if ds.SkipValidation { diff --git a/vendor/google.golang.org/api/internal/version.go b/vendor/google.golang.org/api/internal/version.go new file mode 100644 index 00000000000..7a4f6d8982e --- /dev/null +++ b/vendor/google.golang.org/api/internal/version.go @@ -0,0 +1,8 @@ +// Copyright 2022 Google LLC. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package internal + +// Version is the current tagged release of the library. +const Version = "0.114.0" diff --git a/vendor/google.golang.org/api/option/credentials_go19.go b/vendor/google.golang.org/api/option/credentials_go19.go deleted file mode 100644 index d06f918b0e6..00000000000 --- a/vendor/google.golang.org/api/option/credentials_go19.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2018 Google LLC. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build go1.9 - -package option - -import ( - "golang.org/x/oauth2/google" - "google.golang.org/api/internal" -) - -type withCreds google.Credentials - -func (w *withCreds) Apply(o *internal.DialSettings) { - o.Credentials = (*google.Credentials)(w) -} - -// WithCredentials returns a ClientOption that authenticates API calls. -func WithCredentials(creds *google.Credentials) ClientOption { - return (*withCreds)(creds) -} diff --git a/vendor/google.golang.org/api/option/credentials_notgo19.go b/vendor/google.golang.org/api/option/credentials_notgo19.go deleted file mode 100644 index 0ce107a624a..00000000000 --- a/vendor/google.golang.org/api/option/credentials_notgo19.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2018 Google LLC. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !go1.9 - -package option - -import ( - "golang.org/x/oauth2/google" - "google.golang.org/api/internal" -) - -type withCreds google.DefaultCredentials - -func (w *withCreds) Apply(o *internal.DialSettings) { - o.Credentials = (*google.DefaultCredentials)(w) -} - -func WithCredentials(creds *google.DefaultCredentials) ClientOption { - return (*withCreds)(creds) -} diff --git a/vendor/google.golang.org/api/option/internaloption/internaloption.go b/vendor/google.golang.org/api/option/internaloption/internaloption.go index 1fff22fd5da..cc7ebfe277b 100644 --- a/vendor/google.golang.org/api/option/internaloption/internaloption.go +++ b/vendor/google.golang.org/api/option/internaloption/internaloption.go @@ -6,6 +6,7 @@ package internaloption import ( + "golang.org/x/oauth2/google" "google.golang.org/api/internal" "google.golang.org/api/option" ) @@ -66,6 +67,21 @@ func (e enableDirectPath) Apply(o *internal.DialSettings) { o.EnableDirectPath = bool(e) } +// AllowNonDefaultServiceAccount returns a ClientOption that overrides the default +// requirement for using the default service account for DirectPath. +// +// It should only be used internally by generated clients. +// This is an EXPERIMENTAL API and may be changed or removed in the future. +func AllowNonDefaultServiceAccount(nd bool) option.ClientOption { + return allowNonDefaultServiceAccount(nd) +} + +type allowNonDefaultServiceAccount bool + +func (a allowNonDefaultServiceAccount) Apply(o *internal.DialSettings) { + o.AllowNonDefaultServiceAccount = bool(a) +} + // WithDefaultAudience returns a ClientOption that specifies a default audience // to be used as the audience field ("aud") for the JWT token authentication. // @@ -94,3 +110,34 @@ func (w withDefaultScopes) Apply(o *internal.DialSettings) { o.DefaultScopes = make([]string, len(w)) copy(o.DefaultScopes, w) } + +// EnableJwtWithScope returns a ClientOption that specifies if scope can be used +// with self-signed JWT. +func EnableJwtWithScope() option.ClientOption { + return enableJwtWithScope(true) +} + +type enableJwtWithScope bool + +func (w enableJwtWithScope) Apply(o *internal.DialSettings) { + o.EnableJwtWithScope = bool(w) +} + +// WithCredentials returns a client option to specify credentials which will be used to authenticate API calls. +// This credential takes precedence over all other credential options. +func WithCredentials(creds *google.Credentials) option.ClientOption { + return (*withCreds)(creds) +} + +type withCreds google.Credentials + +func (w *withCreds) Apply(o *internal.DialSettings) { + o.InternalCredentials = (*google.Credentials)(w) +} + +// EmbeddableAdapter is a no-op option.ClientOption that allow libraries to +// create their own client options by embedding this type into their own +// client-specific option wrapper. See example for usage. +type EmbeddableAdapter struct{} + +func (*EmbeddableAdapter) Apply(_ *internal.DialSettings) {} diff --git a/vendor/google.golang.org/api/option/option.go b/vendor/google.golang.org/api/option/option.go index 686476f9cbb..b2085a1949a 100644 --- a/vendor/google.golang.org/api/option/option.go +++ b/vendor/google.golang.org/api/option/option.go @@ -10,6 +10,7 @@ import ( "net/http" "golang.org/x/oauth2" + "golang.org/x/oauth2/google" "google.golang.org/api/internal" "google.golang.org/api/internal/impersonate" "google.golang.org/grpc" @@ -81,6 +82,9 @@ func (w withEndpoint) Apply(o *internal.DialSettings) { // WithScopes returns a ClientOption that overrides the default OAuth2 scopes // to be used for a service. +// +// If both WithScopes and WithTokenSource are used, scope settings from the +// token source will be used instead. func WithScopes(scope ...string) ClientOption { return withScopes(scope) } @@ -92,7 +96,9 @@ func (w withScopes) Apply(o *internal.DialSettings) { copy(o.Scopes, w) } -// WithUserAgent returns a ClientOption that sets the User-Agent. +// WithUserAgent returns a ClientOption that sets the User-Agent. This option +// is incompatible with the [WithHTTPClient] option. If you wish to provide a +// custom client you will need to add this header via RoundTripper middleware. func WithUserAgent(ua string) ClientOption { return withUA(ua) } @@ -144,8 +150,6 @@ func (w withGRPCDialOption) Apply(o *internal.DialSettings) { // WithGRPCConnectionPool returns a ClientOption that creates a pool of gRPC // connections that requests will be balanced between. -// -// This is an EXPERIMENTAL API and may be changed or removed in the future. func WithGRPCConnectionPool(size int) ClientOption { return withGRPCConnectionPool(size) } @@ -288,10 +292,10 @@ func (w withClientCertSource) Apply(o *internal.DialSettings) { // service account SA2 while using delegate service accounts DSA1 and DSA2, // the following must be true: // -// 1. Base service account SA1 has roles/iam.serviceAccountTokenCreator on -// DSA1. -// 2. DSA1 has roles/iam.serviceAccountTokenCreator on DSA2. -// 3. DSA2 has roles/iam.serviceAccountTokenCreator on target SA2. +// 1. Base service account SA1 has roles/iam.serviceAccountTokenCreator on +// DSA1. +// 2. DSA1 has roles/iam.serviceAccountTokenCreator on DSA2. +// 3. DSA2 has roles/iam.serviceAccountTokenCreator on target SA2. // // The resulting impersonated credential will either have the default scopes of // the client being instantiating or the scopes from WithScopes if provided. @@ -305,6 +309,10 @@ func (w withClientCertSource) Apply(o *internal.DialSettings) { // roles/serviceusage.serviceUsageConsumer. // // This is an EXPERIMENTAL API and may be changed or removed in the future. +// +// Deprecated: This option has been replaced by `impersonate` package: +// `google.golang.org/api/impersonate`. Please use the `impersonate` package +// instead with the WithTokenSource option. func ImpersonateCredentials(target string, delegates ...string) ClientOption { return impersonateServiceAccount{ target: target, @@ -324,3 +332,14 @@ func (i impersonateServiceAccount) Apply(o *internal.DialSettings) { o.ImpersonationConfig.Delegates = make([]string, len(i.delegates)) copy(o.ImpersonationConfig.Delegates, i.delegates) } + +type withCreds google.Credentials + +func (w *withCreds) Apply(o *internal.DialSettings) { + o.Credentials = (*google.Credentials)(w) +} + +// WithCredentials returns a ClientOption that authenticates API calls. +func WithCredentials(creds *google.Credentials) ClientOption { + return (*withCreds)(creds) +} diff --git a/vendor/google.golang.org/api/storage/v1/storage-api.json b/vendor/google.golang.org/api/storage/v1/storage-api.json index dd283a07281..edebc73ad4c 100644 --- a/vendor/google.golang.org/api/storage/v1/storage-api.json +++ b/vendor/google.golang.org/api/storage/v1/storage-api.json @@ -26,7 +26,7 @@ "description": "Stores and retrieves potentially large, immutable data objects.", "discoveryVersion": "v1", "documentationLink": "https://developers.google.com/storage/docs/json_api/", - "etag": "\"32313837343738383335383432353737343034\"", + "etag": "\"34333739363230323936363635393736363430\"", "icons": { "x16": "https://www.google.com/images/icons/product/cloud_storage-16.png", "x32": "https://www.google.com/images/icons/product/cloud_storage-32.png" @@ -79,6 +79,11 @@ "location": "query", "type": "string" }, + "uploadType": { + "description": "Upload protocol for media (e.g. \"media\", \"multipart\", \"resumable\").", + "location": "query", + "type": "string" + }, "userIp": { "description": "Deprecated. Please use quotaUser instead.", "location": "query", @@ -110,11 +115,6 @@ "required": true, "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request. Required for Requester Pays buckets.", "location": "query", @@ -148,11 +148,6 @@ "required": true, "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request. Required for Requester Pays buckets.", "location": "query", @@ -182,11 +177,6 @@ "required": true, "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request. Required for Requester Pays buckets.", "location": "query", @@ -219,11 +209,6 @@ "required": true, "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request. Required for Requester Pays buckets.", "location": "query", @@ -260,11 +245,6 @@ "required": true, "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request. Required for Requester Pays buckets.", "location": "query", @@ -304,11 +284,6 @@ "required": true, "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request. Required for Requester Pays buckets.", "location": "query", @@ -357,11 +332,6 @@ "location": "query", "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request. Required for Requester Pays buckets.", "location": "query", @@ -414,11 +384,6 @@ "location": "query", "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request. Required for Requester Pays buckets.", "location": "query", @@ -458,11 +423,6 @@ "minimum": "1", "type": "integer" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request. Required for Requester Pays buckets.", "location": "query", @@ -545,11 +505,6 @@ "location": "query", "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request.", "location": "query", @@ -614,11 +569,6 @@ "location": "query", "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request.", "location": "query", @@ -659,11 +609,6 @@ "required": true, "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request. Required for Requester Pays buckets.", "location": "query", @@ -759,11 +704,6 @@ "location": "query", "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request. Required for Requester Pays buckets.", "location": "query", @@ -796,11 +736,6 @@ "required": true, "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request. Required for Requester Pays buckets.", "location": "query", @@ -841,11 +776,6 @@ "required": true, "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request. Required for Requester Pays buckets.", "location": "query", @@ -943,11 +873,6 @@ "location": "query", "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request. Required for Requester Pays buckets.", "location": "query", @@ -1012,11 +937,6 @@ "required": true, "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request. Required for Requester Pays buckets.", "location": "query", @@ -1050,11 +970,6 @@ "required": true, "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request. Required for Requester Pays buckets.", "location": "query", @@ -1084,11 +999,6 @@ "required": true, "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request. Required for Requester Pays buckets.", "location": "query", @@ -1133,11 +1043,6 @@ "location": "query", "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request. Required for Requester Pays buckets.", "location": "query", @@ -1174,11 +1079,6 @@ "required": true, "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request. Required for Requester Pays buckets.", "location": "query", @@ -1218,11 +1118,6 @@ "required": true, "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request. Required for Requester Pays buckets.", "location": "query", @@ -1266,11 +1161,6 @@ "required": true, "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request. Required for Requester Pays buckets.", "location": "query", @@ -1305,11 +1195,6 @@ "required": true, "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request. Required for Requester Pays buckets.", "location": "query", @@ -1342,11 +1227,6 @@ "required": true, "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request. Required for Requester Pays buckets.", "location": "query", @@ -1380,11 +1260,6 @@ "required": true, "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request. Required for Requester Pays buckets.", "location": "query", @@ -1441,11 +1316,6 @@ "required": true, "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request. Required for Requester Pays buckets.", "location": "query", @@ -1492,11 +1362,6 @@ "required": true, "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request. Required for Requester Pays buckets.", "location": "query", @@ -1539,11 +1404,6 @@ "required": true, "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request. Required for Requester Pays buckets.", "location": "query", @@ -1589,11 +1449,6 @@ "required": true, "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request. Required for Requester Pays buckets.", "location": "query", @@ -1643,11 +1498,6 @@ "required": true, "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request. Required for Requester Pays buckets.", "location": "query", @@ -1700,11 +1550,6 @@ "required": true, "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request. Required for Requester Pays buckets.", "location": "query", @@ -1786,11 +1631,6 @@ "location": "query", "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request. Required for Requester Pays buckets.", "location": "query", @@ -1920,11 +1760,6 @@ "location": "query", "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "sourceBucket": { "description": "Name of the bucket in which to find the source object.", "location": "path", @@ -2013,11 +1848,6 @@ "required": true, "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request. Required for Requester Pays buckets.", "location": "query", @@ -2095,11 +1925,6 @@ "location": "query", "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request. Required for Requester Pays buckets.", "location": "query", @@ -2147,11 +1972,6 @@ "required": true, "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request. Required for Requester Pays buckets.", "location": "query", @@ -2272,11 +2092,6 @@ "location": "query", "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request. Required for Requester Pays buckets.", "location": "query", @@ -2326,6 +2141,11 @@ "location": "query", "type": "boolean" }, + "matchGlob": { + "description": "Filter results to objects and prefixes that match this glob pattern.", + "location": "query", + "type": "string" + }, "maxResults": { "default": "1000", "description": "Maximum number of items plus prefixes to return in a single page of responses. As duplicate prefixes are omitted, fewer total results may be returned than requested. The service will use this parameter or 1,000 items, whichever is smaller.", @@ -2357,11 +2177,6 @@ "location": "query", "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "startOffset": { "description": "Filter results to objects whose names are lexicographically equal to or after startOffset. If endOffset is also set, the objects listed will have names between startOffset (inclusive) and endOffset (exclusive).", "location": "query", @@ -2476,11 +2291,6 @@ "location": "query", "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request, for Requester Pays buckets.", "location": "query", @@ -2615,11 +2425,6 @@ "location": "query", "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "rewriteToken": { "description": "Include this field (from the previous rewrite response) on each rewrite request after the first one, until the rewrite response 'done' flag is true. Calls that provide a rewriteToken can omit all other request fields, but if included those fields must match the values provided in the first rewrite request.", "location": "query", @@ -2689,11 +2494,6 @@ "required": true, "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request. Required for Requester Pays buckets.", "location": "query", @@ -2748,11 +2548,6 @@ "required": true, "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request. Required for Requester Pays buckets.", "location": "query", @@ -2856,11 +2651,6 @@ "location": "query", "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request. Required for Requester Pays buckets.", "location": "query", @@ -2939,11 +2729,6 @@ "location": "query", "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "startOffset": { "description": "Filter results to objects whose names are lexicographically equal to or after startOffset. If endOffset is also set, the objects listed will have names between startOffset (inclusive) and endOffset (exclusive).", "location": "query", @@ -3202,11 +2987,6 @@ "required": true, "type": "string" }, - "provisionalUserProject": { - "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - "location": "query", - "type": "string" - }, "userProject": { "description": "The project to be billed for this request.", "location": "query", @@ -3230,7 +3010,7 @@ } } }, - "revision": "20201112", + "revision": "20230301", "rootUrl": "https://storage.googleapis.com/", "schemas": { "Bucket": { @@ -3249,6 +3029,21 @@ }, "type": "array" }, + "autoclass": { + "description": "The bucket's Autoclass configuration.", + "properties": { + "enabled": { + "description": "Whether or not Autoclass is enabled on this bucket", + "type": "boolean" + }, + "toggleTime": { + "description": "A date and time in RFC 3339 format representing the instant at which \"enabled\" was last toggled.", + "format": "date-time", + "type": "string" + } + }, + "type": "object" + }, "billing": { "description": "The bucket's billing configuration.", "properties": { @@ -3294,6 +3089,19 @@ }, "type": "array" }, + "customPlacementConfig": { + "description": "The bucket's custom placement configuration for Custom Dual Regions.", + "properties": { + "dataLocations": { + "description": "The list of regional locations in which data is placed.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, "defaultEventBasedHold": { "description": "The default value for event-based hold on newly created objects in this bucket. Event-based hold is a way to retain objects indefinitely until an event occurs, signified by the hold's release. After being released, such objects will be subject to bucket-level retention (if any). One sample use case of this flag is for banks to hold loan documents for at least 3 years after loan is paid in full. Here, bucket-level retention is 3 years and the event is loan being paid in full. In this example, these objects will be held intact for any number of years until the event has occurred (event-based hold on the object is released) and then 3 more years after that. That means retention duration of the objects begins from the moment event-based hold transitioned from true to false. Objects under event-based hold cannot be deleted, overwritten or archived until the hold is removed.", "type": "boolean" @@ -3338,7 +3146,7 @@ "type": "object" }, "publicAccessPrevention": { - "description": "The bucket's Public Access Prevention configuration. Currently, 'unspecified' and 'enforced' are supported.", + "description": "The bucket's Public Access Prevention configuration. Currently, 'inherited' and 'enforced' are supported.", "type": "string" }, "uniformBucketLevelAccess": { @@ -3391,7 +3199,7 @@ "type": "string" }, "type": { - "description": "Type of the action. Currently, only Delete and SetStorageClass are supported.", + "description": "Type of the action. Currently, only Delete, SetStorageClass, and AbortIncompleteMultipartUpload are supported.", "type": "string" } }, @@ -3433,6 +3241,13 @@ "description": "A regular expression that satisfies the RE2 syntax. This condition is satisfied when the name of the object matches the RE2 pattern. Note: This feature is currently in the \"Early Access\" launch stage and is only available to a whitelisted set of users; that means that this feature may be changed in backward-incompatible ways and that it is not guaranteed to be released.", "type": "string" }, + "matchesPrefix": { + "description": "List of object name prefixes. This condition will be satisfied when at least one of the prefixes exactly matches the beginning of the object name.", + "items": { + "type": "string" + }, + "type": "array" + }, "matchesStorageClass": { "description": "Objects having any of the storage classes specified by this condition will be matched. Values include MULTI_REGIONAL, REGIONAL, NEARLINE, COLDLINE, ARCHIVE, STANDARD, and DURABLE_REDUCED_AVAILABILITY.", "items": { @@ -3440,6 +3255,13 @@ }, "type": "array" }, + "matchesSuffix": { + "description": "List of object name suffixes. This condition will be satisfied when at least one of the suffixes exactly matches the end of the object name.", + "items": { + "type": "string" + }, + "type": "array" + }, "noncurrentTimeBefore": { "description": "A date in RFC 3339 format with only the date part (for instance, \"2013-01-15\"). This condition is satisfied when the noncurrent time on an object is before this date in UTC. This condition is relevant only for versioned objects.", "format": "date", @@ -3536,6 +3358,14 @@ }, "type": "object" }, + "rpo": { + "description": "The Recovery Point Objective (RPO) of this bucket. Set to ASYNC_TURBO to turn on Turbo Replication on a bucket.", + "type": "string" + }, + "satisfiesPZS": { + "description": "Reserved for future use.", + "type": "boolean" + }, "selfLink": { "description": "The URI of this bucket.", "type": "string" @@ -3577,13 +3407,6 @@ } }, "type": "object" - }, - "zoneAffinity": { - "description": "The zone or zones from which the bucket is intended to use zonal quota. Requests for data from outside the specified affinities are still allowed but won't be able to use zonal quota. The zone or zones need to be within the bucket location otherwise the requests will fail with a 400 Bad Request response.", - "items": { - "type": "string" - }, - "type": "array" } }, "type": "object" @@ -4177,7 +4000,7 @@ "type": "string" }, "updated": { - "description": "The modification time of the object metadata in RFC 3339 format.", + "description": "The modification time of the object metadata in RFC 3339 format. Set initially to object creation time and then updated whenever any metadata of the object changes. This includes changes made by a requester, such as modifying custom metadata, as well as changes made by Cloud Storage on behalf of a requester, such as changing the storage class based on an Object Lifecycle Configuration.", "format": "date-time", "type": "string" } diff --git a/vendor/google.golang.org/api/storage/v1/storage-gen.go b/vendor/google.golang.org/api/storage/v1/storage-gen.go index 10383bb2fae..2f9ceefdcda 100644 --- a/vendor/google.golang.org/api/storage/v1/storage-gen.go +++ b/vendor/google.golang.org/api/storage/v1/storage-gen.go @@ -1,4 +1,4 @@ -// Copyright 2020 Google LLC. +// Copyright 2023 Google LLC. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -10,35 +10,35 @@ // // For product documentation, see: https://developers.google.com/storage/docs/json_api/ // -// Creating a client +// # Creating a client // // Usage example: // -// import "google.golang.org/api/storage/v1" -// ... -// ctx := context.Background() -// storageService, err := storage.NewService(ctx) +// import "google.golang.org/api/storage/v1" +// ... +// ctx := context.Background() +// storageService, err := storage.NewService(ctx) // // In this example, Google Application Default Credentials are used for authentication. // // For information on how to create and obtain Application Default Credentials, see https://developers.google.com/identity/protocols/application-default-credentials. // -// Other authentication options +// # Other authentication options // // By default, all available scopes (see "Constants") are used to authenticate. To restrict scopes, use option.WithScopes: // -// storageService, err := storage.NewService(ctx, option.WithScopes(storage.DevstorageReadWriteScope)) +// storageService, err := storage.NewService(ctx, option.WithScopes(storage.DevstorageReadWriteScope)) // // To use an API key for authentication (note: some APIs do not support API keys), use option.WithAPIKey: // -// storageService, err := storage.NewService(ctx, option.WithAPIKey("AIza...")) +// storageService, err := storage.NewService(ctx, option.WithAPIKey("AIza...")) // // To use an OAuth token (e.g., a user token obtained via a three-legged OAuth flow), use option.WithTokenSource: // -// config := &oauth2.Config{...} -// // ... -// token, err := config.Exchange(ctx, ...) -// storageService, err := storage.NewService(ctx, option.WithTokenSource(config.TokenSource(ctx, token))) +// config := &oauth2.Config{...} +// // ... +// token, err := config.Exchange(ctx, ...) +// storageService, err := storage.NewService(ctx, option.WithTokenSource(config.TokenSource(ctx, token))) // // See https://godoc.org/google.golang.org/api/option/ for details on options. package storage // import "google.golang.org/api/storage/v1" @@ -55,7 +55,9 @@ import ( "strconv" "strings" + "github.com/googleapis/gax-go/v2" googleapi "google.golang.org/api/googleapi" + internal "google.golang.org/api/internal" gensupport "google.golang.org/api/internal/gensupport" option "google.golang.org/api/option" internaloption "google.golang.org/api/option/internaloption" @@ -103,7 +105,7 @@ const ( // NewService creates a new Service. func NewService(ctx context.Context, opts ...option.ClientOption) (*Service, error) { - scopesOption := option.WithScopes( + scopesOption := internaloption.WithDefaultScopes( "https://www.googleapis.com/auth/cloud-platform", "https://www.googleapis.com/auth/cloud-platform.read-only", "https://www.googleapis.com/auth/devstorage.full_control", @@ -279,6 +281,9 @@ type Bucket struct { // Acl: Access controls on the bucket. Acl []*BucketAccessControl `json:"acl,omitempty"` + // Autoclass: The bucket's Autoclass configuration. + Autoclass *BucketAutoclass `json:"autoclass,omitempty"` + // Billing: The bucket's billing configuration. Billing *BucketBilling `json:"billing,omitempty"` @@ -286,6 +291,10 @@ type Bucket struct { // configuration. Cors []*BucketCors `json:"cors,omitempty"` + // CustomPlacementConfig: The bucket's custom placement configuration + // for Custom Dual Regions. + CustomPlacementConfig *BucketCustomPlacementConfig `json:"customPlacementConfig,omitempty"` + // DefaultEventBasedHold: The default value for event-based hold on // newly created objects in this bucket. Event-based hold is a way to // retain objects indefinitely until an event occurs, signified by the @@ -369,6 +378,13 @@ type Bucket struct { // PERMISSION_DENIED error. RetentionPolicy *BucketRetentionPolicy `json:"retentionPolicy,omitempty"` + // Rpo: The Recovery Point Objective (RPO) of this bucket. Set to + // ASYNC_TURBO to turn on Turbo Replication on a bucket. + Rpo string `json:"rpo,omitempty"` + + // SatisfiesPZS: Reserved for future use. + SatisfiesPZS bool `json:"satisfiesPZS,omitempty"` + // SelfLink: The URI of this bucket. SelfLink string `json:"selfLink,omitempty"` @@ -395,23 +411,16 @@ type Bucket struct { // Static Website Examples for more information. Website *BucketWebsite `json:"website,omitempty"` - // ZoneAffinity: The zone or zones from which the bucket is intended to - // use zonal quota. Requests for data from outside the specified - // affinities are still allowed but won't be able to use zonal quota. - // The zone or zones need to be within the bucket location otherwise the - // requests will fail with a 400 Bad Request response. - ZoneAffinity []string `json:"zoneAffinity,omitempty"` - // ServerResponse contains the HTTP response code and headers from the // server. googleapi.ServerResponse `json:"-"` // ForceSendFields is a list of field names (e.g. "Acl") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "Acl") to include in API @@ -429,6 +438,38 @@ func (s *Bucket) MarshalJSON() ([]byte, error) { return gensupport.MarshalJSON(raw, s.ForceSendFields, s.NullFields) } +// BucketAutoclass: The bucket's Autoclass configuration. +type BucketAutoclass struct { + // Enabled: Whether or not Autoclass is enabled on this bucket + Enabled bool `json:"enabled,omitempty"` + + // ToggleTime: A date and time in RFC 3339 format representing the + // instant at which "enabled" was last toggled. + ToggleTime string `json:"toggleTime,omitempty"` + + // ForceSendFields is a list of field names (e.g. "Enabled") to + // unconditionally include in API requests. By default, fields with + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. + ForceSendFields []string `json:"-"` + + // NullFields is a list of field names (e.g. "Enabled") to include in + // API requests with the JSON null value. By default, fields with empty + // values are omitted from API requests. However, any field with an + // empty value appearing in NullFields will be sent to the server as + // null. It is an error if a field in this list has a non-empty value. + // This may be used to include null fields in Patch requests. + NullFields []string `json:"-"` +} + +func (s *BucketAutoclass) MarshalJSON() ([]byte, error) { + type NoMethod BucketAutoclass + raw := NoMethod(*s) + return gensupport.MarshalJSON(raw, s.ForceSendFields, s.NullFields) +} + // BucketBilling: The bucket's billing configuration. type BucketBilling struct { // RequesterPays: When set to true, Requester Pays is enabled for this @@ -437,10 +478,10 @@ type BucketBilling struct { // ForceSendFields is a list of field names (e.g. "RequesterPays") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "RequesterPays") to include @@ -480,10 +521,10 @@ type BucketCors struct { // ForceSendFields is a list of field names (e.g. "MaxAgeSeconds") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "MaxAgeSeconds") to include @@ -501,6 +542,36 @@ func (s *BucketCors) MarshalJSON() ([]byte, error) { return gensupport.MarshalJSON(raw, s.ForceSendFields, s.NullFields) } +// BucketCustomPlacementConfig: The bucket's custom placement +// configuration for Custom Dual Regions. +type BucketCustomPlacementConfig struct { + // DataLocations: The list of regional locations in which data is + // placed. + DataLocations []string `json:"dataLocations,omitempty"` + + // ForceSendFields is a list of field names (e.g. "DataLocations") to + // unconditionally include in API requests. By default, fields with + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. + ForceSendFields []string `json:"-"` + + // NullFields is a list of field names (e.g. "DataLocations") to include + // in API requests with the JSON null value. By default, fields with + // empty values are omitted from API requests. However, any field with + // an empty value appearing in NullFields will be sent to the server as + // null. It is an error if a field in this list has a non-empty value. + // This may be used to include null fields in Patch requests. + NullFields []string `json:"-"` +} + +func (s *BucketCustomPlacementConfig) MarshalJSON() ([]byte, error) { + type NoMethod BucketCustomPlacementConfig + raw := NoMethod(*s) + return gensupport.MarshalJSON(raw, s.ForceSendFields, s.NullFields) +} + // BucketEncryption: Encryption configuration for a bucket. type BucketEncryption struct { // DefaultKmsKeyName: A Cloud KMS key that will be used to encrypt @@ -510,10 +581,10 @@ type BucketEncryption struct { // ForceSendFields is a list of field names (e.g. "DefaultKmsKeyName") // to unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "DefaultKmsKeyName") to @@ -543,7 +614,7 @@ type BucketIamConfiguration struct { BucketPolicyOnly *BucketIamConfigurationBucketPolicyOnly `json:"bucketPolicyOnly,omitempty"` // PublicAccessPrevention: The bucket's Public Access Prevention - // configuration. Currently, 'unspecified' and 'enforced' are supported. + // configuration. Currently, 'inherited' and 'enforced' are supported. PublicAccessPrevention string `json:"publicAccessPrevention,omitempty"` // UniformBucketLevelAccess: The bucket's uniform bucket-level access @@ -552,10 +623,10 @@ type BucketIamConfiguration struct { // ForceSendFields is a list of field names (e.g. "BucketPolicyOnly") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "BucketPolicyOnly") to @@ -594,10 +665,10 @@ type BucketIamConfigurationBucketPolicyOnly struct { // ForceSendFields is a list of field names (e.g. "Enabled") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "Enabled") to include in @@ -632,10 +703,10 @@ type BucketIamConfigurationUniformBucketLevelAccess struct { // ForceSendFields is a list of field names (e.g. "Enabled") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "Enabled") to include in @@ -662,10 +733,10 @@ type BucketLifecycle struct { // ForceSendFields is a list of field names (e.g. "Rule") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "Rule") to include in API @@ -692,10 +763,10 @@ type BucketLifecycleRule struct { // ForceSendFields is a list of field names (e.g. "Action") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "Action") to include in API @@ -719,16 +790,16 @@ type BucketLifecycleRuleAction struct { // action is SetStorageClass. StorageClass string `json:"storageClass,omitempty"` - // Type: Type of the action. Currently, only Delete and SetStorageClass - // are supported. + // Type: Type of the action. Currently, only Delete, SetStorageClass, + // and AbortIncompleteMultipartUpload are supported. Type string `json:"type,omitempty"` // ForceSendFields is a list of field names (e.g. "StorageClass") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "StorageClass") to include @@ -751,7 +822,7 @@ func (s *BucketLifecycleRuleAction) MarshalJSON() ([]byte, error) { type BucketLifecycleRuleCondition struct { // Age: Age of an object (in days). This condition is satisfied when an // object reaches the specified age. - Age int64 `json:"age,omitempty"` + Age *int64 `json:"age,omitempty"` // CreatedBefore: A date in RFC 3339 format with only the date part (for // instance, "2013-01-15"). This condition is satisfied when an object @@ -790,12 +861,22 @@ type BucketLifecycleRuleCondition struct { // ways and that it is not guaranteed to be released. MatchesPattern string `json:"matchesPattern,omitempty"` + // MatchesPrefix: List of object name prefixes. This condition will be + // satisfied when at least one of the prefixes exactly matches the + // beginning of the object name. + MatchesPrefix []string `json:"matchesPrefix,omitempty"` + // MatchesStorageClass: Objects having any of the storage classes // specified by this condition will be matched. Values include // MULTI_REGIONAL, REGIONAL, NEARLINE, COLDLINE, ARCHIVE, STANDARD, and // DURABLE_REDUCED_AVAILABILITY. MatchesStorageClass []string `json:"matchesStorageClass,omitempty"` + // MatchesSuffix: List of object name suffixes. This condition will be + // satisfied when at least one of the suffixes exactly matches the end + // of the object name. + MatchesSuffix []string `json:"matchesSuffix,omitempty"` + // NoncurrentTimeBefore: A date in RFC 3339 format with only the date // part (for instance, "2013-01-15"). This condition is satisfied when // the noncurrent time on an object is before this date in UTC. This @@ -809,10 +890,10 @@ type BucketLifecycleRuleCondition struct { // ForceSendFields is a list of field names (e.g. "Age") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "Age") to include in API @@ -843,10 +924,10 @@ type BucketLogging struct { // ForceSendFields is a list of field names (e.g. "LogBucket") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "LogBucket") to include in @@ -875,10 +956,10 @@ type BucketOwner struct { // ForceSendFields is a list of field names (e.g. "Entity") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "Entity") to include in API @@ -924,10 +1005,10 @@ type BucketRetentionPolicy struct { // ForceSendFields is a list of field names (e.g. "EffectiveTime") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "EffectiveTime") to include @@ -953,10 +1034,10 @@ type BucketVersioning struct { // ForceSendFields is a list of field names (e.g. "Enabled") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "Enabled") to include in @@ -992,10 +1073,10 @@ type BucketWebsite struct { // ForceSendFields is a list of field names (e.g. "MainPageSuffix") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "MainPageSuffix") to @@ -1070,10 +1151,10 @@ type BucketAccessControl struct { // ForceSendFields is a list of field names (e.g. "Bucket") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "Bucket") to include in API @@ -1102,10 +1183,10 @@ type BucketAccessControlProjectTeam struct { // ForceSendFields is a list of field names (e.g. "ProjectNumber") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "ProjectNumber") to include @@ -1138,10 +1219,10 @@ type BucketAccessControls struct { // ForceSendFields is a list of field names (e.g. "Items") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "Items") to include in API @@ -1179,10 +1260,10 @@ type Buckets struct { // ForceSendFields is a list of field names (e.g. "Items") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "Items") to include in API @@ -1245,10 +1326,10 @@ type Channel struct { // ForceSendFields is a list of field names (e.g. "Address") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "Address") to include in @@ -1280,10 +1361,10 @@ type ComposeRequest struct { // ForceSendFields is a list of field names (e.g. "Destination") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "Destination") to include @@ -1315,10 +1396,10 @@ type ComposeRequestSourceObjects struct { // ForceSendFields is a list of field names (e.g. "Generation") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "Generation") to include in @@ -1347,10 +1428,10 @@ type ComposeRequestSourceObjectsObjectPreconditions struct { // ForceSendFields is a list of field names (e.g. "IfGenerationMatch") // to unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "IfGenerationMatch") to @@ -1395,10 +1476,10 @@ type Expr struct { // ForceSendFields is a list of field names (e.g. "Description") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "Description") to include @@ -1435,10 +1516,10 @@ type HmacKey struct { // ForceSendFields is a list of field names (e.g. "Kind") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "Kind") to include in API @@ -1501,10 +1582,10 @@ type HmacKeyMetadata struct { // ForceSendFields is a list of field names (e.g. "AccessId") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "AccessId") to include in @@ -1542,10 +1623,10 @@ type HmacKeysMetadata struct { // ForceSendFields is a list of field names (e.g. "Items") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "Items") to include in API @@ -1606,10 +1687,10 @@ type Notification struct { // ForceSendFields is a list of field names (e.g. "CustomAttributes") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "CustomAttributes") to @@ -1643,10 +1724,10 @@ type Notifications struct { // ForceSendFields is a list of field names (e.g. "Items") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "Items") to include in API @@ -1808,7 +1889,12 @@ type Object struct { TimeStorageClassUpdated string `json:"timeStorageClassUpdated,omitempty"` // Updated: The modification time of the object metadata in RFC 3339 - // format. + // format. Set initially to object creation time and then updated + // whenever any metadata of the object changes. This includes changes + // made by a requester, such as modifying custom metadata, as well as + // changes made by Cloud Storage on behalf of a requester, such as + // changing the storage class based on an Object Lifecycle + // Configuration. Updated string `json:"updated,omitempty"` // ServerResponse contains the HTTP response code and headers from the @@ -1817,10 +1903,10 @@ type Object struct { // ForceSendFields is a list of field names (e.g. "Acl") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "Acl") to include in API @@ -1849,10 +1935,10 @@ type ObjectCustomerEncryption struct { // ForceSendFields is a list of field names (e.g. "EncryptionAlgorithm") // to unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "EncryptionAlgorithm") to @@ -1882,10 +1968,10 @@ type ObjectOwner struct { // ForceSendFields is a list of field names (e.g. "Entity") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "Entity") to include in API @@ -1966,10 +2052,10 @@ type ObjectAccessControl struct { // ForceSendFields is a list of field names (e.g. "Bucket") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "Bucket") to include in API @@ -1998,10 +2084,10 @@ type ObjectAccessControlProjectTeam struct { // ForceSendFields is a list of field names (e.g. "ProjectNumber") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "ProjectNumber") to include @@ -2034,10 +2120,10 @@ type ObjectAccessControls struct { // ForceSendFields is a list of field names (e.g. "Items") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "Items") to include in API @@ -2079,10 +2165,10 @@ type Objects struct { // ForceSendFields is a list of field names (e.g. "Items") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "Items") to include in API @@ -2131,10 +2217,10 @@ type Policy struct { // ForceSendFields is a list of field names (e.g. "Bindings") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "Bindings") to include in @@ -2218,10 +2304,10 @@ type PolicyBindings struct { // ForceSendFields is a list of field names (e.g. "Condition") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "Condition") to include in @@ -2273,10 +2359,10 @@ type RewriteResponse struct { // ForceSendFields is a list of field names (e.g. "Done") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "Done") to include in API @@ -2310,10 +2396,10 @@ type ServiceAccount struct { // ForceSendFields is a list of field names (e.g. "EmailAddress") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "EmailAddress") to include @@ -2363,10 +2449,10 @@ type TestIamPermissionsResponse struct { // ForceSendFields is a list of field names (e.g. "Kind") to // unconditionally include in API requests. By default, fields with - // empty values are omitted from API requests. However, any non-pointer, - // non-interface field appearing in ForceSendFields will be sent to the - // server regardless of whether the field is empty or not. This may be - // used to include empty fields in Patch requests. + // empty or default values are omitted from API requests. However, any + // non-pointer, non-interface field appearing in ForceSendFields will be + // sent to the server regardless of whether the field is empty or not. + // This may be used to include empty fields in Patch requests. ForceSendFields []string `json:"-"` // NullFields is a list of field names (e.g. "Kind") to include in API @@ -2397,6 +2483,11 @@ type BucketAccessControlsDeleteCall struct { // Delete: Permanently deletes the ACL entry for the specified entity on // the specified bucket. +// +// - bucket: Name of a bucket. +// - entity: The entity holding the permission. Can be user-userId, +// user-emailAddress, group-groupId, group-emailAddress, allUsers, or +// allAuthenticatedUsers. func (r *BucketAccessControlsService) Delete(bucket string, entity string) *BucketAccessControlsDeleteCall { c := &BucketAccessControlsDeleteCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket @@ -2404,14 +2495,6 @@ func (r *BucketAccessControlsService) Delete(bucket string, entity string) *Buck return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *BucketAccessControlsDeleteCall) ProvisionalUserProject(provisionalUserProject string) *BucketAccessControlsDeleteCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. Required for Requester Pays buckets. func (c *BucketAccessControlsDeleteCall) UserProject(userProject string) *BucketAccessControlsDeleteCall { @@ -2446,7 +2529,7 @@ func (c *BucketAccessControlsDeleteCall) Header() http.Header { func (c *BucketAccessControlsDeleteCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -2477,7 +2560,7 @@ func (c *BucketAccessControlsDeleteCall) Do(opts ...googleapi.CallOption) error } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return err + return gensupport.WrapError(err) } return nil // { @@ -2501,11 +2584,6 @@ func (c *BucketAccessControlsDeleteCall) Do(opts ...googleapi.CallOption) error // "required": true, // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request. Required for Requester Pays buckets.", // "location": "query", @@ -2535,6 +2613,11 @@ type BucketAccessControlsGetCall struct { // Get: Returns the ACL entry for the specified entity on the specified // bucket. +// +// - bucket: Name of a bucket. +// - entity: The entity holding the permission. Can be user-userId, +// user-emailAddress, group-groupId, group-emailAddress, allUsers, or +// allAuthenticatedUsers. func (r *BucketAccessControlsService) Get(bucket string, entity string) *BucketAccessControlsGetCall { c := &BucketAccessControlsGetCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket @@ -2542,14 +2625,6 @@ func (r *BucketAccessControlsService) Get(bucket string, entity string) *BucketA return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *BucketAccessControlsGetCall) ProvisionalUserProject(provisionalUserProject string) *BucketAccessControlsGetCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. Required for Requester Pays buckets. func (c *BucketAccessControlsGetCall) UserProject(userProject string) *BucketAccessControlsGetCall { @@ -2594,7 +2669,7 @@ func (c *BucketAccessControlsGetCall) Header() http.Header { func (c *BucketAccessControlsGetCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -2633,17 +2708,17 @@ func (c *BucketAccessControlsGetCall) Do(opts ...googleapi.CallOption) (*BucketA if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &BucketAccessControl{ ServerResponse: googleapi.ServerResponse{ @@ -2677,11 +2752,6 @@ func (c *BucketAccessControlsGetCall) Do(opts ...googleapi.CallOption) (*BucketA // "required": true, // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request. Required for Requester Pays buckets.", // "location": "query", @@ -2712,6 +2782,8 @@ type BucketAccessControlsInsertCall struct { } // Insert: Creates a new ACL entry on the specified bucket. +// +// - bucket: Name of a bucket. func (r *BucketAccessControlsService) Insert(bucket string, bucketaccesscontrol *BucketAccessControl) *BucketAccessControlsInsertCall { c := &BucketAccessControlsInsertCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket @@ -2719,14 +2791,6 @@ func (r *BucketAccessControlsService) Insert(bucket string, bucketaccesscontrol return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *BucketAccessControlsInsertCall) ProvisionalUserProject(provisionalUserProject string) *BucketAccessControlsInsertCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. Required for Requester Pays buckets. func (c *BucketAccessControlsInsertCall) UserProject(userProject string) *BucketAccessControlsInsertCall { @@ -2761,7 +2825,7 @@ func (c *BucketAccessControlsInsertCall) Header() http.Header { func (c *BucketAccessControlsInsertCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -2801,17 +2865,17 @@ func (c *BucketAccessControlsInsertCall) Do(opts ...googleapi.CallOption) (*Buck if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &BucketAccessControl{ ServerResponse: googleapi.ServerResponse{ @@ -2838,11 +2902,6 @@ func (c *BucketAccessControlsInsertCall) Do(opts ...googleapi.CallOption) (*Buck // "required": true, // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request. Required for Requester Pays buckets.", // "location": "query", @@ -2876,20 +2935,14 @@ type BucketAccessControlsListCall struct { } // List: Retrieves ACL entries on the specified bucket. +// +// - bucket: Name of a bucket. func (r *BucketAccessControlsService) List(bucket string) *BucketAccessControlsListCall { c := &BucketAccessControlsListCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *BucketAccessControlsListCall) ProvisionalUserProject(provisionalUserProject string) *BucketAccessControlsListCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. Required for Requester Pays buckets. func (c *BucketAccessControlsListCall) UserProject(userProject string) *BucketAccessControlsListCall { @@ -2934,7 +2987,7 @@ func (c *BucketAccessControlsListCall) Header() http.Header { func (c *BucketAccessControlsListCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -2972,17 +3025,17 @@ func (c *BucketAccessControlsListCall) Do(opts ...googleapi.CallOption) (*Bucket if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &BucketAccessControls{ ServerResponse: googleapi.ServerResponse{ @@ -3009,11 +3062,6 @@ func (c *BucketAccessControlsListCall) Do(opts ...googleapi.CallOption) (*Bucket // "required": true, // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request. Required for Requester Pays buckets.", // "location": "query", @@ -3045,6 +3093,11 @@ type BucketAccessControlsPatchCall struct { } // Patch: Patches an ACL entry on the specified bucket. +// +// - bucket: Name of a bucket. +// - entity: The entity holding the permission. Can be user-userId, +// user-emailAddress, group-groupId, group-emailAddress, allUsers, or +// allAuthenticatedUsers. func (r *BucketAccessControlsService) Patch(bucket string, entity string, bucketaccesscontrol *BucketAccessControl) *BucketAccessControlsPatchCall { c := &BucketAccessControlsPatchCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket @@ -3053,14 +3106,6 @@ func (r *BucketAccessControlsService) Patch(bucket string, entity string, bucket return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *BucketAccessControlsPatchCall) ProvisionalUserProject(provisionalUserProject string) *BucketAccessControlsPatchCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. Required for Requester Pays buckets. func (c *BucketAccessControlsPatchCall) UserProject(userProject string) *BucketAccessControlsPatchCall { @@ -3095,7 +3140,7 @@ func (c *BucketAccessControlsPatchCall) Header() http.Header { func (c *BucketAccessControlsPatchCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -3136,17 +3181,17 @@ func (c *BucketAccessControlsPatchCall) Do(opts ...googleapi.CallOption) (*Bucke if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &BucketAccessControl{ ServerResponse: googleapi.ServerResponse{ @@ -3180,11 +3225,6 @@ func (c *BucketAccessControlsPatchCall) Do(opts ...googleapi.CallOption) (*Bucke // "required": true, // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request. Required for Requester Pays buckets.", // "location": "query", @@ -3219,6 +3259,11 @@ type BucketAccessControlsUpdateCall struct { } // Update: Updates an ACL entry on the specified bucket. +// +// - bucket: Name of a bucket. +// - entity: The entity holding the permission. Can be user-userId, +// user-emailAddress, group-groupId, group-emailAddress, allUsers, or +// allAuthenticatedUsers. func (r *BucketAccessControlsService) Update(bucket string, entity string, bucketaccesscontrol *BucketAccessControl) *BucketAccessControlsUpdateCall { c := &BucketAccessControlsUpdateCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket @@ -3227,14 +3272,6 @@ func (r *BucketAccessControlsService) Update(bucket string, entity string, bucke return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *BucketAccessControlsUpdateCall) ProvisionalUserProject(provisionalUserProject string) *BucketAccessControlsUpdateCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. Required for Requester Pays buckets. func (c *BucketAccessControlsUpdateCall) UserProject(userProject string) *BucketAccessControlsUpdateCall { @@ -3269,7 +3306,7 @@ func (c *BucketAccessControlsUpdateCall) Header() http.Header { func (c *BucketAccessControlsUpdateCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -3310,17 +3347,17 @@ func (c *BucketAccessControlsUpdateCall) Do(opts ...googleapi.CallOption) (*Buck if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &BucketAccessControl{ ServerResponse: googleapi.ServerResponse{ @@ -3354,11 +3391,6 @@ func (c *BucketAccessControlsUpdateCall) Do(opts ...googleapi.CallOption) (*Buck // "required": true, // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request. Required for Requester Pays buckets.", // "location": "query", @@ -3391,6 +3423,8 @@ type BucketsDeleteCall struct { } // Delete: Permanently deletes an empty bucket. +// +// - bucket: Name of a bucket. func (r *BucketsService) Delete(bucket string) *BucketsDeleteCall { c := &BucketsDeleteCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket @@ -3413,14 +3447,6 @@ func (c *BucketsDeleteCall) IfMetagenerationNotMatch(ifMetagenerationNotMatch in return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *BucketsDeleteCall) ProvisionalUserProject(provisionalUserProject string) *BucketsDeleteCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. Required for Requester Pays buckets. func (c *BucketsDeleteCall) UserProject(userProject string) *BucketsDeleteCall { @@ -3455,7 +3481,7 @@ func (c *BucketsDeleteCall) Header() http.Header { func (c *BucketsDeleteCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -3485,7 +3511,7 @@ func (c *BucketsDeleteCall) Do(opts ...googleapi.CallOption) error { } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return err + return gensupport.WrapError(err) } return nil // { @@ -3514,11 +3540,6 @@ func (c *BucketsDeleteCall) Do(opts ...googleapi.CallOption) error { // "location": "query", // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request. Required for Requester Pays buckets.", // "location": "query", @@ -3547,6 +3568,8 @@ type BucketsGetCall struct { } // Get: Returns metadata for the specified bucket. +// +// - bucket: Name of a bucket. func (r *BucketsService) Get(bucket string) *BucketsGetCall { c := &BucketsGetCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket @@ -3575,21 +3598,14 @@ func (c *BucketsGetCall) IfMetagenerationNotMatch(ifMetagenerationNotMatch int64 // properties to return. Defaults to noAcl. // // Possible values: -// "full" - Include all properties. -// "noAcl" - Omit owner, acl and defaultObjectAcl properties. +// +// "full" - Include all properties. +// "noAcl" - Omit owner, acl and defaultObjectAcl properties. func (c *BucketsGetCall) Projection(projection string) *BucketsGetCall { c.urlParams_.Set("projection", projection) return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *BucketsGetCall) ProvisionalUserProject(provisionalUserProject string) *BucketsGetCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. Required for Requester Pays buckets. func (c *BucketsGetCall) UserProject(userProject string) *BucketsGetCall { @@ -3634,7 +3650,7 @@ func (c *BucketsGetCall) Header() http.Header { func (c *BucketsGetCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -3672,17 +3688,17 @@ func (c *BucketsGetCall) Do(opts ...googleapi.CallOption) (*Bucket, error) { if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &Bucket{ ServerResponse: googleapi.ServerResponse{ @@ -3734,11 +3750,6 @@ func (c *BucketsGetCall) Do(opts ...googleapi.CallOption) (*Bucket, error) { // "location": "query", // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request. Required for Requester Pays buckets.", // "location": "query", @@ -3772,6 +3783,8 @@ type BucketsGetIamPolicyCall struct { } // GetIamPolicy: Returns an IAM policy for the specified bucket. +// +// - bucket: Name of a bucket. func (r *BucketsService) GetIamPolicy(bucket string) *BucketsGetIamPolicyCall { c := &BucketsGetIamPolicyCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket @@ -3788,14 +3801,6 @@ func (c *BucketsGetIamPolicyCall) OptionsRequestedPolicyVersion(optionsRequested return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *BucketsGetIamPolicyCall) ProvisionalUserProject(provisionalUserProject string) *BucketsGetIamPolicyCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. Required for Requester Pays buckets. func (c *BucketsGetIamPolicyCall) UserProject(userProject string) *BucketsGetIamPolicyCall { @@ -3840,7 +3845,7 @@ func (c *BucketsGetIamPolicyCall) Header() http.Header { func (c *BucketsGetIamPolicyCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -3878,17 +3883,17 @@ func (c *BucketsGetIamPolicyCall) Do(opts ...googleapi.CallOption) (*Policy, err if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &Policy{ ServerResponse: googleapi.ServerResponse{ @@ -3922,11 +3927,6 @@ func (c *BucketsGetIamPolicyCall) Do(opts ...googleapi.CallOption) (*Policy, err // "minimum": "1", // "type": "integer" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request. Required for Requester Pays buckets.", // "location": "query", @@ -3956,6 +3956,8 @@ type BucketsInsertCall struct { } // Insert: Creates a new bucket. +// +// - project: A valid API project identifier. func (r *BucketsService) Insert(projectid string, bucket *Bucket) *BucketsInsertCall { c := &BucketsInsertCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.urlParams_.Set("project", projectid) @@ -3967,14 +3969,22 @@ func (r *BucketsService) Insert(projectid string, bucket *Bucket) *BucketsInsert // predefined set of access controls to this bucket. // // Possible values: -// "authenticatedRead" - Project team owners get OWNER access, and +// +// "authenticatedRead" - Project team owners get OWNER access, and +// // allAuthenticatedUsers get READER access. -// "private" - Project team owners get OWNER access. -// "projectPrivate" - Project team members get access according to +// +// "private" - Project team owners get OWNER access. +// "projectPrivate" - Project team members get access according to +// // their roles. -// "publicRead" - Project team owners get OWNER access, and allUsers +// +// "publicRead" - Project team owners get OWNER access, and allUsers +// // get READER access. -// "publicReadWrite" - Project team owners get OWNER access, and +// +// "publicReadWrite" - Project team owners get OWNER access, and +// // allUsers get WRITER access. func (c *BucketsInsertCall) PredefinedAcl(predefinedAcl string) *BucketsInsertCall { c.urlParams_.Set("predefinedAcl", predefinedAcl) @@ -3986,16 +3996,26 @@ func (c *BucketsInsertCall) PredefinedAcl(predefinedAcl string) *BucketsInsertCa // object access controls to this bucket. // // Possible values: -// "authenticatedRead" - Object owner gets OWNER access, and +// +// "authenticatedRead" - Object owner gets OWNER access, and +// // allAuthenticatedUsers get READER access. -// "bucketOwnerFullControl" - Object owner gets OWNER access, and +// +// "bucketOwnerFullControl" - Object owner gets OWNER access, and +// // project team owners get OWNER access. -// "bucketOwnerRead" - Object owner gets OWNER access, and project +// +// "bucketOwnerRead" - Object owner gets OWNER access, and project +// // team owners get READER access. -// "private" - Object owner gets OWNER access. -// "projectPrivate" - Object owner gets OWNER access, and project team +// +// "private" - Object owner gets OWNER access. +// "projectPrivate" - Object owner gets OWNER access, and project team +// // members get access according to their roles. -// "publicRead" - Object owner gets OWNER access, and allUsers get +// +// "publicRead" - Object owner gets OWNER access, and allUsers get +// // READER access. func (c *BucketsInsertCall) PredefinedDefaultObjectAcl(predefinedDefaultObjectAcl string) *BucketsInsertCall { c.urlParams_.Set("predefinedDefaultObjectAcl", predefinedDefaultObjectAcl) @@ -4008,21 +4028,14 @@ func (c *BucketsInsertCall) PredefinedDefaultObjectAcl(predefinedDefaultObjectAc // full. // // Possible values: -// "full" - Include all properties. -// "noAcl" - Omit owner, acl and defaultObjectAcl properties. +// +// "full" - Include all properties. +// "noAcl" - Omit owner, acl and defaultObjectAcl properties. func (c *BucketsInsertCall) Projection(projection string) *BucketsInsertCall { c.urlParams_.Set("projection", projection) return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *BucketsInsertCall) ProvisionalUserProject(provisionalUserProject string) *BucketsInsertCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. func (c *BucketsInsertCall) UserProject(userProject string) *BucketsInsertCall { @@ -4057,7 +4070,7 @@ func (c *BucketsInsertCall) Header() http.Header { func (c *BucketsInsertCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -4094,17 +4107,17 @@ func (c *BucketsInsertCall) Do(opts ...googleapi.CallOption) (*Bucket, error) { if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &Bucket{ ServerResponse: googleapi.ServerResponse{ @@ -4184,11 +4197,6 @@ func (c *BucketsInsertCall) Do(opts ...googleapi.CallOption) (*Bucket, error) { // "location": "query", // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request.", // "location": "query", @@ -4222,6 +4230,8 @@ type BucketsListCall struct { } // List: Retrieves a list of buckets for a given project. +// +// - project: A valid API project identifier. func (r *BucketsService) List(projectid string) *BucketsListCall { c := &BucketsListCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.urlParams_.Set("project", projectid) @@ -4255,21 +4265,14 @@ func (c *BucketsListCall) Prefix(prefix string) *BucketsListCall { // properties to return. Defaults to noAcl. // // Possible values: -// "full" - Include all properties. -// "noAcl" - Omit owner, acl and defaultObjectAcl properties. +// +// "full" - Include all properties. +// "noAcl" - Omit owner, acl and defaultObjectAcl properties. func (c *BucketsListCall) Projection(projection string) *BucketsListCall { c.urlParams_.Set("projection", projection) return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *BucketsListCall) ProvisionalUserProject(provisionalUserProject string) *BucketsListCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. func (c *BucketsListCall) UserProject(userProject string) *BucketsListCall { @@ -4314,7 +4317,7 @@ func (c *BucketsListCall) Header() http.Header { func (c *BucketsListCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -4349,17 +4352,17 @@ func (c *BucketsListCall) Do(opts ...googleapi.CallOption) (*Buckets, error) { if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &Buckets{ ServerResponse: googleapi.ServerResponse{ @@ -4417,11 +4420,6 @@ func (c *BucketsListCall) Do(opts ...googleapi.CallOption) (*Buckets, error) { // "location": "query", // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request.", // "location": "query", @@ -4475,6 +4473,10 @@ type BucketsLockRetentionPolicyCall struct { } // LockRetentionPolicy: Locks retention policy on a bucket. +// +// - bucket: Name of a bucket. +// - ifMetagenerationMatch: Makes the operation conditional on whether +// bucket's current metageneration matches the given value. func (r *BucketsService) LockRetentionPolicy(bucket string, ifMetagenerationMatch int64) *BucketsLockRetentionPolicyCall { c := &BucketsLockRetentionPolicyCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket @@ -4482,14 +4484,6 @@ func (r *BucketsService) LockRetentionPolicy(bucket string, ifMetagenerationMatc return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *BucketsLockRetentionPolicyCall) ProvisionalUserProject(provisionalUserProject string) *BucketsLockRetentionPolicyCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. Required for Requester Pays buckets. func (c *BucketsLockRetentionPolicyCall) UserProject(userProject string) *BucketsLockRetentionPolicyCall { @@ -4524,7 +4518,7 @@ func (c *BucketsLockRetentionPolicyCall) Header() http.Header { func (c *BucketsLockRetentionPolicyCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -4559,17 +4553,17 @@ func (c *BucketsLockRetentionPolicyCall) Do(opts ...googleapi.CallOption) (*Buck if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &Bucket{ ServerResponse: googleapi.ServerResponse{ @@ -4604,11 +4598,6 @@ func (c *BucketsLockRetentionPolicyCall) Do(opts ...googleapi.CallOption) (*Buck // "required": true, // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request. Required for Requester Pays buckets.", // "location": "query", @@ -4642,6 +4631,8 @@ type BucketsPatchCall struct { // Patch: Patches a bucket. Changes to the bucket will be readable // immediately after writing, but configuration changes may take time to // propagate. +// +// - bucket: Name of a bucket. func (r *BucketsService) Patch(bucket string, bucket2 *Bucket) *BucketsPatchCall { c := &BucketsPatchCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket @@ -4671,14 +4662,22 @@ func (c *BucketsPatchCall) IfMetagenerationNotMatch(ifMetagenerationNotMatch int // predefined set of access controls to this bucket. // // Possible values: -// "authenticatedRead" - Project team owners get OWNER access, and +// +// "authenticatedRead" - Project team owners get OWNER access, and +// // allAuthenticatedUsers get READER access. -// "private" - Project team owners get OWNER access. -// "projectPrivate" - Project team members get access according to +// +// "private" - Project team owners get OWNER access. +// "projectPrivate" - Project team members get access according to +// // their roles. -// "publicRead" - Project team owners get OWNER access, and allUsers +// +// "publicRead" - Project team owners get OWNER access, and allUsers +// // get READER access. -// "publicReadWrite" - Project team owners get OWNER access, and +// +// "publicReadWrite" - Project team owners get OWNER access, and +// // allUsers get WRITER access. func (c *BucketsPatchCall) PredefinedAcl(predefinedAcl string) *BucketsPatchCall { c.urlParams_.Set("predefinedAcl", predefinedAcl) @@ -4690,16 +4689,26 @@ func (c *BucketsPatchCall) PredefinedAcl(predefinedAcl string) *BucketsPatchCall // object access controls to this bucket. // // Possible values: -// "authenticatedRead" - Object owner gets OWNER access, and +// +// "authenticatedRead" - Object owner gets OWNER access, and +// // allAuthenticatedUsers get READER access. -// "bucketOwnerFullControl" - Object owner gets OWNER access, and +// +// "bucketOwnerFullControl" - Object owner gets OWNER access, and +// // project team owners get OWNER access. -// "bucketOwnerRead" - Object owner gets OWNER access, and project +// +// "bucketOwnerRead" - Object owner gets OWNER access, and project +// // team owners get READER access. -// "private" - Object owner gets OWNER access. -// "projectPrivate" - Object owner gets OWNER access, and project team +// +// "private" - Object owner gets OWNER access. +// "projectPrivate" - Object owner gets OWNER access, and project team +// // members get access according to their roles. -// "publicRead" - Object owner gets OWNER access, and allUsers get +// +// "publicRead" - Object owner gets OWNER access, and allUsers get +// // READER access. func (c *BucketsPatchCall) PredefinedDefaultObjectAcl(predefinedDefaultObjectAcl string) *BucketsPatchCall { c.urlParams_.Set("predefinedDefaultObjectAcl", predefinedDefaultObjectAcl) @@ -4710,21 +4719,14 @@ func (c *BucketsPatchCall) PredefinedDefaultObjectAcl(predefinedDefaultObjectAcl // properties to return. Defaults to full. // // Possible values: -// "full" - Include all properties. -// "noAcl" - Omit owner, acl and defaultObjectAcl properties. +// +// "full" - Include all properties. +// "noAcl" - Omit owner, acl and defaultObjectAcl properties. func (c *BucketsPatchCall) Projection(projection string) *BucketsPatchCall { c.urlParams_.Set("projection", projection) return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *BucketsPatchCall) ProvisionalUserProject(provisionalUserProject string) *BucketsPatchCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. Required for Requester Pays buckets. func (c *BucketsPatchCall) UserProject(userProject string) *BucketsPatchCall { @@ -4759,7 +4761,7 @@ func (c *BucketsPatchCall) Header() http.Header { func (c *BucketsPatchCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -4799,17 +4801,17 @@ func (c *BucketsPatchCall) Do(opts ...googleapi.CallOption) (*Bucket, error) { if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &Bucket{ ServerResponse: googleapi.ServerResponse{ @@ -4901,11 +4903,6 @@ func (c *BucketsPatchCall) Do(opts ...googleapi.CallOption) (*Bucket, error) { // "location": "query", // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request. Required for Requester Pays buckets.", // "location": "query", @@ -4939,6 +4936,8 @@ type BucketsSetIamPolicyCall struct { } // SetIamPolicy: Updates an IAM policy for the specified bucket. +// +// - bucket: Name of a bucket. func (r *BucketsService) SetIamPolicy(bucket string, policy *Policy) *BucketsSetIamPolicyCall { c := &BucketsSetIamPolicyCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket @@ -4946,14 +4945,6 @@ func (r *BucketsService) SetIamPolicy(bucket string, policy *Policy) *BucketsSet return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *BucketsSetIamPolicyCall) ProvisionalUserProject(provisionalUserProject string) *BucketsSetIamPolicyCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. Required for Requester Pays buckets. func (c *BucketsSetIamPolicyCall) UserProject(userProject string) *BucketsSetIamPolicyCall { @@ -4988,7 +4979,7 @@ func (c *BucketsSetIamPolicyCall) Header() http.Header { func (c *BucketsSetIamPolicyCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -5028,17 +5019,17 @@ func (c *BucketsSetIamPolicyCall) Do(opts ...googleapi.CallOption) (*Policy, err if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &Policy{ ServerResponse: googleapi.ServerResponse{ @@ -5065,11 +5056,6 @@ func (c *BucketsSetIamPolicyCall) Do(opts ...googleapi.CallOption) (*Policy, err // "required": true, // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request. Required for Requester Pays buckets.", // "location": "query", @@ -5104,6 +5090,9 @@ type BucketsTestIamPermissionsCall struct { // TestIamPermissions: Tests a set of permissions on the given bucket to // see which, if any, are held by the caller. +// +// - bucket: Name of a bucket. +// - permissions: Permissions to test. func (r *BucketsService) TestIamPermissions(bucket string, permissions []string) *BucketsTestIamPermissionsCall { c := &BucketsTestIamPermissionsCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket @@ -5111,14 +5100,6 @@ func (r *BucketsService) TestIamPermissions(bucket string, permissions []string) return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *BucketsTestIamPermissionsCall) ProvisionalUserProject(provisionalUserProject string) *BucketsTestIamPermissionsCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. Required for Requester Pays buckets. func (c *BucketsTestIamPermissionsCall) UserProject(userProject string) *BucketsTestIamPermissionsCall { @@ -5163,7 +5144,7 @@ func (c *BucketsTestIamPermissionsCall) Header() http.Header { func (c *BucketsTestIamPermissionsCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -5201,17 +5182,17 @@ func (c *BucketsTestIamPermissionsCall) Do(opts ...googleapi.CallOption) (*TestI if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &TestIamPermissionsResponse{ ServerResponse: googleapi.ServerResponse{ @@ -5246,11 +5227,6 @@ func (c *BucketsTestIamPermissionsCall) Do(opts ...googleapi.CallOption) (*TestI // "required": true, // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request. Required for Requester Pays buckets.", // "location": "query", @@ -5286,6 +5262,8 @@ type BucketsUpdateCall struct { // Update: Updates a bucket. Changes to the bucket will be readable // immediately after writing, but configuration changes may take time to // propagate. +// +// - bucket: Name of a bucket. func (r *BucketsService) Update(bucket string, bucket2 *Bucket) *BucketsUpdateCall { c := &BucketsUpdateCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket @@ -5315,14 +5293,22 @@ func (c *BucketsUpdateCall) IfMetagenerationNotMatch(ifMetagenerationNotMatch in // predefined set of access controls to this bucket. // // Possible values: -// "authenticatedRead" - Project team owners get OWNER access, and +// +// "authenticatedRead" - Project team owners get OWNER access, and +// // allAuthenticatedUsers get READER access. -// "private" - Project team owners get OWNER access. -// "projectPrivate" - Project team members get access according to +// +// "private" - Project team owners get OWNER access. +// "projectPrivate" - Project team members get access according to +// // their roles. -// "publicRead" - Project team owners get OWNER access, and allUsers +// +// "publicRead" - Project team owners get OWNER access, and allUsers +// // get READER access. -// "publicReadWrite" - Project team owners get OWNER access, and +// +// "publicReadWrite" - Project team owners get OWNER access, and +// // allUsers get WRITER access. func (c *BucketsUpdateCall) PredefinedAcl(predefinedAcl string) *BucketsUpdateCall { c.urlParams_.Set("predefinedAcl", predefinedAcl) @@ -5334,16 +5320,26 @@ func (c *BucketsUpdateCall) PredefinedAcl(predefinedAcl string) *BucketsUpdateCa // object access controls to this bucket. // // Possible values: -// "authenticatedRead" - Object owner gets OWNER access, and +// +// "authenticatedRead" - Object owner gets OWNER access, and +// // allAuthenticatedUsers get READER access. -// "bucketOwnerFullControl" - Object owner gets OWNER access, and +// +// "bucketOwnerFullControl" - Object owner gets OWNER access, and +// // project team owners get OWNER access. -// "bucketOwnerRead" - Object owner gets OWNER access, and project +// +// "bucketOwnerRead" - Object owner gets OWNER access, and project +// // team owners get READER access. -// "private" - Object owner gets OWNER access. -// "projectPrivate" - Object owner gets OWNER access, and project team +// +// "private" - Object owner gets OWNER access. +// "projectPrivate" - Object owner gets OWNER access, and project team +// // members get access according to their roles. -// "publicRead" - Object owner gets OWNER access, and allUsers get +// +// "publicRead" - Object owner gets OWNER access, and allUsers get +// // READER access. func (c *BucketsUpdateCall) PredefinedDefaultObjectAcl(predefinedDefaultObjectAcl string) *BucketsUpdateCall { c.urlParams_.Set("predefinedDefaultObjectAcl", predefinedDefaultObjectAcl) @@ -5354,21 +5350,14 @@ func (c *BucketsUpdateCall) PredefinedDefaultObjectAcl(predefinedDefaultObjectAc // properties to return. Defaults to full. // // Possible values: -// "full" - Include all properties. -// "noAcl" - Omit owner, acl and defaultObjectAcl properties. +// +// "full" - Include all properties. +// "noAcl" - Omit owner, acl and defaultObjectAcl properties. func (c *BucketsUpdateCall) Projection(projection string) *BucketsUpdateCall { c.urlParams_.Set("projection", projection) return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *BucketsUpdateCall) ProvisionalUserProject(provisionalUserProject string) *BucketsUpdateCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. Required for Requester Pays buckets. func (c *BucketsUpdateCall) UserProject(userProject string) *BucketsUpdateCall { @@ -5403,7 +5392,7 @@ func (c *BucketsUpdateCall) Header() http.Header { func (c *BucketsUpdateCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -5443,17 +5432,17 @@ func (c *BucketsUpdateCall) Do(opts ...googleapi.CallOption) (*Bucket, error) { if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &Bucket{ ServerResponse: googleapi.ServerResponse{ @@ -5545,11 +5534,6 @@ func (c *BucketsUpdateCall) Do(opts ...googleapi.CallOption) (*Bucket, error) { // "location": "query", // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request. Required for Requester Pays buckets.", // "location": "query", @@ -5615,7 +5599,7 @@ func (c *ChannelsStopCall) Header() http.Header { func (c *ChannelsStopCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -5647,7 +5631,7 @@ func (c *ChannelsStopCall) Do(opts ...googleapi.CallOption) error { } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return err + return gensupport.WrapError(err) } return nil // { @@ -5683,6 +5667,11 @@ type DefaultObjectAccessControlsDeleteCall struct { // Delete: Permanently deletes the default object ACL entry for the // specified entity on the specified bucket. +// +// - bucket: Name of a bucket. +// - entity: The entity holding the permission. Can be user-userId, +// user-emailAddress, group-groupId, group-emailAddress, allUsers, or +// allAuthenticatedUsers. func (r *DefaultObjectAccessControlsService) Delete(bucket string, entity string) *DefaultObjectAccessControlsDeleteCall { c := &DefaultObjectAccessControlsDeleteCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket @@ -5690,14 +5679,6 @@ func (r *DefaultObjectAccessControlsService) Delete(bucket string, entity string return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *DefaultObjectAccessControlsDeleteCall) ProvisionalUserProject(provisionalUserProject string) *DefaultObjectAccessControlsDeleteCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. Required for Requester Pays buckets. func (c *DefaultObjectAccessControlsDeleteCall) UserProject(userProject string) *DefaultObjectAccessControlsDeleteCall { @@ -5732,7 +5713,7 @@ func (c *DefaultObjectAccessControlsDeleteCall) Header() http.Header { func (c *DefaultObjectAccessControlsDeleteCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -5763,7 +5744,7 @@ func (c *DefaultObjectAccessControlsDeleteCall) Do(opts ...googleapi.CallOption) } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return err + return gensupport.WrapError(err) } return nil // { @@ -5787,11 +5768,6 @@ func (c *DefaultObjectAccessControlsDeleteCall) Do(opts ...googleapi.CallOption) // "required": true, // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request. Required for Requester Pays buckets.", // "location": "query", @@ -5821,6 +5797,11 @@ type DefaultObjectAccessControlsGetCall struct { // Get: Returns the default object ACL entry for the specified entity on // the specified bucket. +// +// - bucket: Name of a bucket. +// - entity: The entity holding the permission. Can be user-userId, +// user-emailAddress, group-groupId, group-emailAddress, allUsers, or +// allAuthenticatedUsers. func (r *DefaultObjectAccessControlsService) Get(bucket string, entity string) *DefaultObjectAccessControlsGetCall { c := &DefaultObjectAccessControlsGetCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket @@ -5828,14 +5809,6 @@ func (r *DefaultObjectAccessControlsService) Get(bucket string, entity string) * return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *DefaultObjectAccessControlsGetCall) ProvisionalUserProject(provisionalUserProject string) *DefaultObjectAccessControlsGetCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. Required for Requester Pays buckets. func (c *DefaultObjectAccessControlsGetCall) UserProject(userProject string) *DefaultObjectAccessControlsGetCall { @@ -5880,7 +5853,7 @@ func (c *DefaultObjectAccessControlsGetCall) Header() http.Header { func (c *DefaultObjectAccessControlsGetCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -5919,17 +5892,17 @@ func (c *DefaultObjectAccessControlsGetCall) Do(opts ...googleapi.CallOption) (* if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &ObjectAccessControl{ ServerResponse: googleapi.ServerResponse{ @@ -5963,11 +5936,6 @@ func (c *DefaultObjectAccessControlsGetCall) Do(opts ...googleapi.CallOption) (* // "required": true, // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request. Required for Requester Pays buckets.", // "location": "query", @@ -5999,6 +5967,8 @@ type DefaultObjectAccessControlsInsertCall struct { // Insert: Creates a new default object ACL entry on the specified // bucket. +// +// - bucket: Name of a bucket. func (r *DefaultObjectAccessControlsService) Insert(bucket string, objectaccesscontrol *ObjectAccessControl) *DefaultObjectAccessControlsInsertCall { c := &DefaultObjectAccessControlsInsertCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket @@ -6006,14 +5976,6 @@ func (r *DefaultObjectAccessControlsService) Insert(bucket string, objectaccessc return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *DefaultObjectAccessControlsInsertCall) ProvisionalUserProject(provisionalUserProject string) *DefaultObjectAccessControlsInsertCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. Required for Requester Pays buckets. func (c *DefaultObjectAccessControlsInsertCall) UserProject(userProject string) *DefaultObjectAccessControlsInsertCall { @@ -6048,7 +6010,7 @@ func (c *DefaultObjectAccessControlsInsertCall) Header() http.Header { func (c *DefaultObjectAccessControlsInsertCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -6088,17 +6050,17 @@ func (c *DefaultObjectAccessControlsInsertCall) Do(opts ...googleapi.CallOption) if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &ObjectAccessControl{ ServerResponse: googleapi.ServerResponse{ @@ -6125,11 +6087,6 @@ func (c *DefaultObjectAccessControlsInsertCall) Do(opts ...googleapi.CallOption) // "required": true, // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request. Required for Requester Pays buckets.", // "location": "query", @@ -6163,6 +6120,8 @@ type DefaultObjectAccessControlsListCall struct { } // List: Retrieves default object ACL entries on the specified bucket. +// +// - bucket: Name of a bucket. func (r *DefaultObjectAccessControlsService) List(bucket string) *DefaultObjectAccessControlsListCall { c := &DefaultObjectAccessControlsListCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket @@ -6186,14 +6145,6 @@ func (c *DefaultObjectAccessControlsListCall) IfMetagenerationNotMatch(ifMetagen return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *DefaultObjectAccessControlsListCall) ProvisionalUserProject(provisionalUserProject string) *DefaultObjectAccessControlsListCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. Required for Requester Pays buckets. func (c *DefaultObjectAccessControlsListCall) UserProject(userProject string) *DefaultObjectAccessControlsListCall { @@ -6238,7 +6189,7 @@ func (c *DefaultObjectAccessControlsListCall) Header() http.Header { func (c *DefaultObjectAccessControlsListCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -6276,17 +6227,17 @@ func (c *DefaultObjectAccessControlsListCall) Do(opts ...googleapi.CallOption) ( if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &ObjectAccessControls{ ServerResponse: googleapi.ServerResponse{ @@ -6325,11 +6276,6 @@ func (c *DefaultObjectAccessControlsListCall) Do(opts ...googleapi.CallOption) ( // "location": "query", // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request. Required for Requester Pays buckets.", // "location": "query", @@ -6361,6 +6307,11 @@ type DefaultObjectAccessControlsPatchCall struct { } // Patch: Patches a default object ACL entry on the specified bucket. +// +// - bucket: Name of a bucket. +// - entity: The entity holding the permission. Can be user-userId, +// user-emailAddress, group-groupId, group-emailAddress, allUsers, or +// allAuthenticatedUsers. func (r *DefaultObjectAccessControlsService) Patch(bucket string, entity string, objectaccesscontrol *ObjectAccessControl) *DefaultObjectAccessControlsPatchCall { c := &DefaultObjectAccessControlsPatchCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket @@ -6369,14 +6320,6 @@ func (r *DefaultObjectAccessControlsService) Patch(bucket string, entity string, return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *DefaultObjectAccessControlsPatchCall) ProvisionalUserProject(provisionalUserProject string) *DefaultObjectAccessControlsPatchCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. Required for Requester Pays buckets. func (c *DefaultObjectAccessControlsPatchCall) UserProject(userProject string) *DefaultObjectAccessControlsPatchCall { @@ -6411,7 +6354,7 @@ func (c *DefaultObjectAccessControlsPatchCall) Header() http.Header { func (c *DefaultObjectAccessControlsPatchCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -6452,17 +6395,17 @@ func (c *DefaultObjectAccessControlsPatchCall) Do(opts ...googleapi.CallOption) if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &ObjectAccessControl{ ServerResponse: googleapi.ServerResponse{ @@ -6496,11 +6439,6 @@ func (c *DefaultObjectAccessControlsPatchCall) Do(opts ...googleapi.CallOption) // "required": true, // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request. Required for Requester Pays buckets.", // "location": "query", @@ -6535,6 +6473,11 @@ type DefaultObjectAccessControlsUpdateCall struct { } // Update: Updates a default object ACL entry on the specified bucket. +// +// - bucket: Name of a bucket. +// - entity: The entity holding the permission. Can be user-userId, +// user-emailAddress, group-groupId, group-emailAddress, allUsers, or +// allAuthenticatedUsers. func (r *DefaultObjectAccessControlsService) Update(bucket string, entity string, objectaccesscontrol *ObjectAccessControl) *DefaultObjectAccessControlsUpdateCall { c := &DefaultObjectAccessControlsUpdateCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket @@ -6543,14 +6486,6 @@ func (r *DefaultObjectAccessControlsService) Update(bucket string, entity string return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *DefaultObjectAccessControlsUpdateCall) ProvisionalUserProject(provisionalUserProject string) *DefaultObjectAccessControlsUpdateCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. Required for Requester Pays buckets. func (c *DefaultObjectAccessControlsUpdateCall) UserProject(userProject string) *DefaultObjectAccessControlsUpdateCall { @@ -6585,7 +6520,7 @@ func (c *DefaultObjectAccessControlsUpdateCall) Header() http.Header { func (c *DefaultObjectAccessControlsUpdateCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -6626,17 +6561,17 @@ func (c *DefaultObjectAccessControlsUpdateCall) Do(opts ...googleapi.CallOption) if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &ObjectAccessControl{ ServerResponse: googleapi.ServerResponse{ @@ -6670,11 +6605,6 @@ func (c *DefaultObjectAccessControlsUpdateCall) Do(opts ...googleapi.CallOption) // "required": true, // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request. Required for Requester Pays buckets.", // "location": "query", @@ -6708,6 +6638,9 @@ type NotificationsDeleteCall struct { } // Delete: Permanently deletes a notification subscription. +// +// - bucket: The parent bucket of the notification. +// - notification: ID of the notification to delete. func (r *NotificationsService) Delete(bucket string, notification string) *NotificationsDeleteCall { c := &NotificationsDeleteCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket @@ -6715,14 +6648,6 @@ func (r *NotificationsService) Delete(bucket string, notification string) *Notif return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *NotificationsDeleteCall) ProvisionalUserProject(provisionalUserProject string) *NotificationsDeleteCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. Required for Requester Pays buckets. func (c *NotificationsDeleteCall) UserProject(userProject string) *NotificationsDeleteCall { @@ -6757,7 +6682,7 @@ func (c *NotificationsDeleteCall) Header() http.Header { func (c *NotificationsDeleteCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -6788,7 +6713,7 @@ func (c *NotificationsDeleteCall) Do(opts ...googleapi.CallOption) error { } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return err + return gensupport.WrapError(err) } return nil // { @@ -6812,11 +6737,6 @@ func (c *NotificationsDeleteCall) Do(opts ...googleapi.CallOption) error { // "required": true, // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request. Required for Requester Pays buckets.", // "location": "query", @@ -6846,6 +6766,9 @@ type NotificationsGetCall struct { } // Get: View a notification configuration. +// +// - bucket: The parent bucket of the notification. +// - notification: Notification ID. func (r *NotificationsService) Get(bucket string, notification string) *NotificationsGetCall { c := &NotificationsGetCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket @@ -6853,14 +6776,6 @@ func (r *NotificationsService) Get(bucket string, notification string) *Notifica return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *NotificationsGetCall) ProvisionalUserProject(provisionalUserProject string) *NotificationsGetCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. Required for Requester Pays buckets. func (c *NotificationsGetCall) UserProject(userProject string) *NotificationsGetCall { @@ -6905,7 +6820,7 @@ func (c *NotificationsGetCall) Header() http.Header { func (c *NotificationsGetCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -6944,17 +6859,17 @@ func (c *NotificationsGetCall) Do(opts ...googleapi.CallOption) (*Notification, if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &Notification{ ServerResponse: googleapi.ServerResponse{ @@ -6988,11 +6903,6 @@ func (c *NotificationsGetCall) Do(opts ...googleapi.CallOption) (*Notification, // "required": true, // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request. Required for Requester Pays buckets.", // "location": "query", @@ -7026,6 +6936,8 @@ type NotificationsInsertCall struct { } // Insert: Creates a notification subscription for a given bucket. +// +// - bucket: The parent bucket of the notification. func (r *NotificationsService) Insert(bucket string, notification *Notification) *NotificationsInsertCall { c := &NotificationsInsertCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket @@ -7033,14 +6945,6 @@ func (r *NotificationsService) Insert(bucket string, notification *Notification) return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *NotificationsInsertCall) ProvisionalUserProject(provisionalUserProject string) *NotificationsInsertCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. Required for Requester Pays buckets. func (c *NotificationsInsertCall) UserProject(userProject string) *NotificationsInsertCall { @@ -7075,7 +6979,7 @@ func (c *NotificationsInsertCall) Header() http.Header { func (c *NotificationsInsertCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -7115,17 +7019,17 @@ func (c *NotificationsInsertCall) Do(opts ...googleapi.CallOption) (*Notificatio if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &Notification{ ServerResponse: googleapi.ServerResponse{ @@ -7152,11 +7056,6 @@ func (c *NotificationsInsertCall) Do(opts ...googleapi.CallOption) (*Notificatio // "required": true, // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request. Required for Requester Pays buckets.", // "location": "query", @@ -7192,20 +7091,14 @@ type NotificationsListCall struct { // List: Retrieves a list of notification subscriptions for a given // bucket. +// +// - bucket: Name of a Google Cloud Storage bucket. func (r *NotificationsService) List(bucket string) *NotificationsListCall { c := &NotificationsListCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *NotificationsListCall) ProvisionalUserProject(provisionalUserProject string) *NotificationsListCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. Required for Requester Pays buckets. func (c *NotificationsListCall) UserProject(userProject string) *NotificationsListCall { @@ -7250,7 +7143,7 @@ func (c *NotificationsListCall) Header() http.Header { func (c *NotificationsListCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -7288,17 +7181,17 @@ func (c *NotificationsListCall) Do(opts ...googleapi.CallOption) (*Notifications if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &Notifications{ ServerResponse: googleapi.ServerResponse{ @@ -7325,11 +7218,6 @@ func (c *NotificationsListCall) Do(opts ...googleapi.CallOption) (*Notifications // "required": true, // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request. Required for Requester Pays buckets.", // "location": "query", @@ -7365,6 +7253,13 @@ type ObjectAccessControlsDeleteCall struct { // Delete: Permanently deletes the ACL entry for the specified entity on // the specified object. +// +// - bucket: Name of a bucket. +// - entity: The entity holding the permission. Can be user-userId, +// user-emailAddress, group-groupId, group-emailAddress, allUsers, or +// allAuthenticatedUsers. +// - object: Name of the object. For information about how to URL encode +// object names to be path safe, see Encoding URI Path Parts. func (r *ObjectAccessControlsService) Delete(bucket string, object string, entity string) *ObjectAccessControlsDeleteCall { c := &ObjectAccessControlsDeleteCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket @@ -7381,14 +7276,6 @@ func (c *ObjectAccessControlsDeleteCall) Generation(generation int64) *ObjectAcc return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *ObjectAccessControlsDeleteCall) ProvisionalUserProject(provisionalUserProject string) *ObjectAccessControlsDeleteCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. Required for Requester Pays buckets. func (c *ObjectAccessControlsDeleteCall) UserProject(userProject string) *ObjectAccessControlsDeleteCall { @@ -7423,7 +7310,7 @@ func (c *ObjectAccessControlsDeleteCall) Header() http.Header { func (c *ObjectAccessControlsDeleteCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -7455,7 +7342,7 @@ func (c *ObjectAccessControlsDeleteCall) Do(opts ...googleapi.CallOption) error } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return err + return gensupport.WrapError(err) } return nil // { @@ -7492,11 +7379,6 @@ func (c *ObjectAccessControlsDeleteCall) Do(opts ...googleapi.CallOption) error // "required": true, // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request. Required for Requester Pays buckets.", // "location": "query", @@ -7527,6 +7409,13 @@ type ObjectAccessControlsGetCall struct { // Get: Returns the ACL entry for the specified entity on the specified // object. +// +// - bucket: Name of a bucket. +// - entity: The entity holding the permission. Can be user-userId, +// user-emailAddress, group-groupId, group-emailAddress, allUsers, or +// allAuthenticatedUsers. +// - object: Name of the object. For information about how to URL encode +// object names to be path safe, see Encoding URI Path Parts. func (r *ObjectAccessControlsService) Get(bucket string, object string, entity string) *ObjectAccessControlsGetCall { c := &ObjectAccessControlsGetCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket @@ -7543,14 +7432,6 @@ func (c *ObjectAccessControlsGetCall) Generation(generation int64) *ObjectAccess return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *ObjectAccessControlsGetCall) ProvisionalUserProject(provisionalUserProject string) *ObjectAccessControlsGetCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. Required for Requester Pays buckets. func (c *ObjectAccessControlsGetCall) UserProject(userProject string) *ObjectAccessControlsGetCall { @@ -7595,7 +7476,7 @@ func (c *ObjectAccessControlsGetCall) Header() http.Header { func (c *ObjectAccessControlsGetCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -7635,17 +7516,17 @@ func (c *ObjectAccessControlsGetCall) Do(opts ...googleapi.CallOption) (*ObjectA if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &ObjectAccessControl{ ServerResponse: googleapi.ServerResponse{ @@ -7692,11 +7573,6 @@ func (c *ObjectAccessControlsGetCall) Do(opts ...googleapi.CallOption) (*ObjectA // "required": true, // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request. Required for Requester Pays buckets.", // "location": "query", @@ -7728,6 +7604,10 @@ type ObjectAccessControlsInsertCall struct { } // Insert: Creates a new ACL entry on the specified object. +// +// - bucket: Name of a bucket. +// - object: Name of the object. For information about how to URL encode +// object names to be path safe, see Encoding URI Path Parts. func (r *ObjectAccessControlsService) Insert(bucket string, object string, objectaccesscontrol *ObjectAccessControl) *ObjectAccessControlsInsertCall { c := &ObjectAccessControlsInsertCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket @@ -7744,14 +7624,6 @@ func (c *ObjectAccessControlsInsertCall) Generation(generation int64) *ObjectAcc return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *ObjectAccessControlsInsertCall) ProvisionalUserProject(provisionalUserProject string) *ObjectAccessControlsInsertCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. Required for Requester Pays buckets. func (c *ObjectAccessControlsInsertCall) UserProject(userProject string) *ObjectAccessControlsInsertCall { @@ -7786,7 +7658,7 @@ func (c *ObjectAccessControlsInsertCall) Header() http.Header { func (c *ObjectAccessControlsInsertCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -7827,17 +7699,17 @@ func (c *ObjectAccessControlsInsertCall) Do(opts ...googleapi.CallOption) (*Obje if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &ObjectAccessControl{ ServerResponse: googleapi.ServerResponse{ @@ -7877,11 +7749,6 @@ func (c *ObjectAccessControlsInsertCall) Do(opts ...googleapi.CallOption) (*Obje // "required": true, // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request. Required for Requester Pays buckets.", // "location": "query", @@ -7916,6 +7783,10 @@ type ObjectAccessControlsListCall struct { } // List: Retrieves ACL entries on the specified object. +// +// - bucket: Name of a bucket. +// - object: Name of the object. For information about how to URL encode +// object names to be path safe, see Encoding URI Path Parts. func (r *ObjectAccessControlsService) List(bucket string, object string) *ObjectAccessControlsListCall { c := &ObjectAccessControlsListCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket @@ -7931,14 +7802,6 @@ func (c *ObjectAccessControlsListCall) Generation(generation int64) *ObjectAcces return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *ObjectAccessControlsListCall) ProvisionalUserProject(provisionalUserProject string) *ObjectAccessControlsListCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. Required for Requester Pays buckets. func (c *ObjectAccessControlsListCall) UserProject(userProject string) *ObjectAccessControlsListCall { @@ -7983,7 +7846,7 @@ func (c *ObjectAccessControlsListCall) Header() http.Header { func (c *ObjectAccessControlsListCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -8022,17 +7885,17 @@ func (c *ObjectAccessControlsListCall) Do(opts ...googleapi.CallOption) (*Object if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &ObjectAccessControls{ ServerResponse: googleapi.ServerResponse{ @@ -8072,11 +7935,6 @@ func (c *ObjectAccessControlsListCall) Do(opts ...googleapi.CallOption) (*Object // "required": true, // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request. Required for Requester Pays buckets.", // "location": "query", @@ -8109,6 +7967,13 @@ type ObjectAccessControlsPatchCall struct { } // Patch: Patches an ACL entry on the specified object. +// +// - bucket: Name of a bucket. +// - entity: The entity holding the permission. Can be user-userId, +// user-emailAddress, group-groupId, group-emailAddress, allUsers, or +// allAuthenticatedUsers. +// - object: Name of the object. For information about how to URL encode +// object names to be path safe, see Encoding URI Path Parts. func (r *ObjectAccessControlsService) Patch(bucket string, object string, entity string, objectaccesscontrol *ObjectAccessControl) *ObjectAccessControlsPatchCall { c := &ObjectAccessControlsPatchCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket @@ -8126,14 +7991,6 @@ func (c *ObjectAccessControlsPatchCall) Generation(generation int64) *ObjectAcce return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *ObjectAccessControlsPatchCall) ProvisionalUserProject(provisionalUserProject string) *ObjectAccessControlsPatchCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. Required for Requester Pays buckets. func (c *ObjectAccessControlsPatchCall) UserProject(userProject string) *ObjectAccessControlsPatchCall { @@ -8168,7 +8025,7 @@ func (c *ObjectAccessControlsPatchCall) Header() http.Header { func (c *ObjectAccessControlsPatchCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -8210,17 +8067,17 @@ func (c *ObjectAccessControlsPatchCall) Do(opts ...googleapi.CallOption) (*Objec if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &ObjectAccessControl{ ServerResponse: googleapi.ServerResponse{ @@ -8267,11 +8124,6 @@ func (c *ObjectAccessControlsPatchCall) Do(opts ...googleapi.CallOption) (*Objec // "required": true, // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request. Required for Requester Pays buckets.", // "location": "query", @@ -8307,6 +8159,13 @@ type ObjectAccessControlsUpdateCall struct { } // Update: Updates an ACL entry on the specified object. +// +// - bucket: Name of a bucket. +// - entity: The entity holding the permission. Can be user-userId, +// user-emailAddress, group-groupId, group-emailAddress, allUsers, or +// allAuthenticatedUsers. +// - object: Name of the object. For information about how to URL encode +// object names to be path safe, see Encoding URI Path Parts. func (r *ObjectAccessControlsService) Update(bucket string, object string, entity string, objectaccesscontrol *ObjectAccessControl) *ObjectAccessControlsUpdateCall { c := &ObjectAccessControlsUpdateCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket @@ -8324,14 +8183,6 @@ func (c *ObjectAccessControlsUpdateCall) Generation(generation int64) *ObjectAcc return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *ObjectAccessControlsUpdateCall) ProvisionalUserProject(provisionalUserProject string) *ObjectAccessControlsUpdateCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. Required for Requester Pays buckets. func (c *ObjectAccessControlsUpdateCall) UserProject(userProject string) *ObjectAccessControlsUpdateCall { @@ -8366,7 +8217,7 @@ func (c *ObjectAccessControlsUpdateCall) Header() http.Header { func (c *ObjectAccessControlsUpdateCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -8408,17 +8259,17 @@ func (c *ObjectAccessControlsUpdateCall) Do(opts ...googleapi.CallOption) (*Obje if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &ObjectAccessControl{ ServerResponse: googleapi.ServerResponse{ @@ -8465,11 +8316,6 @@ func (c *ObjectAccessControlsUpdateCall) Do(opts ...googleapi.CallOption) (*Obje // "required": true, // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request. Required for Requester Pays buckets.", // "location": "query", @@ -8505,6 +8351,12 @@ type ObjectsComposeCall struct { // Compose: Concatenates a list of existing objects into a new object in // the same bucket. +// +// - destinationBucket: Name of the bucket containing the source +// objects. The destination object is stored in this bucket. +// - destinationObject: Name of the new object. For information about +// how to URL encode object names to be path safe, see Encoding URI +// Path Parts. func (r *ObjectsService) Compose(destinationBucket string, destinationObject string, composerequest *ComposeRequest) *ObjectsComposeCall { c := &ObjectsComposeCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.destinationBucket = destinationBucket @@ -8518,16 +8370,26 @@ func (r *ObjectsService) Compose(destinationBucket string, destinationObject str // to the destination object. // // Possible values: -// "authenticatedRead" - Object owner gets OWNER access, and +// +// "authenticatedRead" - Object owner gets OWNER access, and +// // allAuthenticatedUsers get READER access. -// "bucketOwnerFullControl" - Object owner gets OWNER access, and +// +// "bucketOwnerFullControl" - Object owner gets OWNER access, and +// // project team owners get OWNER access. -// "bucketOwnerRead" - Object owner gets OWNER access, and project +// +// "bucketOwnerRead" - Object owner gets OWNER access, and project +// // team owners get READER access. -// "private" - Object owner gets OWNER access. -// "projectPrivate" - Object owner gets OWNER access, and project team +// +// "private" - Object owner gets OWNER access. +// "projectPrivate" - Object owner gets OWNER access, and project team +// // members get access according to their roles. -// "publicRead" - Object owner gets OWNER access, and allUsers get +// +// "publicRead" - Object owner gets OWNER access, and allUsers get +// // READER access. func (c *ObjectsComposeCall) DestinationPredefinedAcl(destinationPredefinedAcl string) *ObjectsComposeCall { c.urlParams_.Set("destinationPredefinedAcl", destinationPredefinedAcl) @@ -8554,21 +8416,15 @@ func (c *ObjectsComposeCall) IfMetagenerationMatch(ifMetagenerationMatch int64) // KmsKeyName sets the optional parameter "kmsKeyName": Resource name of // the Cloud KMS key, of the form // projects/my-project/locations/global/keyRings/my-kr/cryptoKeys/my-key, -// that will be used to encrypt the object. Overrides the object +// +// that will be used to encrypt the object. Overrides the object +// // metadata's kms_key_name value, if any. func (c *ObjectsComposeCall) KmsKeyName(kmsKeyName string) *ObjectsComposeCall { c.urlParams_.Set("kmsKeyName", kmsKeyName) return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *ObjectsComposeCall) ProvisionalUserProject(provisionalUserProject string) *ObjectsComposeCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. Required for Requester Pays buckets. func (c *ObjectsComposeCall) UserProject(userProject string) *ObjectsComposeCall { @@ -8603,7 +8459,7 @@ func (c *ObjectsComposeCall) Header() http.Header { func (c *ObjectsComposeCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -8644,17 +8500,17 @@ func (c *ObjectsComposeCall) Do(opts ...googleapi.CallOption) (*Object, error) { if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &Object{ ServerResponse: googleapi.ServerResponse{ @@ -8726,11 +8582,6 @@ func (c *ObjectsComposeCall) Do(opts ...googleapi.CallOption) (*Object, error) { // "location": "query", // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request. Required for Requester Pays buckets.", // "location": "query", @@ -8769,6 +8620,19 @@ type ObjectsCopyCall struct { // Copy: Copies a source object to a destination object. Optionally // overrides metadata. +// +// - destinationBucket: Name of the bucket in which to store the new +// object. Overrides the provided object metadata's bucket value, if +// any.For information about how to URL encode object names to be path +// safe, see Encoding URI Path Parts. +// - destinationObject: Name of the new object. Required when the object +// metadata is not otherwise provided. Overrides the object metadata's +// name value, if any. +// - sourceBucket: Name of the bucket in which to find the source +// object. +// - sourceObject: Name of the source object. For information about how +// to URL encode object names to be path safe, see Encoding URI Path +// Parts. func (r *ObjectsService) Copy(sourceBucket string, sourceObject string, destinationBucket string, destinationObject string, object *Object) *ObjectsCopyCall { c := &ObjectsCopyCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.sourceBucket = sourceBucket @@ -8783,7 +8647,9 @@ func (r *ObjectsService) Copy(sourceBucket string, sourceObject string, destinat // "destinationKmsKeyName": Resource name of the Cloud KMS key, of the // form // projects/my-project/locations/global/keyRings/my-kr/cryptoKeys/my-key, -// that will be used to encrypt the object. Overrides the object +// +// that will be used to encrypt the object. Overrides the object +// // metadata's kms_key_name value, if any. func (c *ObjectsCopyCall) DestinationKmsKeyName(destinationKmsKeyName string) *ObjectsCopyCall { c.urlParams_.Set("destinationKmsKeyName", destinationKmsKeyName) @@ -8795,16 +8661,26 @@ func (c *ObjectsCopyCall) DestinationKmsKeyName(destinationKmsKeyName string) *O // to the destination object. // // Possible values: -// "authenticatedRead" - Object owner gets OWNER access, and +// +// "authenticatedRead" - Object owner gets OWNER access, and +// // allAuthenticatedUsers get READER access. -// "bucketOwnerFullControl" - Object owner gets OWNER access, and +// +// "bucketOwnerFullControl" - Object owner gets OWNER access, and +// // project team owners get OWNER access. -// "bucketOwnerRead" - Object owner gets OWNER access, and project +// +// "bucketOwnerRead" - Object owner gets OWNER access, and project +// // team owners get READER access. -// "private" - Object owner gets OWNER access. -// "projectPrivate" - Object owner gets OWNER access, and project team +// +// "private" - Object owner gets OWNER access. +// "projectPrivate" - Object owner gets OWNER access, and project team +// // members get access according to their roles. -// "publicRead" - Object owner gets OWNER access, and allUsers get +// +// "publicRead" - Object owner gets OWNER access, and allUsers get +// // READER access. func (c *ObjectsCopyCall) DestinationPredefinedAcl(destinationPredefinedAcl string) *ObjectsCopyCall { c.urlParams_.Set("destinationPredefinedAcl", destinationPredefinedAcl) @@ -8889,21 +8765,14 @@ func (c *ObjectsCopyCall) IfSourceMetagenerationNotMatch(ifSourceMetagenerationN // specifies the acl property, when it defaults to full. // // Possible values: -// "full" - Include all properties. -// "noAcl" - Omit the owner, acl property. +// +// "full" - Include all properties. +// "noAcl" - Omit the owner, acl property. func (c *ObjectsCopyCall) Projection(projection string) *ObjectsCopyCall { c.urlParams_.Set("projection", projection) return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *ObjectsCopyCall) ProvisionalUserProject(provisionalUserProject string) *ObjectsCopyCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // SourceGeneration sets the optional parameter "sourceGeneration": If // present, selects a specific revision of the source object (as opposed // to the latest version, the default). @@ -8946,7 +8815,7 @@ func (c *ObjectsCopyCall) Header() http.Header { func (c *ObjectsCopyCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -8989,17 +8858,17 @@ func (c *ObjectsCopyCall) Do(opts ...googleapi.CallOption) (*Object, error) { if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &Object{ ServerResponse: googleapi.ServerResponse{ @@ -9122,11 +8991,6 @@ func (c *ObjectsCopyCall) Do(opts ...googleapi.CallOption) (*Object, error) { // "location": "query", // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "sourceBucket": { // "description": "Name of the bucket in which to find the source object.", // "location": "path", @@ -9181,6 +9045,10 @@ type ObjectsDeleteCall struct { // Delete: Deletes an object and its metadata. Deletions are permanent // if versioning is not enabled for the bucket, or if the generation // parameter is used. +// +// - bucket: Name of the bucket in which the object resides. +// - object: Name of the object. For information about how to URL encode +// object names to be path safe, see Encoding URI Path Parts. func (r *ObjectsService) Delete(bucket string, object string) *ObjectsDeleteCall { c := &ObjectsDeleteCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket @@ -9232,14 +9100,6 @@ func (c *ObjectsDeleteCall) IfMetagenerationNotMatch(ifMetagenerationNotMatch in return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *ObjectsDeleteCall) ProvisionalUserProject(provisionalUserProject string) *ObjectsDeleteCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. Required for Requester Pays buckets. func (c *ObjectsDeleteCall) UserProject(userProject string) *ObjectsDeleteCall { @@ -9274,7 +9134,7 @@ func (c *ObjectsDeleteCall) Header() http.Header { func (c *ObjectsDeleteCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -9305,7 +9165,7 @@ func (c *ObjectsDeleteCall) Do(opts ...googleapi.CallOption) error { } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return err + return gensupport.WrapError(err) } return nil // { @@ -9359,11 +9219,6 @@ func (c *ObjectsDeleteCall) Do(opts ...googleapi.CallOption) error { // "required": true, // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request. Required for Requester Pays buckets.", // "location": "query", @@ -9393,6 +9248,10 @@ type ObjectsGetCall struct { } // Get: Retrieves an object or its metadata. +// +// - bucket: Name of the bucket in which the object resides. +// - object: Name of the object. For information about how to URL encode +// object names to be path safe, see Encoding URI Path Parts. func (r *ObjectsService) Get(bucket string, object string) *ObjectsGetCall { c := &ObjectsGetCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket @@ -9448,21 +9307,14 @@ func (c *ObjectsGetCall) IfMetagenerationNotMatch(ifMetagenerationNotMatch int64 // properties to return. Defaults to noAcl. // // Possible values: -// "full" - Include all properties. -// "noAcl" - Omit the owner, acl property. +// +// "full" - Include all properties. +// "noAcl" - Omit the owner, acl property. func (c *ObjectsGetCall) Projection(projection string) *ObjectsGetCall { c.urlParams_.Set("projection", projection) return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *ObjectsGetCall) ProvisionalUserProject(provisionalUserProject string) *ObjectsGetCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. Required for Requester Pays buckets. func (c *ObjectsGetCall) UserProject(userProject string) *ObjectsGetCall { @@ -9507,7 +9359,7 @@ func (c *ObjectsGetCall) Header() http.Header { func (c *ObjectsGetCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -9543,7 +9395,7 @@ func (c *ObjectsGetCall) Download(opts ...googleapi.CallOption) (*http.Response, } if err := googleapi.CheckMediaResponse(res); err != nil { res.Body.Close() - return nil, err + return nil, gensupport.WrapError(err) } return res, nil } @@ -9562,17 +9414,17 @@ func (c *ObjectsGetCall) Do(opts ...googleapi.CallOption) (*Object, error) { if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &Object{ ServerResponse: googleapi.ServerResponse{ @@ -9649,11 +9501,6 @@ func (c *ObjectsGetCall) Do(opts ...googleapi.CallOption) (*Object, error) { // "location": "query", // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request. Required for Requester Pays buckets.", // "location": "query", @@ -9690,6 +9537,10 @@ type ObjectsGetIamPolicyCall struct { } // GetIamPolicy: Returns an IAM policy for the specified object. +// +// - bucket: Name of the bucket in which the object resides. +// - object: Name of the object. For information about how to URL encode +// object names to be path safe, see Encoding URI Path Parts. func (r *ObjectsService) GetIamPolicy(bucket string, object string) *ObjectsGetIamPolicyCall { c := &ObjectsGetIamPolicyCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket @@ -9705,14 +9556,6 @@ func (c *ObjectsGetIamPolicyCall) Generation(generation int64) *ObjectsGetIamPol return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *ObjectsGetIamPolicyCall) ProvisionalUserProject(provisionalUserProject string) *ObjectsGetIamPolicyCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. Required for Requester Pays buckets. func (c *ObjectsGetIamPolicyCall) UserProject(userProject string) *ObjectsGetIamPolicyCall { @@ -9757,7 +9600,7 @@ func (c *ObjectsGetIamPolicyCall) Header() http.Header { func (c *ObjectsGetIamPolicyCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -9796,17 +9639,17 @@ func (c *ObjectsGetIamPolicyCall) Do(opts ...googleapi.CallOption) (*Policy, err if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &Policy{ ServerResponse: googleapi.ServerResponse{ @@ -9846,11 +9689,6 @@ func (c *ObjectsGetIamPolicyCall) Do(opts ...googleapi.CallOption) (*Policy, err // "required": true, // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request. Required for Requester Pays buckets.", // "location": "query", @@ -9880,11 +9718,15 @@ type ObjectsInsertCall struct { object *Object urlParams_ gensupport.URLParams mediaInfo_ *gensupport.MediaInfo + retry *gensupport.RetryConfig ctx_ context.Context header_ http.Header } // Insert: Stores a new object and metadata. +// +// - bucket: Name of the bucket in which to store the new object. +// Overrides the provided object metadata's bucket value, if any. func (r *ObjectsService) Insert(bucket string, object *Object) *ObjectsInsertCall { c := &ObjectsInsertCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket @@ -9942,7 +9784,9 @@ func (c *ObjectsInsertCall) IfMetagenerationNotMatch(ifMetagenerationNotMatch in // KmsKeyName sets the optional parameter "kmsKeyName": Resource name of // the Cloud KMS key, of the form // projects/my-project/locations/global/keyRings/my-kr/cryptoKeys/my-key, -// that will be used to encrypt the object. Overrides the object +// +// that will be used to encrypt the object. Overrides the object +// // metadata's kms_key_name value, if any. func (c *ObjectsInsertCall) KmsKeyName(kmsKeyName string) *ObjectsInsertCall { c.urlParams_.Set("kmsKeyName", kmsKeyName) @@ -9962,16 +9806,26 @@ func (c *ObjectsInsertCall) Name(name string) *ObjectsInsertCall { // predefined set of access controls to this object. // // Possible values: -// "authenticatedRead" - Object owner gets OWNER access, and +// +// "authenticatedRead" - Object owner gets OWNER access, and +// // allAuthenticatedUsers get READER access. -// "bucketOwnerFullControl" - Object owner gets OWNER access, and +// +// "bucketOwnerFullControl" - Object owner gets OWNER access, and +// // project team owners get OWNER access. -// "bucketOwnerRead" - Object owner gets OWNER access, and project +// +// "bucketOwnerRead" - Object owner gets OWNER access, and project +// // team owners get READER access. -// "private" - Object owner gets OWNER access. -// "projectPrivate" - Object owner gets OWNER access, and project team +// +// "private" - Object owner gets OWNER access. +// "projectPrivate" - Object owner gets OWNER access, and project team +// // members get access according to their roles. -// "publicRead" - Object owner gets OWNER access, and allUsers get +// +// "publicRead" - Object owner gets OWNER access, and allUsers get +// // READER access. func (c *ObjectsInsertCall) PredefinedAcl(predefinedAcl string) *ObjectsInsertCall { c.urlParams_.Set("predefinedAcl", predefinedAcl) @@ -9983,21 +9837,14 @@ func (c *ObjectsInsertCall) PredefinedAcl(predefinedAcl string) *ObjectsInsertCa // specifies the acl property, when it defaults to full. // // Possible values: -// "full" - Include all properties. -// "noAcl" - Omit the owner, acl property. +// +// "full" - Include all properties. +// "noAcl" - Omit the owner, acl property. func (c *ObjectsInsertCall) Projection(projection string) *ObjectsInsertCall { c.urlParams_.Set("projection", projection) return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *ObjectsInsertCall) ProvisionalUserProject(provisionalUserProject string) *ObjectsInsertCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. Required for Requester Pays buckets. func (c *ObjectsInsertCall) UserProject(userProject string) *ObjectsInsertCall { @@ -10045,6 +9892,32 @@ func (c *ObjectsInsertCall) ProgressUpdater(pu googleapi.ProgressUpdater) *Objec return c } +// WithRetry causes the library to retry the initial request of the +// upload(for resumable uploads) or the entire upload (for multipart +// uploads) ifa transient error occurs. This is contingent on ChunkSize +// being > 0 (sothat the input data may be buffered). The backoff +// argument will be used todetermine exponential backoff timing, and the +// errorFunc is used to determinewhich errors are considered retryable. +// By default, exponetial backoff will beapplied using gax defaults, and +// the following errors are retried: +// +// - HTTP responses with codes 408, 429, 502, 503, and 504. +// +// - Transient network errors such as connection reset and +// io.ErrUnexpectedEOF. +// +// - Errors which are considered transient using the Temporary() +// interface. +// +// - Wrapped versions of these errors. +func (c *ObjectsInsertCall) WithRetry(bo *gax.Backoff, errorFunc func(err error) bool) *ObjectsInsertCall { + c.retry = &gensupport.RetryConfig{ + Backoff: bo, + ShouldRetry: errorFunc, + } + return c +} + // Fields allows partial responses to be retrieved. See // https://developers.google.com/gdata/docs/2.0/basics#PartialResponse // for more information. @@ -10074,7 +9947,7 @@ func (c *ObjectsInsertCall) Header() http.Header { func (c *ObjectsInsertCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -10108,7 +9981,10 @@ func (c *ObjectsInsertCall) doRequest(alt string) (*http.Response, error) { googleapi.Expand(req.URL, map[string]string{ "bucket": c.bucket, }) - return gensupport.SendRequestWithRetry(c.ctx_, c.s.client, req) + if c.retry != nil { + return gensupport.SendRequestWithRetry(c.ctx_, c.s.client, req, c.retry) + } + return gensupport.SendRequest(c.ctx_, c.s.client, req) } // Do executes the "storage.objects.insert" call. @@ -10125,22 +10001,23 @@ func (c *ObjectsInsertCall) Do(opts ...googleapi.CallOption) (*Object, error) { if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } rx := c.mediaInfo_.ResumableUpload(res.Header.Get("Location")) if rx != nil { rx.Client = c.s.client rx.UserAgent = c.s.userAgent() + rx.Retry = c.retry ctx := c.ctx_ if ctx == nil { ctx = context.TODO() @@ -10151,7 +10028,7 @@ func (c *ObjectsInsertCall) Do(opts ...googleapi.CallOption) (*Object, error) { } defer res.Body.Close() if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } } ret := &Object{ @@ -10267,11 +10144,6 @@ func (c *ObjectsInsertCall) Do(opts ...googleapi.CallOption) (*Object, error) { // "location": "query", // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request. Required for Requester Pays buckets.", // "location": "query", @@ -10307,6 +10179,8 @@ type ObjectsListCall struct { } // List: Retrieves a list of objects matching the criteria. +// +// - bucket: Name of the bucket in which to look for objects. func (r *ObjectsService) List(bucket string) *ObjectsListCall { c := &ObjectsListCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket @@ -10342,6 +10216,13 @@ func (c *ObjectsListCall) IncludeTrailingDelimiter(includeTrailingDelimiter bool return c } +// MatchGlob sets the optional parameter "matchGlob": Filter results to +// objects and prefixes that match this glob pattern. +func (c *ObjectsListCall) MatchGlob(matchGlob string) *ObjectsListCall { + c.urlParams_.Set("matchGlob", matchGlob) + return c +} + // MaxResults sets the optional parameter "maxResults": Maximum number // of items plus prefixes to return in a single page of responses. As // duplicate prefixes are omitted, fewer total results may be returned @@ -10371,21 +10252,14 @@ func (c *ObjectsListCall) Prefix(prefix string) *ObjectsListCall { // properties to return. Defaults to noAcl. // // Possible values: -// "full" - Include all properties. -// "noAcl" - Omit the owner, acl property. +// +// "full" - Include all properties. +// "noAcl" - Omit the owner, acl property. func (c *ObjectsListCall) Projection(projection string) *ObjectsListCall { c.urlParams_.Set("projection", projection) return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *ObjectsListCall) ProvisionalUserProject(provisionalUserProject string) *ObjectsListCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // StartOffset sets the optional parameter "startOffset": Filter results // to objects whose names are lexicographically equal to or after // startOffset. If endOffset is also set, the objects listed will have @@ -10447,7 +10321,7 @@ func (c *ObjectsListCall) Header() http.Header { func (c *ObjectsListCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -10485,17 +10359,17 @@ func (c *ObjectsListCall) Do(opts ...googleapi.CallOption) (*Objects, error) { if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &Objects{ ServerResponse: googleapi.ServerResponse{ @@ -10537,6 +10411,11 @@ func (c *ObjectsListCall) Do(opts ...googleapi.CallOption) (*Objects, error) { // "location": "query", // "type": "boolean" // }, + // "matchGlob": { + // "description": "Filter results to objects and prefixes that match this glob pattern.", + // "location": "query", + // "type": "string" + // }, // "maxResults": { // "default": "1000", // "description": "Maximum number of items plus prefixes to return in a single page of responses. As duplicate prefixes are omitted, fewer total results may be returned than requested. The service will use this parameter or 1,000 items, whichever is smaller.", @@ -10568,11 +10447,6 @@ func (c *ObjectsListCall) Do(opts ...googleapi.CallOption) (*Objects, error) { // "location": "query", // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "startOffset": { // "description": "Filter results to objects whose names are lexicographically equal to or after startOffset. If endOffset is also set, the objects listed will have names between startOffset (inclusive) and endOffset (exclusive).", // "location": "query", @@ -10639,6 +10513,10 @@ type ObjectsPatchCall struct { } // Patch: Patches an object's metadata. +// +// - bucket: Name of the bucket in which the object resides. +// - object: Name of the object. For information about how to URL encode +// object names to be path safe, see Encoding URI Path Parts. func (r *ObjectsService) Patch(bucket string, object string, object2 *Object) *ObjectsPatchCall { c := &ObjectsPatchCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket @@ -10695,16 +10573,26 @@ func (c *ObjectsPatchCall) IfMetagenerationNotMatch(ifMetagenerationNotMatch int // predefined set of access controls to this object. // // Possible values: -// "authenticatedRead" - Object owner gets OWNER access, and +// +// "authenticatedRead" - Object owner gets OWNER access, and +// // allAuthenticatedUsers get READER access. -// "bucketOwnerFullControl" - Object owner gets OWNER access, and +// +// "bucketOwnerFullControl" - Object owner gets OWNER access, and +// // project team owners get OWNER access. -// "bucketOwnerRead" - Object owner gets OWNER access, and project +// +// "bucketOwnerRead" - Object owner gets OWNER access, and project +// // team owners get READER access. -// "private" - Object owner gets OWNER access. -// "projectPrivate" - Object owner gets OWNER access, and project team +// +// "private" - Object owner gets OWNER access. +// "projectPrivate" - Object owner gets OWNER access, and project team +// // members get access according to their roles. -// "publicRead" - Object owner gets OWNER access, and allUsers get +// +// "publicRead" - Object owner gets OWNER access, and allUsers get +// // READER access. func (c *ObjectsPatchCall) PredefinedAcl(predefinedAcl string) *ObjectsPatchCall { c.urlParams_.Set("predefinedAcl", predefinedAcl) @@ -10715,21 +10603,14 @@ func (c *ObjectsPatchCall) PredefinedAcl(predefinedAcl string) *ObjectsPatchCall // properties to return. Defaults to full. // // Possible values: -// "full" - Include all properties. -// "noAcl" - Omit the owner, acl property. +// +// "full" - Include all properties. +// "noAcl" - Omit the owner, acl property. func (c *ObjectsPatchCall) Projection(projection string) *ObjectsPatchCall { c.urlParams_.Set("projection", projection) return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *ObjectsPatchCall) ProvisionalUserProject(provisionalUserProject string) *ObjectsPatchCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request, for Requester Pays buckets. func (c *ObjectsPatchCall) UserProject(userProject string) *ObjectsPatchCall { @@ -10764,7 +10645,7 @@ func (c *ObjectsPatchCall) Header() http.Header { func (c *ObjectsPatchCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -10805,17 +10686,17 @@ func (c *ObjectsPatchCall) Do(opts ...googleapi.CallOption) (*Object, error) { if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &Object{ ServerResponse: googleapi.ServerResponse{ @@ -10913,11 +10794,6 @@ func (c *ObjectsPatchCall) Do(opts ...googleapi.CallOption) (*Object, error) { // "location": "query", // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request, for Requester Pays buckets.", // "location": "query", @@ -10955,6 +10831,19 @@ type ObjectsRewriteCall struct { // Rewrite: Rewrites a source object to a destination object. Optionally // overrides metadata. +// +// - destinationBucket: Name of the bucket in which to store the new +// object. Overrides the provided object metadata's bucket value, if +// any. +// - destinationObject: Name of the new object. Required when the object +// metadata is not otherwise provided. Overrides the object metadata's +// name value, if any. For information about how to URL encode object +// names to be path safe, see Encoding URI Path Parts. +// - sourceBucket: Name of the bucket in which to find the source +// object. +// - sourceObject: Name of the source object. For information about how +// to URL encode object names to be path safe, see Encoding URI Path +// Parts. func (r *ObjectsService) Rewrite(sourceBucket string, sourceObject string, destinationBucket string, destinationObject string, object *Object) *ObjectsRewriteCall { c := &ObjectsRewriteCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.sourceBucket = sourceBucket @@ -10969,7 +10858,9 @@ func (r *ObjectsService) Rewrite(sourceBucket string, sourceObject string, desti // "destinationKmsKeyName": Resource name of the Cloud KMS key, of the // form // projects/my-project/locations/global/keyRings/my-kr/cryptoKeys/my-key, -// that will be used to encrypt the object. Overrides the object +// +// that will be used to encrypt the object. Overrides the object +// // metadata's kms_key_name value, if any. func (c *ObjectsRewriteCall) DestinationKmsKeyName(destinationKmsKeyName string) *ObjectsRewriteCall { c.urlParams_.Set("destinationKmsKeyName", destinationKmsKeyName) @@ -10981,16 +10872,26 @@ func (c *ObjectsRewriteCall) DestinationKmsKeyName(destinationKmsKeyName string) // to the destination object. // // Possible values: -// "authenticatedRead" - Object owner gets OWNER access, and +// +// "authenticatedRead" - Object owner gets OWNER access, and +// // allAuthenticatedUsers get READER access. -// "bucketOwnerFullControl" - Object owner gets OWNER access, and +// +// "bucketOwnerFullControl" - Object owner gets OWNER access, and +// // project team owners get OWNER access. -// "bucketOwnerRead" - Object owner gets OWNER access, and project +// +// "bucketOwnerRead" - Object owner gets OWNER access, and project +// // team owners get READER access. -// "private" - Object owner gets OWNER access. -// "projectPrivate" - Object owner gets OWNER access, and project team +// +// "private" - Object owner gets OWNER access. +// "projectPrivate" - Object owner gets OWNER access, and project team +// // members get access according to their roles. -// "publicRead" - Object owner gets OWNER access, and allUsers get +// +// "publicRead" - Object owner gets OWNER access, and allUsers get +// // READER access. func (c *ObjectsRewriteCall) DestinationPredefinedAcl(destinationPredefinedAcl string) *ObjectsRewriteCall { c.urlParams_.Set("destinationPredefinedAcl", destinationPredefinedAcl) @@ -11088,21 +10989,14 @@ func (c *ObjectsRewriteCall) MaxBytesRewrittenPerCall(maxBytesRewrittenPerCall i // specifies the acl property, when it defaults to full. // // Possible values: -// "full" - Include all properties. -// "noAcl" - Omit the owner, acl property. +// +// "full" - Include all properties. +// "noAcl" - Omit the owner, acl property. func (c *ObjectsRewriteCall) Projection(projection string) *ObjectsRewriteCall { c.urlParams_.Set("projection", projection) return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *ObjectsRewriteCall) ProvisionalUserProject(provisionalUserProject string) *ObjectsRewriteCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // RewriteToken sets the optional parameter "rewriteToken": Include this // field (from the previous rewrite response) on each rewrite request // after the first one, until the rewrite response 'done' flag is true. @@ -11156,7 +11050,7 @@ func (c *ObjectsRewriteCall) Header() http.Header { func (c *ObjectsRewriteCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -11199,17 +11093,17 @@ func (c *ObjectsRewriteCall) Do(opts ...googleapi.CallOption) (*RewriteResponse, if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &RewriteResponse{ ServerResponse: googleapi.ServerResponse{ @@ -11338,11 +11232,6 @@ func (c *ObjectsRewriteCall) Do(opts ...googleapi.CallOption) (*RewriteResponse, // "location": "query", // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "rewriteToken": { // "description": "Include this field (from the previous rewrite response) on each rewrite request after the first one, until the rewrite response 'done' flag is true. Calls that provide a rewriteToken can omit all other request fields, but if included those fields must match the values provided in the first rewrite request.", // "location": "query", @@ -11401,6 +11290,10 @@ type ObjectsSetIamPolicyCall struct { } // SetIamPolicy: Updates an IAM policy for the specified object. +// +// - bucket: Name of the bucket in which the object resides. +// - object: Name of the object. For information about how to URL encode +// object names to be path safe, see Encoding URI Path Parts. func (r *ObjectsService) SetIamPolicy(bucket string, object string, policy *Policy) *ObjectsSetIamPolicyCall { c := &ObjectsSetIamPolicyCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket @@ -11417,14 +11310,6 @@ func (c *ObjectsSetIamPolicyCall) Generation(generation int64) *ObjectsSetIamPol return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *ObjectsSetIamPolicyCall) ProvisionalUserProject(provisionalUserProject string) *ObjectsSetIamPolicyCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. Required for Requester Pays buckets. func (c *ObjectsSetIamPolicyCall) UserProject(userProject string) *ObjectsSetIamPolicyCall { @@ -11459,7 +11344,7 @@ func (c *ObjectsSetIamPolicyCall) Header() http.Header { func (c *ObjectsSetIamPolicyCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -11500,17 +11385,17 @@ func (c *ObjectsSetIamPolicyCall) Do(opts ...googleapi.CallOption) (*Policy, err if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &Policy{ ServerResponse: googleapi.ServerResponse{ @@ -11550,11 +11435,6 @@ func (c *ObjectsSetIamPolicyCall) Do(opts ...googleapi.CallOption) (*Policy, err // "required": true, // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request. Required for Requester Pays buckets.", // "location": "query", @@ -11591,6 +11471,11 @@ type ObjectsTestIamPermissionsCall struct { // TestIamPermissions: Tests a set of permissions on the given object to // see which, if any, are held by the caller. +// +// - bucket: Name of the bucket in which the object resides. +// - object: Name of the object. For information about how to URL encode +// object names to be path safe, see Encoding URI Path Parts. +// - permissions: Permissions to test. func (r *ObjectsService) TestIamPermissions(bucket string, object string, permissions []string) *ObjectsTestIamPermissionsCall { c := &ObjectsTestIamPermissionsCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket @@ -11607,14 +11492,6 @@ func (c *ObjectsTestIamPermissionsCall) Generation(generation int64) *ObjectsTes return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *ObjectsTestIamPermissionsCall) ProvisionalUserProject(provisionalUserProject string) *ObjectsTestIamPermissionsCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. Required for Requester Pays buckets. func (c *ObjectsTestIamPermissionsCall) UserProject(userProject string) *ObjectsTestIamPermissionsCall { @@ -11659,7 +11536,7 @@ func (c *ObjectsTestIamPermissionsCall) Header() http.Header { func (c *ObjectsTestIamPermissionsCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -11698,17 +11575,17 @@ func (c *ObjectsTestIamPermissionsCall) Do(opts ...googleapi.CallOption) (*TestI if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &TestIamPermissionsResponse{ ServerResponse: googleapi.ServerResponse{ @@ -11756,11 +11633,6 @@ func (c *ObjectsTestIamPermissionsCall) Do(opts ...googleapi.CallOption) (*TestI // "required": true, // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request. Required for Requester Pays buckets.", // "location": "query", @@ -11795,6 +11667,10 @@ type ObjectsUpdateCall struct { } // Update: Updates an object's metadata. +// +// - bucket: Name of the bucket in which the object resides. +// - object: Name of the object. For information about how to URL encode +// object names to be path safe, see Encoding URI Path Parts. func (r *ObjectsService) Update(bucket string, object string, object2 *Object) *ObjectsUpdateCall { c := &ObjectsUpdateCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket @@ -11851,16 +11727,26 @@ func (c *ObjectsUpdateCall) IfMetagenerationNotMatch(ifMetagenerationNotMatch in // predefined set of access controls to this object. // // Possible values: -// "authenticatedRead" - Object owner gets OWNER access, and +// +// "authenticatedRead" - Object owner gets OWNER access, and +// // allAuthenticatedUsers get READER access. -// "bucketOwnerFullControl" - Object owner gets OWNER access, and +// +// "bucketOwnerFullControl" - Object owner gets OWNER access, and +// // project team owners get OWNER access. -// "bucketOwnerRead" - Object owner gets OWNER access, and project +// +// "bucketOwnerRead" - Object owner gets OWNER access, and project +// // team owners get READER access. -// "private" - Object owner gets OWNER access. -// "projectPrivate" - Object owner gets OWNER access, and project team +// +// "private" - Object owner gets OWNER access. +// "projectPrivate" - Object owner gets OWNER access, and project team +// // members get access according to their roles. -// "publicRead" - Object owner gets OWNER access, and allUsers get +// +// "publicRead" - Object owner gets OWNER access, and allUsers get +// // READER access. func (c *ObjectsUpdateCall) PredefinedAcl(predefinedAcl string) *ObjectsUpdateCall { c.urlParams_.Set("predefinedAcl", predefinedAcl) @@ -11871,21 +11757,14 @@ func (c *ObjectsUpdateCall) PredefinedAcl(predefinedAcl string) *ObjectsUpdateCa // properties to return. Defaults to full. // // Possible values: -// "full" - Include all properties. -// "noAcl" - Omit the owner, acl property. +// +// "full" - Include all properties. +// "noAcl" - Omit the owner, acl property. func (c *ObjectsUpdateCall) Projection(projection string) *ObjectsUpdateCall { c.urlParams_.Set("projection", projection) return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *ObjectsUpdateCall) ProvisionalUserProject(provisionalUserProject string) *ObjectsUpdateCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. Required for Requester Pays buckets. func (c *ObjectsUpdateCall) UserProject(userProject string) *ObjectsUpdateCall { @@ -11920,7 +11799,7 @@ func (c *ObjectsUpdateCall) Header() http.Header { func (c *ObjectsUpdateCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -11961,17 +11840,17 @@ func (c *ObjectsUpdateCall) Do(opts ...googleapi.CallOption) (*Object, error) { if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &Object{ ServerResponse: googleapi.ServerResponse{ @@ -12069,11 +11948,6 @@ func (c *ObjectsUpdateCall) Do(opts ...googleapi.CallOption) (*Object, error) { // "location": "query", // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request. Required for Requester Pays buckets.", // "location": "query", @@ -12107,6 +11981,8 @@ type ObjectsWatchAllCall struct { } // WatchAll: Watch for changes on all objects in a bucket. +// +// - bucket: Name of the bucket in which to look for objects. func (r *ObjectsService) WatchAll(bucket string, channel *Channel) *ObjectsWatchAllCall { c := &ObjectsWatchAllCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.bucket = bucket @@ -12172,21 +12048,14 @@ func (c *ObjectsWatchAllCall) Prefix(prefix string) *ObjectsWatchAllCall { // properties to return. Defaults to noAcl. // // Possible values: -// "full" - Include all properties. -// "noAcl" - Omit the owner, acl property. +// +// "full" - Include all properties. +// "noAcl" - Omit the owner, acl property. func (c *ObjectsWatchAllCall) Projection(projection string) *ObjectsWatchAllCall { c.urlParams_.Set("projection", projection) return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *ObjectsWatchAllCall) ProvisionalUserProject(provisionalUserProject string) *ObjectsWatchAllCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // StartOffset sets the optional parameter "startOffset": Filter results // to objects whose names are lexicographically equal to or after // startOffset. If endOffset is also set, the objects listed will have @@ -12238,7 +12107,7 @@ func (c *ObjectsWatchAllCall) Header() http.Header { func (c *ObjectsWatchAllCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -12278,17 +12147,17 @@ func (c *ObjectsWatchAllCall) Do(opts ...googleapi.CallOption) (*Channel, error) if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &Channel{ ServerResponse: googleapi.ServerResponse{ @@ -12361,11 +12230,6 @@ func (c *ObjectsWatchAllCall) Do(opts ...googleapi.CallOption) (*Channel, error) // "location": "query", // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "startOffset": { // "description": "Filter results to objects whose names are lexicographically equal to or after startOffset. If endOffset is also set, the objects listed will have names between startOffset (inclusive) and endOffset (exclusive).", // "location": "query", @@ -12413,6 +12277,9 @@ type ProjectsHmacKeysCreateCall struct { } // Create: Creates a new HMAC key for the specified service account. +// +// - projectId: Project ID owning the service account. +// - serviceAccountEmail: Email address of the service account. func (r *ProjectsHmacKeysService) Create(projectId string, serviceAccountEmail string) *ProjectsHmacKeysCreateCall { c := &ProjectsHmacKeysCreateCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.projectId = projectId @@ -12454,7 +12321,7 @@ func (c *ProjectsHmacKeysCreateCall) Header() http.Header { func (c *ProjectsHmacKeysCreateCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -12489,17 +12356,17 @@ func (c *ProjectsHmacKeysCreateCall) Do(opts ...googleapi.CallOption) (*HmacKey, if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &HmacKey{ ServerResponse: googleapi.ServerResponse{ @@ -12563,6 +12430,9 @@ type ProjectsHmacKeysDeleteCall struct { } // Delete: Deletes an HMAC key. +// +// - accessId: Name of the HMAC key to be deleted. +// - projectId: Project ID owning the requested key. func (r *ProjectsHmacKeysService) Delete(projectId string, accessId string) *ProjectsHmacKeysDeleteCall { c := &ProjectsHmacKeysDeleteCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.projectId = projectId @@ -12604,7 +12474,7 @@ func (c *ProjectsHmacKeysDeleteCall) Header() http.Header { func (c *ProjectsHmacKeysDeleteCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -12635,7 +12505,7 @@ func (c *ProjectsHmacKeysDeleteCall) Do(opts ...googleapi.CallOption) error { } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return err + return gensupport.WrapError(err) } return nil // { @@ -12688,6 +12558,10 @@ type ProjectsHmacKeysGetCall struct { } // Get: Retrieves an HMAC key's metadata +// +// - accessId: Name of the HMAC key. +// - projectId: Project ID owning the service account of the requested +// key. func (r *ProjectsHmacKeysService) Get(projectId string, accessId string) *ProjectsHmacKeysGetCall { c := &ProjectsHmacKeysGetCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.projectId = projectId @@ -12739,7 +12613,7 @@ func (c *ProjectsHmacKeysGetCall) Header() http.Header { func (c *ProjectsHmacKeysGetCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -12778,17 +12652,17 @@ func (c *ProjectsHmacKeysGetCall) Do(opts ...googleapi.CallOption) (*HmacKeyMeta if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &HmacKeyMetadata{ ServerResponse: googleapi.ServerResponse{ @@ -12854,6 +12728,8 @@ type ProjectsHmacKeysListCall struct { } // List: Retrieves a list of HMAC keys matching the criteria. +// +// - projectId: Name of the project in which to look for HMAC keys. func (r *ProjectsHmacKeysService) List(projectId string) *ProjectsHmacKeysListCall { c := &ProjectsHmacKeysListCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.projectId = projectId @@ -12939,7 +12815,7 @@ func (c *ProjectsHmacKeysListCall) Header() http.Header { func (c *ProjectsHmacKeysListCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -12977,17 +12853,17 @@ func (c *ProjectsHmacKeysListCall) Do(opts ...googleapi.CallOption) (*HmacKeysMe if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &HmacKeysMetadata{ ServerResponse: googleapi.ServerResponse{ @@ -13092,6 +12968,10 @@ type ProjectsHmacKeysUpdateCall struct { // Update: Updates the state of an HMAC key. See the HMAC Key resource // descriptor for valid states. +// +// - accessId: Name of the HMAC key being updated. +// - projectId: Project ID owning the service account of the updated +// key. func (r *ProjectsHmacKeysService) Update(projectId string, accessId string, hmackeymetadata *HmacKeyMetadata) *ProjectsHmacKeysUpdateCall { c := &ProjectsHmacKeysUpdateCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.projectId = projectId @@ -13134,7 +13014,7 @@ func (c *ProjectsHmacKeysUpdateCall) Header() http.Header { func (c *ProjectsHmacKeysUpdateCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -13175,17 +13055,17 @@ func (c *ProjectsHmacKeysUpdateCall) Do(opts ...googleapi.CallOption) (*HmacKeyM if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &HmacKeyMetadata{ ServerResponse: googleapi.ServerResponse{ @@ -13253,20 +13133,14 @@ type ProjectsServiceAccountGetCall struct { // Get: Get the email address of this project's Google Cloud Storage // service account. +// +// - projectId: Project ID. func (r *ProjectsServiceAccountService) Get(projectId string) *ProjectsServiceAccountGetCall { c := &ProjectsServiceAccountGetCall{s: r.s, urlParams_: make(gensupport.URLParams)} c.projectId = projectId return c } -// ProvisionalUserProject sets the optional parameter -// "provisionalUserProject": The project to be billed for this request -// if the target bucket is requester-pays bucket. -func (c *ProjectsServiceAccountGetCall) ProvisionalUserProject(provisionalUserProject string) *ProjectsServiceAccountGetCall { - c.urlParams_.Set("provisionalUserProject", provisionalUserProject) - return c -} - // UserProject sets the optional parameter "userProject": The project to // be billed for this request. func (c *ProjectsServiceAccountGetCall) UserProject(userProject string) *ProjectsServiceAccountGetCall { @@ -13311,7 +13185,7 @@ func (c *ProjectsServiceAccountGetCall) Header() http.Header { func (c *ProjectsServiceAccountGetCall) doRequest(alt string) (*http.Response, error) { reqHeaders := make(http.Header) - reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/20201124") + reqHeaders.Set("x-goog-api-client", "gl-go/"+gensupport.GoVersion()+" gdcl/"+internal.Version) for k, v := range c.header_ { reqHeaders[k] = v } @@ -13349,17 +13223,17 @@ func (c *ProjectsServiceAccountGetCall) Do(opts ...googleapi.CallOption) (*Servi if res.Body != nil { res.Body.Close() } - return nil, &googleapi.Error{ + return nil, gensupport.WrapError(&googleapi.Error{ Code: res.StatusCode, Header: res.Header, - } + }) } if err != nil { return nil, err } defer googleapi.CloseBody(res) if err := googleapi.CheckResponse(res); err != nil { - return nil, err + return nil, gensupport.WrapError(err) } ret := &ServiceAccount{ ServerResponse: googleapi.ServerResponse{ @@ -13386,11 +13260,6 @@ func (c *ProjectsServiceAccountGetCall) Do(opts ...googleapi.CallOption) (*Servi // "required": true, // "type": "string" // }, - // "provisionalUserProject": { - // "description": "The project to be billed for this request if the target bucket is requester-pays bucket.", - // "location": "query", - // "type": "string" - // }, // "userProject": { // "description": "The project to be billed for this request.", // "location": "query", diff --git a/vendor/google.golang.org/api/transport/dial.go b/vendor/google.golang.org/api/transport/dial.go new file mode 100644 index 00000000000..652b8eba51d --- /dev/null +++ b/vendor/google.golang.org/api/transport/dial.go @@ -0,0 +1,48 @@ +// Copyright 2015 Google LLC. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package transport + +import ( + "context" + "net/http" + + "golang.org/x/oauth2/google" + "google.golang.org/grpc" + + "google.golang.org/api/internal" + "google.golang.org/api/option" + gtransport "google.golang.org/api/transport/grpc" + htransport "google.golang.org/api/transport/http" +) + +// NewHTTPClient returns an HTTP client for use communicating with a Google cloud +// service, configured with the given ClientOptions. It also returns the endpoint +// for the service as specified in the options. +func NewHTTPClient(ctx context.Context, opts ...option.ClientOption) (*http.Client, string, error) { + return htransport.NewClient(ctx, opts...) +} + +// DialGRPC returns a GRPC connection for use communicating with a Google cloud +// service, configured with the given ClientOptions. +func DialGRPC(ctx context.Context, opts ...option.ClientOption) (*grpc.ClientConn, error) { + return gtransport.Dial(ctx, opts...) +} + +// DialGRPCInsecure returns an insecure GRPC connection for use communicating +// with fake or mock Google cloud service implementations, such as emulators. +// The connection is configured with the given ClientOptions. +func DialGRPCInsecure(ctx context.Context, opts ...option.ClientOption) (*grpc.ClientConn, error) { + return gtransport.DialInsecure(ctx, opts...) +} + +// Creds constructs a google.Credentials from the information in the options, +// or obtains the default credentials in the same way as google.FindDefaultCredentials. +func Creds(ctx context.Context, opts ...option.ClientOption) (*google.Credentials, error) { + var ds internal.DialSettings + for _, opt := range opts { + opt.Apply(&ds) + } + return internal.Creds(ctx, &ds) +} diff --git a/vendor/google.golang.org/api/transport/doc.go b/vendor/google.golang.org/api/transport/doc.go new file mode 100644 index 00000000000..7143abee458 --- /dev/null +++ b/vendor/google.golang.org/api/transport/doc.go @@ -0,0 +1,11 @@ +// Copyright 2019 Google LLC. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package transport provides utility methods for creating authenticated +// transports to Google's HTTP and gRPC APIs. It is intended to be used in +// conjunction with google.golang.org/api/option. +// +// This package is not intended for use by end developers. Use the +// google.golang.org/api/option package to configure API clients. +package transport diff --git a/vendor/google.golang.org/api/transport/grpc/dial.go b/vendor/google.golang.org/api/transport/grpc/dial.go new file mode 100644 index 00000000000..20c94fa640b --- /dev/null +++ b/vendor/google.golang.org/api/transport/grpc/dial.go @@ -0,0 +1,328 @@ +// Copyright 2015 Google LLC. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package grpc supports network connections to GRPC servers. +// This package is not intended for use by end developers. Use the +// google.golang.org/api/option package to configure API clients. +package grpc + +import ( + "context" + "crypto/tls" + "errors" + "log" + "net" + "os" + "strings" + + "cloud.google.com/go/compute/metadata" + "go.opencensus.io/plugin/ocgrpc" + "golang.org/x/oauth2" + "google.golang.org/api/internal" + "google.golang.org/api/option" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + grpcgoogle "google.golang.org/grpc/credentials/google" + grpcinsecure "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/credentials/oauth" + + // Install grpclb, which is required for direct path. + _ "google.golang.org/grpc/balancer/grpclb" +) + +// Check env to disable DirectPath traffic. +const disableDirectPath = "GOOGLE_CLOUD_DISABLE_DIRECT_PATH" + +// Check env to decide if using google-c2p resolver for DirectPath traffic. +const enableDirectPathXds = "GOOGLE_CLOUD_ENABLE_DIRECT_PATH_XDS" + +// Set at init time by dial_appengine.go. If nil, we're not on App Engine. +var appengineDialerHook func(context.Context) grpc.DialOption + +// Set at init time by dial_socketopt.go. If nil, socketopt is not supported. +var timeoutDialerOption grpc.DialOption + +// Dial returns a GRPC connection for use communicating with a Google cloud +// service, configured with the given ClientOptions. +func Dial(ctx context.Context, opts ...option.ClientOption) (*grpc.ClientConn, error) { + o, err := processAndValidateOpts(opts) + if err != nil { + return nil, err + } + if o.GRPCConnPool != nil { + return o.GRPCConnPool.Conn(), nil + } + // NOTE(cbro): We removed support for option.WithGRPCConnPool (GRPCConnPoolSize) + // on 2020-02-12 because RoundRobin and WithBalancer are deprecated and we need to remove usages of it. + // + // Connection pooling is only done via DialPool. + return dial(ctx, false, o) +} + +// DialInsecure returns an insecure GRPC connection for use communicating +// with fake or mock Google cloud service implementations, such as emulators. +// The connection is configured with the given ClientOptions. +func DialInsecure(ctx context.Context, opts ...option.ClientOption) (*grpc.ClientConn, error) { + o, err := processAndValidateOpts(opts) + if err != nil { + return nil, err + } + return dial(ctx, true, o) +} + +// DialPool returns a pool of GRPC connections for the given service. +// This differs from the connection pooling implementation used by Dial, which uses a custom GRPC load balancer. +// DialPool should be used instead of Dial when a pool is used by default or a different custom GRPC load balancer is needed. +// The context and options are shared between each Conn in the pool. +// The pool size is configured using the WithGRPCConnectionPool option. +// +// This API is subject to change as we further refine requirements. It will go away if gRPC stubs accept an interface instead of the concrete ClientConn type. See https://github.com/grpc/grpc-go/issues/1287. +func DialPool(ctx context.Context, opts ...option.ClientOption) (ConnPool, error) { + o, err := processAndValidateOpts(opts) + if err != nil { + return nil, err + } + if o.GRPCConnPool != nil { + return o.GRPCConnPool, nil + } + poolSize := o.GRPCConnPoolSize + if o.GRPCConn != nil { + // WithGRPCConn is technically incompatible with WithGRPCConnectionPool. + // Always assume pool size is 1 when a grpc.ClientConn is explicitly used. + poolSize = 1 + } + o.GRPCConnPoolSize = 0 // we don't *need* to set this to zero, but it's safe to. + + if poolSize == 0 || poolSize == 1 { + // Fast path for common case for a connection pool with a single connection. + conn, err := dial(ctx, false, o) + if err != nil { + return nil, err + } + return &singleConnPool{conn}, nil + } + + pool := &roundRobinConnPool{} + for i := 0; i < poolSize; i++ { + conn, err := dial(ctx, false, o) + if err != nil { + defer pool.Close() // NOTE: error from Close is ignored. + return nil, err + } + pool.conns = append(pool.conns, conn) + } + return pool, nil +} + +func dial(ctx context.Context, insecure bool, o *internal.DialSettings) (*grpc.ClientConn, error) { + if o.HTTPClient != nil { + return nil, errors.New("unsupported HTTP client specified") + } + if o.GRPCConn != nil { + return o.GRPCConn, nil + } + clientCertSource, endpoint, err := internal.GetClientCertificateSourceAndEndpoint(o) + if err != nil { + return nil, err + } + + var transportCreds credentials.TransportCredentials + if insecure { + transportCreds = grpcinsecure.NewCredentials() + } else { + transportCreds = credentials.NewTLS(&tls.Config{ + GetClientCertificate: clientCertSource, + }) + } + + // Initialize gRPC dial options with transport-level security options. + grpcOpts := []grpc.DialOption{ + grpc.WithTransportCredentials(transportCreds), + } + + // Authentication can only be sent when communicating over a secure connection. + // + // TODO: Should we be more lenient in the future and allow sending credentials + // when dialing an insecure connection? + if !o.NoAuth && !insecure { + if o.APIKey != "" { + log.Print("API keys are not supported for gRPC APIs. Remove the WithAPIKey option from your client-creating call.") + } + creds, err := internal.Creds(ctx, o) + if err != nil { + return nil, err + } + + grpcOpts = append(grpcOpts, + grpc.WithPerRPCCredentials(grpcTokenSource{ + TokenSource: oauth.TokenSource{creds.TokenSource}, + quotaProject: internal.GetQuotaProject(creds, o.QuotaProject), + requestReason: o.RequestReason, + }), + ) + + // Attempt Direct Path: + if isDirectPathEnabled(endpoint, o) && isTokenSourceDirectPathCompatible(creds.TokenSource, o) && metadata.OnGCE() { + // Overwrite all of the previously specific DialOptions, DirectPath uses its own set of credentials and certificates. + grpcOpts = []grpc.DialOption{ + grpc.WithCredentialsBundle(grpcgoogle.NewDefaultCredentialsWithOptions(grpcgoogle.DefaultCredentialsOptions{oauth.TokenSource{creds.TokenSource}}))} + if timeoutDialerOption != nil { + grpcOpts = append(grpcOpts, timeoutDialerOption) + } + // Check if google-c2p resolver is enabled for DirectPath + if strings.EqualFold(os.Getenv(enableDirectPathXds), "true") { + // google-c2p resolver target must not have a port number + if addr, _, err := net.SplitHostPort(endpoint); err == nil { + endpoint = "google-c2p:///" + addr + } else { + endpoint = "google-c2p:///" + endpoint + } + } else { + if !strings.HasPrefix(endpoint, "dns:///") { + endpoint = "dns:///" + endpoint + } + grpcOpts = append(grpcOpts, + // For now all DirectPath go clients will be using the following lb config, but in future + // when different services need different configs, then we should change this to a + // per-service config. + grpc.WithDisableServiceConfig(), + grpc.WithDefaultServiceConfig(`{"loadBalancingConfig":[{"grpclb":{"childPolicy":[{"pick_first":{}}]}}]}`)) + } + // TODO(cbro): add support for system parameters (quota project, request reason) via chained interceptor. + } + } + + if appengineDialerHook != nil { + // Use the Socket API on App Engine. + // appengine dialer will override socketopt dialer + grpcOpts = append(grpcOpts, appengineDialerHook(ctx)) + } + + // Add tracing, but before the other options, so that clients can override the + // gRPC stats handler. + // This assumes that gRPC options are processed in order, left to right. + grpcOpts = addOCStatsHandler(grpcOpts, o) + grpcOpts = append(grpcOpts, o.GRPCDialOpts...) + if o.UserAgent != "" { + grpcOpts = append(grpcOpts, grpc.WithUserAgent(o.UserAgent)) + } + + return grpc.DialContext(ctx, endpoint, grpcOpts...) +} + +func addOCStatsHandler(opts []grpc.DialOption, settings *internal.DialSettings) []grpc.DialOption { + if settings.TelemetryDisabled { + return opts + } + return append(opts, grpc.WithStatsHandler(&ocgrpc.ClientHandler{})) +} + +// grpcTokenSource supplies PerRPCCredentials from an oauth.TokenSource. +type grpcTokenSource struct { + oauth.TokenSource + + // Additional metadata attached as headers. + quotaProject string + requestReason string +} + +// GetRequestMetadata gets the request metadata as a map from a grpcTokenSource. +func (ts grpcTokenSource) GetRequestMetadata(ctx context.Context, uri ...string) ( + map[string]string, error) { + metadata, err := ts.TokenSource.GetRequestMetadata(ctx, uri...) + if err != nil { + return nil, err + } + + // Attach system parameter + if ts.quotaProject != "" { + metadata["X-goog-user-project"] = ts.quotaProject + } + if ts.requestReason != "" { + metadata["X-goog-request-reason"] = ts.requestReason + } + return metadata, nil +} + +func isDirectPathEnabled(endpoint string, o *internal.DialSettings) bool { + if !o.EnableDirectPath { + return false + } + if !checkDirectPathEndPoint(endpoint) { + return false + } + if strings.EqualFold(os.Getenv(disableDirectPath), "true") { + return false + } + return true +} + +func isTokenSourceDirectPathCompatible(ts oauth2.TokenSource, o *internal.DialSettings) bool { + if ts == nil { + return false + } + tok, err := ts.Token() + if err != nil { + return false + } + if tok == nil { + return false + } + if o.AllowNonDefaultServiceAccount { + return true + } + if source, _ := tok.Extra("oauth2.google.tokenSource").(string); source != "compute-metadata" { + return false + } + if acct, _ := tok.Extra("oauth2.google.serviceAccount").(string); acct != "default" { + return false + } + return true +} + +func checkDirectPathEndPoint(endpoint string) bool { + // Only [dns:///]host[:port] is supported, not other schemes (e.g., "tcp://" or "unix://"). + // Also don't try direct path if the user has chosen an alternate name resolver + // (i.e., via ":///" prefix). + // + // TODO(cbro): once gRPC has introspectible options, check the user hasn't + // provided a custom dialer in gRPC options. + if strings.Contains(endpoint, "://") && !strings.HasPrefix(endpoint, "dns:///") { + return false + } + + if endpoint == "" { + return false + } + + return true +} + +func processAndValidateOpts(opts []option.ClientOption) (*internal.DialSettings, error) { + var o internal.DialSettings + for _, opt := range opts { + opt.Apply(&o) + } + if err := o.Validate(); err != nil { + return nil, err + } + + return &o, nil +} + +type connPoolOption struct{ ConnPool } + +// WithConnPool returns a ClientOption that specifies the ConnPool +// connection to use as the basis of communications. +// +// This is only to be used by Google client libraries internally, for example +// when creating a longrunning API client that shares the same connection pool +// as a service client. +func WithConnPool(p ConnPool) option.ClientOption { + return connPoolOption{p} +} + +func (o connPoolOption) Apply(s *internal.DialSettings) { + s.GRPCConnPool = o.ConnPool +} diff --git a/vendor/google.golang.org/api/transport/grpc/dial_appengine.go b/vendor/google.golang.org/api/transport/grpc/dial_appengine.go new file mode 100644 index 00000000000..fd3dc0565d0 --- /dev/null +++ b/vendor/google.golang.org/api/transport/grpc/dial_appengine.go @@ -0,0 +1,32 @@ +// Copyright 2016 Google LLC. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build appengine +// +build appengine + +package grpc + +import ( + "context" + "net" + "time" + + "google.golang.org/appengine" + "google.golang.org/appengine/socket" + "google.golang.org/grpc" +) + +func init() { + // NOTE: dev_appserver doesn't currently support SSL. + // When it does, this code can be removed. + if appengine.IsDevAppServer() { + return + } + + appengineDialerHook = func(ctx context.Context) grpc.DialOption { + return grpc.WithDialer(func(addr string, timeout time.Duration) (net.Conn, error) { + return socket.DialTimeout(ctx, "tcp", addr, timeout) + }) + } +} diff --git a/vendor/google.golang.org/api/transport/grpc/dial_socketopt.go b/vendor/google.golang.org/api/transport/grpc/dial_socketopt.go new file mode 100644 index 00000000000..507cd3ec63a --- /dev/null +++ b/vendor/google.golang.org/api/transport/grpc/dial_socketopt.go @@ -0,0 +1,52 @@ +// Copyright 2019 Google LLC. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build go1.11 && linux +// +build go1.11,linux + +package grpc + +import ( + "context" + "net" + "syscall" + + "google.golang.org/grpc" +) + +const ( + // defaultTCPUserTimeout is the default TCP_USER_TIMEOUT socket option. By + // default is 20 seconds. + tcpUserTimeoutMilliseconds = 20000 + + // Copied from golang.org/x/sys/unix.TCP_USER_TIMEOUT. + tcpUserTimeoutOp = 0x12 +) + +func init() { + // timeoutDialerOption is a grpc.DialOption that contains dialer with + // socket option TCP_USER_TIMEOUT. This dialer requires go versions 1.11+. + timeoutDialerOption = grpc.WithContextDialer(dialTCPUserTimeout) +} + +func dialTCPUserTimeout(ctx context.Context, addr string) (net.Conn, error) { + control := func(network, address string, c syscall.RawConn) error { + var syscallErr error + controlErr := c.Control(func(fd uintptr) { + syscallErr = syscall.SetsockoptInt( + int(fd), syscall.IPPROTO_TCP, tcpUserTimeoutOp, tcpUserTimeoutMilliseconds) + }) + if syscallErr != nil { + return syscallErr + } + if controlErr != nil { + return controlErr + } + return nil + } + d := &net.Dialer{ + Control: control, + } + return d.DialContext(ctx, "tcp", addr) +} diff --git a/vendor/google.golang.org/api/transport/grpc/pool.go b/vendor/google.golang.org/api/transport/grpc/pool.go new file mode 100644 index 00000000000..4cf94a2771e --- /dev/null +++ b/vendor/google.golang.org/api/transport/grpc/pool.go @@ -0,0 +1,92 @@ +// Copyright 2020 Google LLC. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package grpc + +import ( + "context" + "fmt" + "sync/atomic" + + "google.golang.org/api/internal" + "google.golang.org/grpc" +) + +// ConnPool is a pool of grpc.ClientConns. +type ConnPool = internal.ConnPool // NOTE(cbro): type alias to export the type. It must live in internal to avoid a circular dependency. + +var _ ConnPool = &roundRobinConnPool{} +var _ ConnPool = &singleConnPool{} + +// singleConnPool is a special case for a single connection. +type singleConnPool struct { + *grpc.ClientConn +} + +func (p *singleConnPool) Conn() *grpc.ClientConn { return p.ClientConn } +func (p *singleConnPool) Num() int { return 1 } + +type roundRobinConnPool struct { + conns []*grpc.ClientConn + + idx uint32 // access via sync/atomic +} + +func (p *roundRobinConnPool) Num() int { + return len(p.conns) +} + +func (p *roundRobinConnPool) Conn() *grpc.ClientConn { + i := atomic.AddUint32(&p.idx, 1) + return p.conns[i%uint32(len(p.conns))] +} + +func (p *roundRobinConnPool) Close() error { + var errs multiError + for _, conn := range p.conns { + if err := conn.Close(); err != nil { + errs = append(errs, err) + } + } + if len(errs) == 0 { + return nil + } + return errs +} + +func (p *roundRobinConnPool) Invoke(ctx context.Context, method string, args interface{}, reply interface{}, opts ...grpc.CallOption) error { + return p.Conn().Invoke(ctx, method, args, reply, opts...) +} + +func (p *roundRobinConnPool) NewStream(ctx context.Context, desc *grpc.StreamDesc, method string, opts ...grpc.CallOption) (grpc.ClientStream, error) { + return p.Conn().NewStream(ctx, desc, method, opts...) +} + +// multiError represents errors from multiple conns in the group. +// +// TODO: figure out how and whether this is useful to export. End users should +// not be depending on the transport/grpc package directly, so there might need +// to be some service-specific multi-error type. +type multiError []error + +func (m multiError) Error() string { + s, n := "", 0 + for _, e := range m { + if e != nil { + if n == 0 { + s = e.Error() + } + n++ + } + } + switch n { + case 0: + return "(0 errors)" + case 1: + return s + case 2: + return s + " (and 1 other error)" + } + return fmt.Sprintf("%s (and %d other errors)", s, n-1) +} diff --git a/vendor/google.golang.org/api/transport/http/default_transport_go113.go b/vendor/google.golang.org/api/transport/http/default_transport_go113.go deleted file mode 100644 index 924f2704d1a..00000000000 --- a/vendor/google.golang.org/api/transport/http/default_transport_go113.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2020 Google LLC. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build go1.13 - -package http - -import "net/http" - -// clonedTransport returns the given RoundTripper as a cloned *http.Transport. -// It returns nil if the RoundTripper can't be cloned or coerced to -// *http.Transport. -func clonedTransport(rt http.RoundTripper) *http.Transport { - t, ok := rt.(*http.Transport) - if !ok { - return nil - } - return t.Clone() -} diff --git a/vendor/google.golang.org/api/transport/http/default_transport_not_go113.go b/vendor/google.golang.org/api/transport/http/default_transport_not_go113.go deleted file mode 100644 index 3cb16c6cb6c..00000000000 --- a/vendor/google.golang.org/api/transport/http/default_transport_not_go113.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2020 Google LLC. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !go1.13 - -package http - -import "net/http" - -// clonedTransport returns the given RoundTripper as a cloned *http.Transport. -// For versions of Go <1.13, this is not supported, so return nil. -func clonedTransport(rt http.RoundTripper) *http.Transport { - return nil -} diff --git a/vendor/google.golang.org/api/transport/http/dial.go b/vendor/google.golang.org/api/transport/http/dial.go index 8578cac9ef2..403509d08f6 100644 --- a/vendor/google.golang.org/api/transport/http/dial.go +++ b/vendor/google.golang.org/api/transport/http/dial.go @@ -16,13 +16,13 @@ import ( "time" "go.opencensus.io/plugin/ochttp" + "golang.org/x/net/http2" "golang.org/x/oauth2" "google.golang.org/api/googleapi/transport" "google.golang.org/api/internal" + "google.golang.org/api/internal/cert" "google.golang.org/api/option" - "google.golang.org/api/transport/cert" "google.golang.org/api/transport/http/internal/propagation" - "google.golang.org/api/transport/internal/dca" ) // NewClient returns an HTTP client for use communicating with a Google cloud @@ -33,7 +33,7 @@ func NewClient(ctx context.Context, opts ...option.ClientOption) (*http.Client, if err != nil { return nil, "", err } - clientCertSource, endpoint, err := dca.GetClientCertificateSourceAndEndpoint(settings) + clientCertSource, endpoint, err := internal.GetClientCertificateSourceAndEndpoint(settings) if err != nil { return nil, "", err } @@ -65,7 +65,6 @@ func newTransport(ctx context.Context, base http.RoundTripper, settings *interna paramTransport := ¶meterTransport{ base: base, userAgent: settings.UserAgent, - quotaProject: settings.QuotaProject, requestReason: settings.RequestReason, } var trans http.RoundTripper = paramTransport @@ -74,6 +73,7 @@ func newTransport(ctx context.Context, base http.RoundTripper, settings *interna case settings.NoAuth: // Do nothing. case settings.APIKey != "": + paramTransport.quotaProject = internal.GetQuotaProject(nil, settings.QuotaProject) trans = &transport.APIKey{ Transport: trans, Key: settings.APIKey, @@ -83,12 +83,9 @@ func newTransport(ctx context.Context, base http.RoundTripper, settings *interna if err != nil { return nil, err } - if paramTransport.quotaProject == "" { - paramTransport.quotaProject = internal.QuotaProjectFromCreds(creds) - } - + paramTransport.quotaProject = internal.GetQuotaProject(creds, settings.QuotaProject) ts := creds.TokenSource - if settings.TokenSource != nil { + if settings.ImpersonationConfig == nil && settings.TokenSource != nil { ts = settings.TokenSource } trans = &oauth2.Transport{ @@ -175,9 +172,22 @@ func defaultBaseTransport(ctx context.Context, clientCertSource cert.Source) htt } } + configureHTTP2(trans) + return trans } +// configureHTTP2 configures the ReadIdleTimeout HTTP/2 option for the +// transport. This allows broken idle connections to be pruned more quickly, +// preventing the client from attempting to re-use connections that will no +// longer work. +func configureHTTP2(trans *http.Transport) { + http2Trans, err := http2.ConfigureTransports(trans) + if err == nil { + http2Trans.ReadIdleTimeout = time.Second * 31 + } +} + // fallbackBaseTransport is used in 0 { + var cancel context.CancelFunc + dialCtx, cancel = context.WithTimeout(ctx, timeout) + defer cancel() + } + + host, portStr, err := net.SplitHostPort(addr) + if err != nil { + return nil, err + } + port, err := strconv.Atoi(portStr) + if err != nil { + return nil, fmt.Errorf("socket: bad port %q: %v", portStr, err) + } + + var prot pb.CreateSocketRequest_SocketProtocol + switch protocol { + case "tcp": + prot = pb.CreateSocketRequest_TCP + case "udp": + prot = pb.CreateSocketRequest_UDP + default: + return nil, fmt.Errorf("socket: unknown protocol %q", protocol) + } + + packedAddrs, resolved, err := resolve(dialCtx, ipFamilies, host) + if err != nil { + return nil, fmt.Errorf("socket: failed resolving %q: %v", host, err) + } + if len(packedAddrs) == 0 { + return nil, fmt.Errorf("no addresses for %q", host) + } + + packedAddr := packedAddrs[0] // use first address + fam := pb.CreateSocketRequest_IPv4 + if len(packedAddr) == net.IPv6len { + fam = pb.CreateSocketRequest_IPv6 + } + + req := &pb.CreateSocketRequest{ + Family: fam.Enum(), + Protocol: prot.Enum(), + RemoteIp: &pb.AddressPort{ + Port: proto.Int32(int32(port)), + PackedAddress: packedAddr, + }, + } + if resolved { + req.RemoteIp.HostnameHint = &host + } + res := &pb.CreateSocketReply{} + if err := internal.Call(dialCtx, "remote_socket", "CreateSocket", req, res); err != nil { + return nil, err + } + + return &Conn{ + ctx: ctx, + desc: res.GetSocketDescriptor(), + prot: prot, + local: res.ProxyExternalIp, + remote: req.RemoteIp, + }, nil +} + +// LookupIP returns the given host's IP addresses. +func LookupIP(ctx context.Context, host string) (addrs []net.IP, err error) { + packedAddrs, _, err := resolve(ctx, ipFamilies, host) + if err != nil { + return nil, fmt.Errorf("socket: failed resolving %q: %v", host, err) + } + addrs = make([]net.IP, len(packedAddrs)) + for i, pa := range packedAddrs { + addrs[i] = net.IP(pa) + } + return addrs, nil +} + +func resolve(ctx context.Context, fams []pb.CreateSocketRequest_SocketFamily, host string) ([][]byte, bool, error) { + // Check if it's an IP address. + if ip := net.ParseIP(host); ip != nil { + if ip := ip.To4(); ip != nil { + return [][]byte{ip}, false, nil + } + return [][]byte{ip}, false, nil + } + + req := &pb.ResolveRequest{ + Name: &host, + AddressFamilies: fams, + } + res := &pb.ResolveReply{} + if err := internal.Call(ctx, "remote_socket", "Resolve", req, res); err != nil { + // XXX: need to map to pb.ResolveReply_ErrorCode? + return nil, false, err + } + return res.PackedAddress, true, nil +} + +// withDeadline is like context.WithDeadline, except it ignores the zero deadline. +func withDeadline(parent context.Context, deadline time.Time) (context.Context, context.CancelFunc) { + if deadline.IsZero() { + return parent, func() {} + } + return context.WithDeadline(parent, deadline) +} + +// Conn represents a socket connection. +// It implements net.Conn. +type Conn struct { + ctx context.Context + desc string + offset int64 + + prot pb.CreateSocketRequest_SocketProtocol + local, remote *pb.AddressPort + + readDeadline, writeDeadline time.Time // optional +} + +// SetContext sets the context that is used by this Conn. +// It is usually used only when using a Conn that was created in a different context, +// such as when a connection is created during a warmup request but used while +// servicing a user request. +func (cn *Conn) SetContext(ctx context.Context) { + cn.ctx = ctx +} + +func (cn *Conn) Read(b []byte) (n int, err error) { + const maxRead = 1 << 20 + if len(b) > maxRead { + b = b[:maxRead] + } + + req := &pb.ReceiveRequest{ + SocketDescriptor: &cn.desc, + DataSize: proto.Int32(int32(len(b))), + } + res := &pb.ReceiveReply{} + if !cn.readDeadline.IsZero() { + req.TimeoutSeconds = proto.Float64(cn.readDeadline.Sub(time.Now()).Seconds()) + } + ctx, cancel := withDeadline(cn.ctx, cn.readDeadline) + defer cancel() + if err := internal.Call(ctx, "remote_socket", "Receive", req, res); err != nil { + return 0, err + } + if len(res.Data) == 0 { + return 0, io.EOF + } + if len(res.Data) > len(b) { + return 0, fmt.Errorf("socket: internal error: read too much data: %d > %d", len(res.Data), len(b)) + } + return copy(b, res.Data), nil +} + +func (cn *Conn) Write(b []byte) (n int, err error) { + const lim = 1 << 20 // max per chunk + + for n < len(b) { + chunk := b[n:] + if len(chunk) > lim { + chunk = chunk[:lim] + } + + req := &pb.SendRequest{ + SocketDescriptor: &cn.desc, + Data: chunk, + StreamOffset: &cn.offset, + } + res := &pb.SendReply{} + if !cn.writeDeadline.IsZero() { + req.TimeoutSeconds = proto.Float64(cn.writeDeadline.Sub(time.Now()).Seconds()) + } + ctx, cancel := withDeadline(cn.ctx, cn.writeDeadline) + defer cancel() + if err = internal.Call(ctx, "remote_socket", "Send", req, res); err != nil { + // assume zero bytes were sent in this RPC + break + } + n += int(res.GetDataSent()) + cn.offset += int64(res.GetDataSent()) + } + + return +} + +func (cn *Conn) Close() error { + req := &pb.CloseRequest{ + SocketDescriptor: &cn.desc, + } + res := &pb.CloseReply{} + if err := internal.Call(cn.ctx, "remote_socket", "Close", req, res); err != nil { + return err + } + cn.desc = "CLOSED" + return nil +} + +func addr(prot pb.CreateSocketRequest_SocketProtocol, ap *pb.AddressPort) net.Addr { + if ap == nil { + return nil + } + switch prot { + case pb.CreateSocketRequest_TCP: + return &net.TCPAddr{ + IP: net.IP(ap.PackedAddress), + Port: int(*ap.Port), + } + case pb.CreateSocketRequest_UDP: + return &net.UDPAddr{ + IP: net.IP(ap.PackedAddress), + Port: int(*ap.Port), + } + } + panic("unknown protocol " + prot.String()) +} + +func (cn *Conn) LocalAddr() net.Addr { return addr(cn.prot, cn.local) } +func (cn *Conn) RemoteAddr() net.Addr { return addr(cn.prot, cn.remote) } + +func (cn *Conn) SetDeadline(t time.Time) error { + cn.readDeadline = t + cn.writeDeadline = t + return nil +} + +func (cn *Conn) SetReadDeadline(t time.Time) error { + cn.readDeadline = t + return nil +} + +func (cn *Conn) SetWriteDeadline(t time.Time) error { + cn.writeDeadline = t + return nil +} + +// KeepAlive signals that the connection is still in use. +// It may be called to prevent the socket being closed due to inactivity. +func (cn *Conn) KeepAlive() error { + req := &pb.GetSocketNameRequest{ + SocketDescriptor: &cn.desc, + } + res := &pb.GetSocketNameReply{} + return internal.Call(cn.ctx, "remote_socket", "GetSocketName", req, res) +} + +func init() { + internal.RegisterErrorCodeMap("remote_socket", pb.RemoteSocketServiceError_ErrorCode_name) +} diff --git a/vendor/google.golang.org/appengine/socket/socket_vm.go b/vendor/google.golang.org/appengine/socket/socket_vm.go new file mode 100644 index 00000000000..c804169a1c0 --- /dev/null +++ b/vendor/google.golang.org/appengine/socket/socket_vm.go @@ -0,0 +1,64 @@ +// Copyright 2015 Google Inc. All rights reserved. +// Use of this source code is governed by the Apache 2.0 +// license that can be found in the LICENSE file. + +// +build !appengine + +package socket + +import ( + "net" + "time" + + "golang.org/x/net/context" +) + +// Dial connects to the address addr on the network protocol. +// The address format is host:port, where host may be a hostname or an IP address. +// Known protocols are "tcp" and "udp". +// The returned connection satisfies net.Conn, and is valid while ctx is valid; +// if the connection is to be used after ctx becomes invalid, invoke SetContext +// with the new context. +func Dial(ctx context.Context, protocol, addr string) (*Conn, error) { + conn, err := net.Dial(protocol, addr) + if err != nil { + return nil, err + } + return &Conn{conn}, nil +} + +// DialTimeout is like Dial but takes a timeout. +// The timeout includes name resolution, if required. +func DialTimeout(ctx context.Context, protocol, addr string, timeout time.Duration) (*Conn, error) { + conn, err := net.DialTimeout(protocol, addr, timeout) + if err != nil { + return nil, err + } + return &Conn{conn}, nil +} + +// LookupIP returns the given host's IP addresses. +func LookupIP(ctx context.Context, host string) (addrs []net.IP, err error) { + return net.LookupIP(host) +} + +// Conn represents a socket connection. +// It implements net.Conn. +type Conn struct { + net.Conn +} + +// SetContext sets the context that is used by this Conn. +// It is usually used only when using a Conn that was created in a different context, +// such as when a connection is created during a warmup request but used while +// servicing a user request. +func (cn *Conn) SetContext(ctx context.Context) { + // This function is not required in App Engine "flexible environment". +} + +// KeepAlive signals that the connection is still in use. +// It may be called to prevent the socket being closed due to inactivity. +func (cn *Conn) KeepAlive() error { + // This function is not required in App Engine "flexible environment". + return nil +} diff --git a/vendor/google.golang.org/genproto/googleapis/api/annotations/annotations.pb.go b/vendor/google.golang.org/genproto/googleapis/api/annotations/annotations.pb.go index 55111d110c7..191bea48c86 100644 --- a/vendor/google.golang.org/genproto/googleapis/api/annotations/annotations.pb.go +++ b/vendor/google.golang.org/genproto/googleapis/api/annotations/annotations.pb.go @@ -1,4 +1,4 @@ -// Copyright (c) 2015, Google Inc. +// Copyright 2015 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -14,8 +14,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.25.0 -// protoc v3.13.0 +// protoc-gen-go v1.26.0 +// protoc v3.12.2 // source: google/api/annotations.proto package annotations @@ -23,7 +23,6 @@ package annotations import ( reflect "reflect" - proto "github.com/golang/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" descriptorpb "google.golang.org/protobuf/types/descriptorpb" @@ -36,10 +35,6 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - var file_google_api_annotations_proto_extTypes = []protoimpl.ExtensionInfo{ { ExtendedType: (*descriptorpb.MethodOptions)(nil), diff --git a/vendor/google.golang.org/genproto/googleapis/api/annotations/client.pb.go b/vendor/google.golang.org/genproto/googleapis/api/annotations/client.pb.go index e4324641d6c..bb9d9489317 100644 --- a/vendor/google.golang.org/genproto/googleapis/api/annotations/client.pb.go +++ b/vendor/google.golang.org/genproto/googleapis/api/annotations/client.pb.go @@ -1,4 +1,4 @@ -// Copyright 2020 Google LLC +// Copyright 2023 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -14,19 +14,21 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.25.0 -// protoc v3.13.0 +// protoc-gen-go v1.26.0 +// protoc v3.21.9 // source: google/api/client.proto package annotations import ( reflect "reflect" + sync "sync" - proto "github.com/golang/protobuf/proto" + api "google.golang.org/genproto/googleapis/api" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" descriptorpb "google.golang.org/protobuf/types/descriptorpb" + durationpb "google.golang.org/protobuf/types/known/durationpb" ) const ( @@ -36,9 +38,1121 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 +// The organization for which the client libraries are being published. +// Affects the url where generated docs are published, etc. +type ClientLibraryOrganization int32 + +const ( + // Not useful. + ClientLibraryOrganization_CLIENT_LIBRARY_ORGANIZATION_UNSPECIFIED ClientLibraryOrganization = 0 + // Google Cloud Platform Org. + ClientLibraryOrganization_CLOUD ClientLibraryOrganization = 1 + // Ads (Advertising) Org. + ClientLibraryOrganization_ADS ClientLibraryOrganization = 2 + // Photos Org. + ClientLibraryOrganization_PHOTOS ClientLibraryOrganization = 3 + // Street View Org. + ClientLibraryOrganization_STREET_VIEW ClientLibraryOrganization = 4 +) + +// Enum value maps for ClientLibraryOrganization. +var ( + ClientLibraryOrganization_name = map[int32]string{ + 0: "CLIENT_LIBRARY_ORGANIZATION_UNSPECIFIED", + 1: "CLOUD", + 2: "ADS", + 3: "PHOTOS", + 4: "STREET_VIEW", + } + ClientLibraryOrganization_value = map[string]int32{ + "CLIENT_LIBRARY_ORGANIZATION_UNSPECIFIED": 0, + "CLOUD": 1, + "ADS": 2, + "PHOTOS": 3, + "STREET_VIEW": 4, + } +) + +func (x ClientLibraryOrganization) Enum() *ClientLibraryOrganization { + p := new(ClientLibraryOrganization) + *p = x + return p +} + +func (x ClientLibraryOrganization) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ClientLibraryOrganization) Descriptor() protoreflect.EnumDescriptor { + return file_google_api_client_proto_enumTypes[0].Descriptor() +} + +func (ClientLibraryOrganization) Type() protoreflect.EnumType { + return &file_google_api_client_proto_enumTypes[0] +} + +func (x ClientLibraryOrganization) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ClientLibraryOrganization.Descriptor instead. +func (ClientLibraryOrganization) EnumDescriptor() ([]byte, []int) { + return file_google_api_client_proto_rawDescGZIP(), []int{0} +} + +// To where should client libraries be published? +type ClientLibraryDestination int32 + +const ( + // Client libraries will neither be generated nor published to package + // managers. + ClientLibraryDestination_CLIENT_LIBRARY_DESTINATION_UNSPECIFIED ClientLibraryDestination = 0 + // Generate the client library in a repo under github.com/googleapis, + // but don't publish it to package managers. + ClientLibraryDestination_GITHUB ClientLibraryDestination = 10 + // Publish the library to package managers like nuget.org and npmjs.com. + ClientLibraryDestination_PACKAGE_MANAGER ClientLibraryDestination = 20 +) + +// Enum value maps for ClientLibraryDestination. +var ( + ClientLibraryDestination_name = map[int32]string{ + 0: "CLIENT_LIBRARY_DESTINATION_UNSPECIFIED", + 10: "GITHUB", + 20: "PACKAGE_MANAGER", + } + ClientLibraryDestination_value = map[string]int32{ + "CLIENT_LIBRARY_DESTINATION_UNSPECIFIED": 0, + "GITHUB": 10, + "PACKAGE_MANAGER": 20, + } +) + +func (x ClientLibraryDestination) Enum() *ClientLibraryDestination { + p := new(ClientLibraryDestination) + *p = x + return p +} + +func (x ClientLibraryDestination) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ClientLibraryDestination) Descriptor() protoreflect.EnumDescriptor { + return file_google_api_client_proto_enumTypes[1].Descriptor() +} + +func (ClientLibraryDestination) Type() protoreflect.EnumType { + return &file_google_api_client_proto_enumTypes[1] +} + +func (x ClientLibraryDestination) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ClientLibraryDestination.Descriptor instead. +func (ClientLibraryDestination) EnumDescriptor() ([]byte, []int) { + return file_google_api_client_proto_rawDescGZIP(), []int{1} +} + +// Required information for every language. +type CommonLanguageSettings struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Link to automatically generated reference documentation. Example: + // https://cloud.google.com/nodejs/docs/reference/asset/latest + // + // Deprecated: Do not use. + ReferenceDocsUri string `protobuf:"bytes,1,opt,name=reference_docs_uri,json=referenceDocsUri,proto3" json:"reference_docs_uri,omitempty"` + // The destination where API teams want this client library to be published. + Destinations []ClientLibraryDestination `protobuf:"varint,2,rep,packed,name=destinations,proto3,enum=google.api.ClientLibraryDestination" json:"destinations,omitempty"` +} + +func (x *CommonLanguageSettings) Reset() { + *x = CommonLanguageSettings{} + if protoimpl.UnsafeEnabled { + mi := &file_google_api_client_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CommonLanguageSettings) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommonLanguageSettings) ProtoMessage() {} + +func (x *CommonLanguageSettings) ProtoReflect() protoreflect.Message { + mi := &file_google_api_client_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommonLanguageSettings.ProtoReflect.Descriptor instead. +func (*CommonLanguageSettings) Descriptor() ([]byte, []int) { + return file_google_api_client_proto_rawDescGZIP(), []int{0} +} + +// Deprecated: Do not use. +func (x *CommonLanguageSettings) GetReferenceDocsUri() string { + if x != nil { + return x.ReferenceDocsUri + } + return "" +} + +func (x *CommonLanguageSettings) GetDestinations() []ClientLibraryDestination { + if x != nil { + return x.Destinations + } + return nil +} + +// Details about how and where to publish client libraries. +type ClientLibrarySettings struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Version of the API to apply these settings to. This is the full protobuf + // package for the API, ending in the version element. + // Examples: "google.cloud.speech.v1" and "google.spanner.admin.database.v1". + Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"` + // Launch stage of this version of the API. + LaunchStage api.LaunchStage `protobuf:"varint,2,opt,name=launch_stage,json=launchStage,proto3,enum=google.api.LaunchStage" json:"launch_stage,omitempty"` + // When using transport=rest, the client request will encode enums as + // numbers rather than strings. + RestNumericEnums bool `protobuf:"varint,3,opt,name=rest_numeric_enums,json=restNumericEnums,proto3" json:"rest_numeric_enums,omitempty"` + // Settings for legacy Java features, supported in the Service YAML. + JavaSettings *JavaSettings `protobuf:"bytes,21,opt,name=java_settings,json=javaSettings,proto3" json:"java_settings,omitempty"` + // Settings for C++ client libraries. + CppSettings *CppSettings `protobuf:"bytes,22,opt,name=cpp_settings,json=cppSettings,proto3" json:"cpp_settings,omitempty"` + // Settings for PHP client libraries. + PhpSettings *PhpSettings `protobuf:"bytes,23,opt,name=php_settings,json=phpSettings,proto3" json:"php_settings,omitempty"` + // Settings for Python client libraries. + PythonSettings *PythonSettings `protobuf:"bytes,24,opt,name=python_settings,json=pythonSettings,proto3" json:"python_settings,omitempty"` + // Settings for Node client libraries. + NodeSettings *NodeSettings `protobuf:"bytes,25,opt,name=node_settings,json=nodeSettings,proto3" json:"node_settings,omitempty"` + // Settings for .NET client libraries. + DotnetSettings *DotnetSettings `protobuf:"bytes,26,opt,name=dotnet_settings,json=dotnetSettings,proto3" json:"dotnet_settings,omitempty"` + // Settings for Ruby client libraries. + RubySettings *RubySettings `protobuf:"bytes,27,opt,name=ruby_settings,json=rubySettings,proto3" json:"ruby_settings,omitempty"` + // Settings for Go client libraries. + GoSettings *GoSettings `protobuf:"bytes,28,opt,name=go_settings,json=goSettings,proto3" json:"go_settings,omitempty"` +} + +func (x *ClientLibrarySettings) Reset() { + *x = ClientLibrarySettings{} + if protoimpl.UnsafeEnabled { + mi := &file_google_api_client_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ClientLibrarySettings) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ClientLibrarySettings) ProtoMessage() {} + +func (x *ClientLibrarySettings) ProtoReflect() protoreflect.Message { + mi := &file_google_api_client_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ClientLibrarySettings.ProtoReflect.Descriptor instead. +func (*ClientLibrarySettings) Descriptor() ([]byte, []int) { + return file_google_api_client_proto_rawDescGZIP(), []int{1} +} + +func (x *ClientLibrarySettings) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *ClientLibrarySettings) GetLaunchStage() api.LaunchStage { + if x != nil { + return x.LaunchStage + } + return api.LaunchStage_LAUNCH_STAGE_UNSPECIFIED +} + +func (x *ClientLibrarySettings) GetRestNumericEnums() bool { + if x != nil { + return x.RestNumericEnums + } + return false +} + +func (x *ClientLibrarySettings) GetJavaSettings() *JavaSettings { + if x != nil { + return x.JavaSettings + } + return nil +} + +func (x *ClientLibrarySettings) GetCppSettings() *CppSettings { + if x != nil { + return x.CppSettings + } + return nil +} + +func (x *ClientLibrarySettings) GetPhpSettings() *PhpSettings { + if x != nil { + return x.PhpSettings + } + return nil +} + +func (x *ClientLibrarySettings) GetPythonSettings() *PythonSettings { + if x != nil { + return x.PythonSettings + } + return nil +} + +func (x *ClientLibrarySettings) GetNodeSettings() *NodeSettings { + if x != nil { + return x.NodeSettings + } + return nil +} + +func (x *ClientLibrarySettings) GetDotnetSettings() *DotnetSettings { + if x != nil { + return x.DotnetSettings + } + return nil +} + +func (x *ClientLibrarySettings) GetRubySettings() *RubySettings { + if x != nil { + return x.RubySettings + } + return nil +} + +func (x *ClientLibrarySettings) GetGoSettings() *GoSettings { + if x != nil { + return x.GoSettings + } + return nil +} + +// This message configures the settings for publishing [Google Cloud Client +// libraries](https://cloud.google.com/apis/docs/cloud-client-libraries) +// generated from the service config. +type Publishing struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // A list of API method settings, e.g. the behavior for methods that use the + // long-running operation pattern. + MethodSettings []*MethodSettings `protobuf:"bytes,2,rep,name=method_settings,json=methodSettings,proto3" json:"method_settings,omitempty"` + // Link to a place that API users can report issues. Example: + // https://issuetracker.google.com/issues/new?component=190865&template=1161103 + NewIssueUri string `protobuf:"bytes,101,opt,name=new_issue_uri,json=newIssueUri,proto3" json:"new_issue_uri,omitempty"` + // Link to product home page. Example: + // https://cloud.google.com/asset-inventory/docs/overview + DocumentationUri string `protobuf:"bytes,102,opt,name=documentation_uri,json=documentationUri,proto3" json:"documentation_uri,omitempty"` + // Used as a tracking tag when collecting data about the APIs developer + // relations artifacts like docs, packages delivered to package managers, + // etc. Example: "speech". + ApiShortName string `protobuf:"bytes,103,opt,name=api_short_name,json=apiShortName,proto3" json:"api_short_name,omitempty"` + // GitHub label to apply to issues and pull requests opened for this API. + GithubLabel string `protobuf:"bytes,104,opt,name=github_label,json=githubLabel,proto3" json:"github_label,omitempty"` + // GitHub teams to be added to CODEOWNERS in the directory in GitHub + // containing source code for the client libraries for this API. + CodeownerGithubTeams []string `protobuf:"bytes,105,rep,name=codeowner_github_teams,json=codeownerGithubTeams,proto3" json:"codeowner_github_teams,omitempty"` + // A prefix used in sample code when demarking regions to be included in + // documentation. + DocTagPrefix string `protobuf:"bytes,106,opt,name=doc_tag_prefix,json=docTagPrefix,proto3" json:"doc_tag_prefix,omitempty"` + // For whom the client library is being published. + Organization ClientLibraryOrganization `protobuf:"varint,107,opt,name=organization,proto3,enum=google.api.ClientLibraryOrganization" json:"organization,omitempty"` + // Client library settings. If the same version string appears multiple + // times in this list, then the last one wins. Settings from earlier + // settings with the same version string are discarded. + LibrarySettings []*ClientLibrarySettings `protobuf:"bytes,109,rep,name=library_settings,json=librarySettings,proto3" json:"library_settings,omitempty"` + // Optional link to proto reference documentation. Example: + // https://cloud.google.com/pubsub/lite/docs/reference/rpc + ProtoReferenceDocumentationUri string `protobuf:"bytes,110,opt,name=proto_reference_documentation_uri,json=protoReferenceDocumentationUri,proto3" json:"proto_reference_documentation_uri,omitempty"` +} + +func (x *Publishing) Reset() { + *x = Publishing{} + if protoimpl.UnsafeEnabled { + mi := &file_google_api_client_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Publishing) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Publishing) ProtoMessage() {} + +func (x *Publishing) ProtoReflect() protoreflect.Message { + mi := &file_google_api_client_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Publishing.ProtoReflect.Descriptor instead. +func (*Publishing) Descriptor() ([]byte, []int) { + return file_google_api_client_proto_rawDescGZIP(), []int{2} +} + +func (x *Publishing) GetMethodSettings() []*MethodSettings { + if x != nil { + return x.MethodSettings + } + return nil +} + +func (x *Publishing) GetNewIssueUri() string { + if x != nil { + return x.NewIssueUri + } + return "" +} + +func (x *Publishing) GetDocumentationUri() string { + if x != nil { + return x.DocumentationUri + } + return "" +} + +func (x *Publishing) GetApiShortName() string { + if x != nil { + return x.ApiShortName + } + return "" +} + +func (x *Publishing) GetGithubLabel() string { + if x != nil { + return x.GithubLabel + } + return "" +} + +func (x *Publishing) GetCodeownerGithubTeams() []string { + if x != nil { + return x.CodeownerGithubTeams + } + return nil +} + +func (x *Publishing) GetDocTagPrefix() string { + if x != nil { + return x.DocTagPrefix + } + return "" +} + +func (x *Publishing) GetOrganization() ClientLibraryOrganization { + if x != nil { + return x.Organization + } + return ClientLibraryOrganization_CLIENT_LIBRARY_ORGANIZATION_UNSPECIFIED +} + +func (x *Publishing) GetLibrarySettings() []*ClientLibrarySettings { + if x != nil { + return x.LibrarySettings + } + return nil +} + +func (x *Publishing) GetProtoReferenceDocumentationUri() string { + if x != nil { + return x.ProtoReferenceDocumentationUri + } + return "" +} + +// Settings for Java client libraries. +type JavaSettings struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The package name to use in Java. Clobbers the java_package option + // set in the protobuf. This should be used **only** by APIs + // who have already set the language_settings.java.package_name" field + // in gapic.yaml. API teams should use the protobuf java_package option + // where possible. + // + // Example of a YAML configuration:: + // + // publishing: + // java_settings: + // library_package: com.google.cloud.pubsub.v1 + LibraryPackage string `protobuf:"bytes,1,opt,name=library_package,json=libraryPackage,proto3" json:"library_package,omitempty"` + // Configure the Java class name to use instead of the service's for its + // corresponding generated GAPIC client. Keys are fully-qualified + // service names as they appear in the protobuf (including the full + // the language_settings.java.interface_names" field in gapic.yaml. API + // teams should otherwise use the service name as it appears in the + // protobuf. + // + // Example of a YAML configuration:: + // + // publishing: + // java_settings: + // service_class_names: + // - google.pubsub.v1.Publisher: TopicAdmin + // - google.pubsub.v1.Subscriber: SubscriptionAdmin + ServiceClassNames map[string]string `protobuf:"bytes,2,rep,name=service_class_names,json=serviceClassNames,proto3" json:"service_class_names,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // Some settings. + Common *CommonLanguageSettings `protobuf:"bytes,3,opt,name=common,proto3" json:"common,omitempty"` +} + +func (x *JavaSettings) Reset() { + *x = JavaSettings{} + if protoimpl.UnsafeEnabled { + mi := &file_google_api_client_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *JavaSettings) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*JavaSettings) ProtoMessage() {} + +func (x *JavaSettings) ProtoReflect() protoreflect.Message { + mi := &file_google_api_client_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use JavaSettings.ProtoReflect.Descriptor instead. +func (*JavaSettings) Descriptor() ([]byte, []int) { + return file_google_api_client_proto_rawDescGZIP(), []int{3} +} + +func (x *JavaSettings) GetLibraryPackage() string { + if x != nil { + return x.LibraryPackage + } + return "" +} + +func (x *JavaSettings) GetServiceClassNames() map[string]string { + if x != nil { + return x.ServiceClassNames + } + return nil +} + +func (x *JavaSettings) GetCommon() *CommonLanguageSettings { + if x != nil { + return x.Common + } + return nil +} + +// Settings for C++ client libraries. +type CppSettings struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Some settings. + Common *CommonLanguageSettings `protobuf:"bytes,1,opt,name=common,proto3" json:"common,omitempty"` +} + +func (x *CppSettings) Reset() { + *x = CppSettings{} + if protoimpl.UnsafeEnabled { + mi := &file_google_api_client_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CppSettings) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CppSettings) ProtoMessage() {} + +func (x *CppSettings) ProtoReflect() protoreflect.Message { + mi := &file_google_api_client_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CppSettings.ProtoReflect.Descriptor instead. +func (*CppSettings) Descriptor() ([]byte, []int) { + return file_google_api_client_proto_rawDescGZIP(), []int{4} +} + +func (x *CppSettings) GetCommon() *CommonLanguageSettings { + if x != nil { + return x.Common + } + return nil +} + +// Settings for Php client libraries. +type PhpSettings struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Some settings. + Common *CommonLanguageSettings `protobuf:"bytes,1,opt,name=common,proto3" json:"common,omitempty"` +} + +func (x *PhpSettings) Reset() { + *x = PhpSettings{} + if protoimpl.UnsafeEnabled { + mi := &file_google_api_client_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PhpSettings) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PhpSettings) ProtoMessage() {} + +func (x *PhpSettings) ProtoReflect() protoreflect.Message { + mi := &file_google_api_client_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PhpSettings.ProtoReflect.Descriptor instead. +func (*PhpSettings) Descriptor() ([]byte, []int) { + return file_google_api_client_proto_rawDescGZIP(), []int{5} +} + +func (x *PhpSettings) GetCommon() *CommonLanguageSettings { + if x != nil { + return x.Common + } + return nil +} + +// Settings for Python client libraries. +type PythonSettings struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Some settings. + Common *CommonLanguageSettings `protobuf:"bytes,1,opt,name=common,proto3" json:"common,omitempty"` +} + +func (x *PythonSettings) Reset() { + *x = PythonSettings{} + if protoimpl.UnsafeEnabled { + mi := &file_google_api_client_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PythonSettings) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PythonSettings) ProtoMessage() {} + +func (x *PythonSettings) ProtoReflect() protoreflect.Message { + mi := &file_google_api_client_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PythonSettings.ProtoReflect.Descriptor instead. +func (*PythonSettings) Descriptor() ([]byte, []int) { + return file_google_api_client_proto_rawDescGZIP(), []int{6} +} + +func (x *PythonSettings) GetCommon() *CommonLanguageSettings { + if x != nil { + return x.Common + } + return nil +} + +// Settings for Node client libraries. +type NodeSettings struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Some settings. + Common *CommonLanguageSettings `protobuf:"bytes,1,opt,name=common,proto3" json:"common,omitempty"` +} + +func (x *NodeSettings) Reset() { + *x = NodeSettings{} + if protoimpl.UnsafeEnabled { + mi := &file_google_api_client_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NodeSettings) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NodeSettings) ProtoMessage() {} + +func (x *NodeSettings) ProtoReflect() protoreflect.Message { + mi := &file_google_api_client_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NodeSettings.ProtoReflect.Descriptor instead. +func (*NodeSettings) Descriptor() ([]byte, []int) { + return file_google_api_client_proto_rawDescGZIP(), []int{7} +} + +func (x *NodeSettings) GetCommon() *CommonLanguageSettings { + if x != nil { + return x.Common + } + return nil +} + +// Settings for Dotnet client libraries. +type DotnetSettings struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Some settings. + Common *CommonLanguageSettings `protobuf:"bytes,1,opt,name=common,proto3" json:"common,omitempty"` + // Map from original service names to renamed versions. + // This is used when the default generated types + // would cause a naming conflict. (Neither name is + // fully-qualified.) + // Example: Subscriber to SubscriberServiceApi. + RenamedServices map[string]string `protobuf:"bytes,2,rep,name=renamed_services,json=renamedServices,proto3" json:"renamed_services,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // Map from full resource types to the effective short name + // for the resource. This is used when otherwise resource + // named from different services would cause naming collisions. + // Example entry: + // "datalabeling.googleapis.com/Dataset": "DataLabelingDataset" + RenamedResources map[string]string `protobuf:"bytes,3,rep,name=renamed_resources,json=renamedResources,proto3" json:"renamed_resources,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // List of full resource types to ignore during generation. + // This is typically used for API-specific Location resources, + // which should be handled by the generator as if they were actually + // the common Location resources. + // Example entry: "documentai.googleapis.com/Location" + IgnoredResources []string `protobuf:"bytes,4,rep,name=ignored_resources,json=ignoredResources,proto3" json:"ignored_resources,omitempty"` + // Namespaces which must be aliased in snippets due to + // a known (but non-generator-predictable) naming collision + ForcedNamespaceAliases []string `protobuf:"bytes,5,rep,name=forced_namespace_aliases,json=forcedNamespaceAliases,proto3" json:"forced_namespace_aliases,omitempty"` + // Method signatures (in the form "service.method(signature)") + // which are provided separately, so shouldn't be generated. + // Snippets *calling* these methods are still generated, however. + HandwrittenSignatures []string `protobuf:"bytes,6,rep,name=handwritten_signatures,json=handwrittenSignatures,proto3" json:"handwritten_signatures,omitempty"` +} + +func (x *DotnetSettings) Reset() { + *x = DotnetSettings{} + if protoimpl.UnsafeEnabled { + mi := &file_google_api_client_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DotnetSettings) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DotnetSettings) ProtoMessage() {} + +func (x *DotnetSettings) ProtoReflect() protoreflect.Message { + mi := &file_google_api_client_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DotnetSettings.ProtoReflect.Descriptor instead. +func (*DotnetSettings) Descriptor() ([]byte, []int) { + return file_google_api_client_proto_rawDescGZIP(), []int{8} +} + +func (x *DotnetSettings) GetCommon() *CommonLanguageSettings { + if x != nil { + return x.Common + } + return nil +} + +func (x *DotnetSettings) GetRenamedServices() map[string]string { + if x != nil { + return x.RenamedServices + } + return nil +} + +func (x *DotnetSettings) GetRenamedResources() map[string]string { + if x != nil { + return x.RenamedResources + } + return nil +} + +func (x *DotnetSettings) GetIgnoredResources() []string { + if x != nil { + return x.IgnoredResources + } + return nil +} + +func (x *DotnetSettings) GetForcedNamespaceAliases() []string { + if x != nil { + return x.ForcedNamespaceAliases + } + return nil +} + +func (x *DotnetSettings) GetHandwrittenSignatures() []string { + if x != nil { + return x.HandwrittenSignatures + } + return nil +} + +// Settings for Ruby client libraries. +type RubySettings struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Some settings. + Common *CommonLanguageSettings `protobuf:"bytes,1,opt,name=common,proto3" json:"common,omitempty"` +} + +func (x *RubySettings) Reset() { + *x = RubySettings{} + if protoimpl.UnsafeEnabled { + mi := &file_google_api_client_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RubySettings) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RubySettings) ProtoMessage() {} + +func (x *RubySettings) ProtoReflect() protoreflect.Message { + mi := &file_google_api_client_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RubySettings.ProtoReflect.Descriptor instead. +func (*RubySettings) Descriptor() ([]byte, []int) { + return file_google_api_client_proto_rawDescGZIP(), []int{9} +} + +func (x *RubySettings) GetCommon() *CommonLanguageSettings { + if x != nil { + return x.Common + } + return nil +} + +// Settings for Go client libraries. +type GoSettings struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Some settings. + Common *CommonLanguageSettings `protobuf:"bytes,1,opt,name=common,proto3" json:"common,omitempty"` +} + +func (x *GoSettings) Reset() { + *x = GoSettings{} + if protoimpl.UnsafeEnabled { + mi := &file_google_api_client_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GoSettings) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GoSettings) ProtoMessage() {} + +func (x *GoSettings) ProtoReflect() protoreflect.Message { + mi := &file_google_api_client_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GoSettings.ProtoReflect.Descriptor instead. +func (*GoSettings) Descriptor() ([]byte, []int) { + return file_google_api_client_proto_rawDescGZIP(), []int{10} +} + +func (x *GoSettings) GetCommon() *CommonLanguageSettings { + if x != nil { + return x.Common + } + return nil +} + +// Describes the generator configuration for a method. +type MethodSettings struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The fully qualified name of the method, for which the options below apply. + // This is used to find the method to apply the options. + Selector string `protobuf:"bytes,1,opt,name=selector,proto3" json:"selector,omitempty"` + // Describes settings to use for long-running operations when generating + // API methods for RPCs. Complements RPCs that use the annotations in + // google/longrunning/operations.proto. + // + // Example of a YAML configuration:: + // + // publishing: + // method_settings: + // - selector: google.cloud.speech.v2.Speech.BatchRecognize + // long_running: + // initial_poll_delay: + // seconds: 60 # 1 minute + // poll_delay_multiplier: 1.5 + // max_poll_delay: + // seconds: 360 # 6 minutes + // total_poll_timeout: + // seconds: 54000 # 90 minutes + LongRunning *MethodSettings_LongRunning `protobuf:"bytes,2,opt,name=long_running,json=longRunning,proto3" json:"long_running,omitempty"` +} + +func (x *MethodSettings) Reset() { + *x = MethodSettings{} + if protoimpl.UnsafeEnabled { + mi := &file_google_api_client_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MethodSettings) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MethodSettings) ProtoMessage() {} + +func (x *MethodSettings) ProtoReflect() protoreflect.Message { + mi := &file_google_api_client_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MethodSettings.ProtoReflect.Descriptor instead. +func (*MethodSettings) Descriptor() ([]byte, []int) { + return file_google_api_client_proto_rawDescGZIP(), []int{11} +} + +func (x *MethodSettings) GetSelector() string { + if x != nil { + return x.Selector + } + return "" +} + +func (x *MethodSettings) GetLongRunning() *MethodSettings_LongRunning { + if x != nil { + return x.LongRunning + } + return nil +} + +// Describes settings to use when generating API methods that use the +// long-running operation pattern. +// All default values below are from those used in the client library +// generators (e.g. +// [Java](https://github.com/googleapis/gapic-generator-java/blob/04c2faa191a9b5a10b92392fe8482279c4404803/src/main/java/com/google/api/generator/gapic/composer/common/RetrySettingsComposer.java)). +type MethodSettings_LongRunning struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Initial delay after which the first poll request will be made. + // Default value: 5 seconds. + InitialPollDelay *durationpb.Duration `protobuf:"bytes,1,opt,name=initial_poll_delay,json=initialPollDelay,proto3" json:"initial_poll_delay,omitempty"` + // Multiplier to gradually increase delay between subsequent polls until it + // reaches max_poll_delay. + // Default value: 1.5. + PollDelayMultiplier float32 `protobuf:"fixed32,2,opt,name=poll_delay_multiplier,json=pollDelayMultiplier,proto3" json:"poll_delay_multiplier,omitempty"` + // Maximum time between two subsequent poll requests. + // Default value: 45 seconds. + MaxPollDelay *durationpb.Duration `protobuf:"bytes,3,opt,name=max_poll_delay,json=maxPollDelay,proto3" json:"max_poll_delay,omitempty"` + // Total polling timeout. + // Default value: 5 minutes. + TotalPollTimeout *durationpb.Duration `protobuf:"bytes,4,opt,name=total_poll_timeout,json=totalPollTimeout,proto3" json:"total_poll_timeout,omitempty"` +} + +func (x *MethodSettings_LongRunning) Reset() { + *x = MethodSettings_LongRunning{} + if protoimpl.UnsafeEnabled { + mi := &file_google_api_client_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MethodSettings_LongRunning) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MethodSettings_LongRunning) ProtoMessage() {} + +func (x *MethodSettings_LongRunning) ProtoReflect() protoreflect.Message { + mi := &file_google_api_client_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MethodSettings_LongRunning.ProtoReflect.Descriptor instead. +func (*MethodSettings_LongRunning) Descriptor() ([]byte, []int) { + return file_google_api_client_proto_rawDescGZIP(), []int{11, 0} +} + +func (x *MethodSettings_LongRunning) GetInitialPollDelay() *durationpb.Duration { + if x != nil { + return x.InitialPollDelay + } + return nil +} + +func (x *MethodSettings_LongRunning) GetPollDelayMultiplier() float32 { + if x != nil { + return x.PollDelayMultiplier + } + return 0 +} + +func (x *MethodSettings_LongRunning) GetMaxPollDelay() *durationpb.Duration { + if x != nil { + return x.MaxPollDelay + } + return nil +} + +func (x *MethodSettings_LongRunning) GetTotalPollTimeout() *durationpb.Duration { + if x != nil { + return x.TotalPollTimeout + } + return nil +} var file_google_api_client_proto_extTypes = []protoimpl.ExtensionInfo{ { @@ -83,26 +1197,26 @@ var ( // // For example, the proto RPC and annotation: // - // rpc CreateSubscription(CreateSubscriptionRequest) - // returns (Subscription) { - // option (google.api.method_signature) = "name,topic"; - // } + // rpc CreateSubscription(CreateSubscriptionRequest) + // returns (Subscription) { + // option (google.api.method_signature) = "name,topic"; + // } // // Would add the following Java overload (in addition to the method accepting // the request object): // - // public final Subscription createSubscription(String name, String topic) + // public final Subscription createSubscription(String name, String topic) // // The following backwards-compatibility guidelines apply: // - // * Adding this annotation to an unannotated method is backwards + // - Adding this annotation to an unannotated method is backwards // compatible. - // * Adding this annotation to a method which already has existing + // - Adding this annotation to a method which already has existing // method signature annotations is backwards compatible if and only if // the new method signature annotation is last in the sequence. - // * Modifying or removing an existing method signature annotation is + // - Modifying or removing an existing method signature annotation is // a breaking change. - // * Re-ordering existing method signature annotations is a breaking + // - Re-ordering existing method signature annotations is a breaking // change. // // repeated string method_signature = 1051; @@ -116,10 +1230,10 @@ var ( // // Example: // - // service Foo { - // option (google.api.default_host) = "foo.googleapi.com"; - // ... - // } + // service Foo { + // option (google.api.default_host) = "foo.googleapi.com"; + // ... + // } // // optional string default_host = 1049; E_DefaultHost = &file_google_api_client_proto_extTypes[1] @@ -127,22 +1241,22 @@ var ( // // Example: // - // service Foo { - // option (google.api.oauth_scopes) = \ - // "https://www.googleapis.com/auth/cloud-platform"; - // ... - // } + // service Foo { + // option (google.api.oauth_scopes) = \ + // "https://www.googleapis.com/auth/cloud-platform"; + // ... + // } // // If there is more than one scope, use a comma-separated string: // // Example: // - // service Foo { - // option (google.api.oauth_scopes) = \ - // "https://www.googleapis.com/auth/cloud-platform," - // "https://www.googleapis.com/auth/monitoring"; - // ... - // } + // service Foo { + // option (google.api.oauth_scopes) = \ + // "https://www.googleapis.com/auth/cloud-platform," + // "https://www.googleapis.com/auth/monitoring"; + // ... + // } // // optional string oauth_scopes = 1050; E_OauthScopes = &file_google_api_client_proto_extTypes[2] @@ -153,44 +1267,317 @@ var File_google_api_client_proto protoreflect.FileDescriptor var file_google_api_client_proto_rawDesc = []byte{ 0x0a, 0x17, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0a, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x61, 0x70, 0x69, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, - 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x3a, 0x4a, 0x0a, 0x10, 0x6d, 0x65, 0x74, 0x68, 0x6f, - 0x64, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x1e, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, - 0x74, 0x68, 0x6f, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x9b, 0x08, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x0f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, - 0x75, 0x72, 0x65, 0x3a, 0x43, 0x0a, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x68, - 0x6f, 0x73, 0x74, 0x12, 0x1f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4f, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x99, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x66, - 0x61, 0x75, 0x6c, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x43, 0x0a, 0x0c, 0x6f, 0x61, 0x75, 0x74, - 0x68, 0x5f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x12, 0x1f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x9a, 0x08, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0b, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x42, 0x69, 0x0a, - 0x0e, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x42, - 0x0b, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x41, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, - 0x67, 0x2f, 0x67, 0x65, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0xa2, 0x02, 0x04, 0x47, 0x41, 0x50, 0x49, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x2e, 0x61, 0x70, 0x69, 0x1a, 0x1d, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, + 0x69, 0x2f, 0x6c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x5f, 0x73, 0x74, 0x61, 0x67, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x94, 0x01, 0x0a, 0x16, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, + 0x73, 0x12, 0x30, 0x0a, 0x12, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x64, + 0x6f, 0x63, 0x73, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, + 0x01, 0x52, 0x10, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x44, 0x6f, 0x63, 0x73, + 0x55, 0x72, 0x69, 0x12, 0x48, 0x0a, 0x0c, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x24, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x62, + 0x72, 0x61, 0x72, 0x79, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x0c, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x93, 0x05, + 0x0a, 0x15, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x53, + 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x12, 0x3a, 0x0a, 0x0c, 0x6c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x5f, 0x73, 0x74, 0x61, 0x67, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x53, 0x74, 0x61, 0x67, 0x65, + 0x52, 0x0b, 0x6c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x53, 0x74, 0x61, 0x67, 0x65, 0x12, 0x2c, 0x0a, + 0x12, 0x72, 0x65, 0x73, 0x74, 0x5f, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x5f, 0x65, 0x6e, + 0x75, 0x6d, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x72, 0x65, 0x73, 0x74, 0x4e, + 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x45, 0x6e, 0x75, 0x6d, 0x73, 0x12, 0x3d, 0x0a, 0x0d, 0x6a, + 0x61, 0x76, 0x61, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x15, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x4a, 0x61, 0x76, 0x61, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0c, 0x6a, 0x61, + 0x76, 0x61, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3a, 0x0a, 0x0c, 0x63, 0x70, + 0x70, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x70, + 0x70, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0b, 0x63, 0x70, 0x70, 0x53, 0x65, + 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3a, 0x0a, 0x0c, 0x70, 0x68, 0x70, 0x5f, 0x73, 0x65, + 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x50, 0x68, 0x70, 0x53, 0x65, 0x74, + 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0b, 0x70, 0x68, 0x70, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, + 0x67, 0x73, 0x12, 0x43, 0x0a, 0x0f, 0x70, 0x79, 0x74, 0x68, 0x6f, 0x6e, 0x5f, 0x73, 0x65, 0x74, + 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x50, 0x79, 0x74, 0x68, 0x6f, 0x6e, 0x53, + 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0e, 0x70, 0x79, 0x74, 0x68, 0x6f, 0x6e, 0x53, + 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3d, 0x0a, 0x0d, 0x6e, 0x6f, 0x64, 0x65, 0x5f, + 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4e, 0x6f, 0x64, 0x65, + 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0c, 0x6e, 0x6f, 0x64, 0x65, 0x53, 0x65, + 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x43, 0x0a, 0x0f, 0x64, 0x6f, 0x74, 0x6e, 0x65, 0x74, + 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x6f, 0x74, + 0x6e, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0e, 0x64, 0x6f, 0x74, + 0x6e, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3d, 0x0a, 0x0d, 0x72, + 0x75, 0x62, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x1b, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x52, 0x75, 0x62, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0c, 0x72, 0x75, + 0x62, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x37, 0x0a, 0x0b, 0x67, 0x6f, + 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x6f, 0x53, + 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0a, 0x67, 0x6f, 0x53, 0x65, 0x74, 0x74, 0x69, + 0x6e, 0x67, 0x73, 0x22, 0xab, 0x04, 0x0a, 0x0a, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x69, + 0x6e, 0x67, 0x12, 0x43, 0x0a, 0x0f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x5f, 0x73, 0x65, 0x74, + 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x53, + 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0e, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x53, + 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x6e, 0x65, 0x77, 0x5f, 0x69, + 0x73, 0x73, 0x75, 0x65, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x65, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, + 0x6e, 0x65, 0x77, 0x49, 0x73, 0x73, 0x75, 0x65, 0x55, 0x72, 0x69, 0x12, 0x2b, 0x0a, 0x11, 0x64, + 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x75, 0x72, 0x69, + 0x18, 0x66, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x72, 0x69, 0x12, 0x24, 0x0a, 0x0e, 0x61, 0x70, 0x69, 0x5f, + 0x73, 0x68, 0x6f, 0x72, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x67, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0c, 0x61, 0x70, 0x69, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x21, + 0x0a, 0x0c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x5f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x68, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x4c, 0x61, 0x62, 0x65, + 0x6c, 0x12, 0x34, 0x0a, 0x16, 0x63, 0x6f, 0x64, 0x65, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x5f, 0x74, 0x65, 0x61, 0x6d, 0x73, 0x18, 0x69, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x14, 0x63, 0x6f, 0x64, 0x65, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x47, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x54, 0x65, 0x61, 0x6d, 0x73, 0x12, 0x24, 0x0a, 0x0e, 0x64, 0x6f, 0x63, 0x5f, 0x74, + 0x61, 0x67, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x6a, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0c, 0x64, 0x6f, 0x63, 0x54, 0x61, 0x67, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, 0x49, 0x0a, + 0x0c, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x6b, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x25, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, + 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x4f, 0x72, + 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x6f, 0x72, 0x67, 0x61, + 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4c, 0x0a, 0x10, 0x6c, 0x69, 0x62, 0x72, + 0x61, 0x72, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x6d, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x53, 0x65, 0x74, + 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0f, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x53, 0x65, + 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x49, 0x0a, 0x21, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x5f, + 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, + 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x6e, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x1e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, + 0x65, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x72, + 0x69, 0x22, 0x9a, 0x02, 0x0a, 0x0c, 0x4a, 0x61, 0x76, 0x61, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, + 0x67, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x5f, 0x70, 0x61, + 0x63, 0x6b, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6c, 0x69, 0x62, + 0x72, 0x61, 0x72, 0x79, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x12, 0x5f, 0x0a, 0x13, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4a, 0x61, 0x76, 0x61, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, + 0x67, 0x73, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x4e, + 0x61, 0x6d, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x11, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x3a, 0x0a, 0x06, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, + 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x1a, 0x44, 0x0a, 0x16, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x49, + 0x0a, 0x0b, 0x43, 0x70, 0x70, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3a, 0x0a, + 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, + 0x73, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x22, 0x49, 0x0a, 0x0b, 0x50, 0x68, 0x70, + 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3a, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4c, 0x61, 0x6e, 0x67, + 0x75, 0x61, 0x67, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x06, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x22, 0x4c, 0x0a, 0x0e, 0x50, 0x79, 0x74, 0x68, 0x6f, 0x6e, 0x53, 0x65, + 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3a, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, + 0x67, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x22, 0x4a, 0x0a, 0x0c, 0x4e, 0x6f, 0x64, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, + 0x67, 0x73, 0x12, 0x3a, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x53, 0x65, + 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x22, 0xae, + 0x04, 0x0a, 0x0e, 0x44, 0x6f, 0x74, 0x6e, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, + 0x73, 0x12, 0x3a, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x53, 0x65, 0x74, + 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x12, 0x5a, 0x0a, + 0x10, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x6f, 0x74, 0x6e, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, + 0x6e, 0x67, 0x73, 0x2e, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0f, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, + 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x5d, 0x0a, 0x11, 0x72, 0x65, 0x6e, + 0x61, 0x6d, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x03, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x44, 0x6f, 0x74, 0x6e, 0x65, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, + 0x2e, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x10, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x52, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x69, 0x67, 0x6e, 0x6f, + 0x72, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x04, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x10, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x38, 0x0a, 0x18, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x64, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, + 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x16, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x64, 0x4e, + 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x12, + 0x35, 0x0a, 0x16, 0x68, 0x61, 0x6e, 0x64, 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x5f, 0x73, + 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x15, 0x68, 0x61, 0x6e, 0x64, 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x53, 0x69, 0x67, 0x6e, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x1a, 0x42, 0x0a, 0x14, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, + 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x43, 0x0a, 0x15, 0x52, 0x65, + 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, + 0x4a, 0x0a, 0x0c, 0x52, 0x75, 0x62, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, + 0x3a, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, + 0x6e, 0x67, 0x73, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x22, 0x48, 0x0a, 0x0a, 0x47, + 0x6f, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3a, 0x0a, 0x06, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x4c, 0x61, 0x6e, + 0x67, 0x75, 0x61, 0x67, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x06, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x22, 0x8e, 0x03, 0x0a, 0x0e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, + 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x6c, 0x65, + 0x63, 0x74, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, 0x6c, 0x65, + 0x63, 0x74, 0x6f, 0x72, 0x12, 0x49, 0x0a, 0x0c, 0x6c, 0x6f, 0x6e, 0x67, 0x5f, 0x72, 0x75, 0x6e, + 0x6e, 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x53, 0x65, + 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x4c, 0x6f, 0x6e, 0x67, 0x52, 0x75, 0x6e, 0x6e, 0x69, + 0x6e, 0x67, 0x52, 0x0b, 0x6c, 0x6f, 0x6e, 0x67, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x1a, + 0x94, 0x02, 0x0a, 0x0b, 0x4c, 0x6f, 0x6e, 0x67, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x12, + 0x47, 0x0a, 0x12, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x70, 0x6f, 0x6c, 0x6c, 0x5f, + 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x10, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x50, + 0x6f, 0x6c, 0x6c, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x32, 0x0a, 0x15, 0x70, 0x6f, 0x6c, 0x6c, + 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x69, 0x65, + 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x02, 0x52, 0x13, 0x70, 0x6f, 0x6c, 0x6c, 0x44, 0x65, 0x6c, + 0x61, 0x79, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x12, 0x3f, 0x0a, 0x0e, + 0x6d, 0x61, 0x78, 0x5f, 0x70, 0x6f, 0x6c, 0x6c, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x0c, 0x6d, 0x61, 0x78, 0x50, 0x6f, 0x6c, 0x6c, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x47, 0x0a, + 0x12, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x70, 0x6f, 0x6c, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, + 0x6f, 0x75, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x10, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x50, 0x6f, 0x6c, 0x6c, 0x54, + 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x2a, 0x79, 0x0a, 0x19, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x2b, 0x0a, 0x27, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x4c, 0x49, + 0x42, 0x52, 0x41, 0x52, 0x59, 0x5f, 0x4f, 0x52, 0x47, 0x41, 0x4e, 0x49, 0x5a, 0x41, 0x54, 0x49, + 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, + 0x12, 0x09, 0x0a, 0x05, 0x43, 0x4c, 0x4f, 0x55, 0x44, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x41, + 0x44, 0x53, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x50, 0x48, 0x4f, 0x54, 0x4f, 0x53, 0x10, 0x03, + 0x12, 0x0f, 0x0a, 0x0b, 0x53, 0x54, 0x52, 0x45, 0x45, 0x54, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x10, + 0x04, 0x2a, 0x67, 0x0a, 0x18, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x62, 0x72, 0x61, + 0x72, 0x79, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2a, 0x0a, + 0x26, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x4c, 0x49, 0x42, 0x52, 0x41, 0x52, 0x59, 0x5f, + 0x44, 0x45, 0x53, 0x54, 0x49, 0x4e, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, + 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x47, 0x49, 0x54, + 0x48, 0x55, 0x42, 0x10, 0x0a, 0x12, 0x13, 0x0a, 0x0f, 0x50, 0x41, 0x43, 0x4b, 0x41, 0x47, 0x45, + 0x5f, 0x4d, 0x41, 0x4e, 0x41, 0x47, 0x45, 0x52, 0x10, 0x14, 0x3a, 0x4a, 0x0a, 0x10, 0x6d, 0x65, + 0x74, 0x68, 0x6f, 0x64, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x1e, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x9b, + 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x53, 0x69, 0x67, + 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x3a, 0x43, 0x0a, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, + 0x74, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x12, 0x1f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x99, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, + 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x43, 0x0a, 0x0c, 0x6f, + 0x61, 0x75, 0x74, 0x68, 0x5f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x12, 0x1f, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x9a, 0x08, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x73, + 0x42, 0x69, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, + 0x70, 0x69, 0x42, 0x0b, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, + 0x01, 0x5a, 0x41, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, + 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x65, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, + 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0xa2, 0x02, 0x04, 0x47, 0x41, 0x50, 0x49, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } +var ( + file_google_api_client_proto_rawDescOnce sync.Once + file_google_api_client_proto_rawDescData = file_google_api_client_proto_rawDesc +) + +func file_google_api_client_proto_rawDescGZIP() []byte { + file_google_api_client_proto_rawDescOnce.Do(func() { + file_google_api_client_proto_rawDescData = protoimpl.X.CompressGZIP(file_google_api_client_proto_rawDescData) + }) + return file_google_api_client_proto_rawDescData +} + +var file_google_api_client_proto_enumTypes = make([]protoimpl.EnumInfo, 2) +var file_google_api_client_proto_msgTypes = make([]protoimpl.MessageInfo, 16) var file_google_api_client_proto_goTypes = []interface{}{ - (*descriptorpb.MethodOptions)(nil), // 0: google.protobuf.MethodOptions - (*descriptorpb.ServiceOptions)(nil), // 1: google.protobuf.ServiceOptions + (ClientLibraryOrganization)(0), // 0: google.api.ClientLibraryOrganization + (ClientLibraryDestination)(0), // 1: google.api.ClientLibraryDestination + (*CommonLanguageSettings)(nil), // 2: google.api.CommonLanguageSettings + (*ClientLibrarySettings)(nil), // 3: google.api.ClientLibrarySettings + (*Publishing)(nil), // 4: google.api.Publishing + (*JavaSettings)(nil), // 5: google.api.JavaSettings + (*CppSettings)(nil), // 6: google.api.CppSettings + (*PhpSettings)(nil), // 7: google.api.PhpSettings + (*PythonSettings)(nil), // 8: google.api.PythonSettings + (*NodeSettings)(nil), // 9: google.api.NodeSettings + (*DotnetSettings)(nil), // 10: google.api.DotnetSettings + (*RubySettings)(nil), // 11: google.api.RubySettings + (*GoSettings)(nil), // 12: google.api.GoSettings + (*MethodSettings)(nil), // 13: google.api.MethodSettings + nil, // 14: google.api.JavaSettings.ServiceClassNamesEntry + nil, // 15: google.api.DotnetSettings.RenamedServicesEntry + nil, // 16: google.api.DotnetSettings.RenamedResourcesEntry + (*MethodSettings_LongRunning)(nil), // 17: google.api.MethodSettings.LongRunning + (api.LaunchStage)(0), // 18: google.api.LaunchStage + (*durationpb.Duration)(nil), // 19: google.protobuf.Duration + (*descriptorpb.MethodOptions)(nil), // 20: google.protobuf.MethodOptions + (*descriptorpb.ServiceOptions)(nil), // 21: google.protobuf.ServiceOptions } var file_google_api_client_proto_depIdxs = []int32{ - 0, // 0: google.api.method_signature:extendee -> google.protobuf.MethodOptions - 1, // 1: google.api.default_host:extendee -> google.protobuf.ServiceOptions - 1, // 2: google.api.oauth_scopes:extendee -> google.protobuf.ServiceOptions - 3, // [3:3] is the sub-list for method output_type - 3, // [3:3] is the sub-list for method input_type - 3, // [3:3] is the sub-list for extension type_name - 0, // [0:3] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name + 1, // 0: google.api.CommonLanguageSettings.destinations:type_name -> google.api.ClientLibraryDestination + 18, // 1: google.api.ClientLibrarySettings.launch_stage:type_name -> google.api.LaunchStage + 5, // 2: google.api.ClientLibrarySettings.java_settings:type_name -> google.api.JavaSettings + 6, // 3: google.api.ClientLibrarySettings.cpp_settings:type_name -> google.api.CppSettings + 7, // 4: google.api.ClientLibrarySettings.php_settings:type_name -> google.api.PhpSettings + 8, // 5: google.api.ClientLibrarySettings.python_settings:type_name -> google.api.PythonSettings + 9, // 6: google.api.ClientLibrarySettings.node_settings:type_name -> google.api.NodeSettings + 10, // 7: google.api.ClientLibrarySettings.dotnet_settings:type_name -> google.api.DotnetSettings + 11, // 8: google.api.ClientLibrarySettings.ruby_settings:type_name -> google.api.RubySettings + 12, // 9: google.api.ClientLibrarySettings.go_settings:type_name -> google.api.GoSettings + 13, // 10: google.api.Publishing.method_settings:type_name -> google.api.MethodSettings + 0, // 11: google.api.Publishing.organization:type_name -> google.api.ClientLibraryOrganization + 3, // 12: google.api.Publishing.library_settings:type_name -> google.api.ClientLibrarySettings + 14, // 13: google.api.JavaSettings.service_class_names:type_name -> google.api.JavaSettings.ServiceClassNamesEntry + 2, // 14: google.api.JavaSettings.common:type_name -> google.api.CommonLanguageSettings + 2, // 15: google.api.CppSettings.common:type_name -> google.api.CommonLanguageSettings + 2, // 16: google.api.PhpSettings.common:type_name -> google.api.CommonLanguageSettings + 2, // 17: google.api.PythonSettings.common:type_name -> google.api.CommonLanguageSettings + 2, // 18: google.api.NodeSettings.common:type_name -> google.api.CommonLanguageSettings + 2, // 19: google.api.DotnetSettings.common:type_name -> google.api.CommonLanguageSettings + 15, // 20: google.api.DotnetSettings.renamed_services:type_name -> google.api.DotnetSettings.RenamedServicesEntry + 16, // 21: google.api.DotnetSettings.renamed_resources:type_name -> google.api.DotnetSettings.RenamedResourcesEntry + 2, // 22: google.api.RubySettings.common:type_name -> google.api.CommonLanguageSettings + 2, // 23: google.api.GoSettings.common:type_name -> google.api.CommonLanguageSettings + 17, // 24: google.api.MethodSettings.long_running:type_name -> google.api.MethodSettings.LongRunning + 19, // 25: google.api.MethodSettings.LongRunning.initial_poll_delay:type_name -> google.protobuf.Duration + 19, // 26: google.api.MethodSettings.LongRunning.max_poll_delay:type_name -> google.protobuf.Duration + 19, // 27: google.api.MethodSettings.LongRunning.total_poll_timeout:type_name -> google.protobuf.Duration + 20, // 28: google.api.method_signature:extendee -> google.protobuf.MethodOptions + 21, // 29: google.api.default_host:extendee -> google.protobuf.ServiceOptions + 21, // 30: google.api.oauth_scopes:extendee -> google.protobuf.ServiceOptions + 31, // [31:31] is the sub-list for method output_type + 31, // [31:31] is the sub-list for method input_type + 31, // [31:31] is the sub-list for extension type_name + 28, // [28:31] is the sub-list for extension extendee + 0, // [0:28] is the sub-list for field type_name } func init() { file_google_api_client_proto_init() } @@ -198,18 +1585,178 @@ func file_google_api_client_proto_init() { if File_google_api_client_proto != nil { return } + if !protoimpl.UnsafeEnabled { + file_google_api_client_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CommonLanguageSettings); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_api_client_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ClientLibrarySettings); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_api_client_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Publishing); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_api_client_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*JavaSettings); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_api_client_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CppSettings); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_api_client_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PhpSettings); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_api_client_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PythonSettings); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_api_client_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NodeSettings); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_api_client_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DotnetSettings); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_api_client_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RubySettings); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_api_client_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GoSettings); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_api_client_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MethodSettings); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_api_client_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MethodSettings_LongRunning); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_google_api_client_proto_rawDesc, - NumEnums: 0, - NumMessages: 0, + NumEnums: 2, + NumMessages: 16, NumExtensions: 3, NumServices: 0, }, GoTypes: file_google_api_client_proto_goTypes, DependencyIndexes: file_google_api_client_proto_depIdxs, + EnumInfos: file_google_api_client_proto_enumTypes, + MessageInfos: file_google_api_client_proto_msgTypes, ExtensionInfos: file_google_api_client_proto_extTypes, }.Build() File_google_api_client_proto = out.File diff --git a/vendor/google.golang.org/genproto/googleapis/api/annotations/field_behavior.pb.go b/vendor/google.golang.org/genproto/googleapis/api/annotations/field_behavior.pb.go index 91ad80ecc8b..dbe2e2d0c65 100644 --- a/vendor/google.golang.org/genproto/googleapis/api/annotations/field_behavior.pb.go +++ b/vendor/google.golang.org/genproto/googleapis/api/annotations/field_behavior.pb.go @@ -1,4 +1,4 @@ -// Copyright 2020 Google LLC +// Copyright 2023 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -14,8 +14,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.25.0 -// protoc v3.13.0 +// protoc-gen-go v1.26.0 +// protoc v3.21.9 // source: google/api/field_behavior.proto package annotations @@ -24,7 +24,6 @@ import ( reflect "reflect" sync "sync" - proto "github.com/golang/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" descriptorpb "google.golang.org/protobuf/types/descriptorpb" @@ -37,10 +36,6 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - // An indicator of the behavior of a given field (for example, that a field // is required in requests, or given as output but ignored as input). // This **does not** change the behavior in protocol buffers itself; it only @@ -75,9 +70,14 @@ const ( FieldBehavior_IMMUTABLE FieldBehavior = 5 // Denotes that a (repeated) field is an unordered list. // This indicates that the service may provide the elements of the list - // in any arbitrary order, rather than the order the user originally + // in any arbitrary order, rather than the order the user originally // provided. Additionally, the list's order may or may not be stable. FieldBehavior_UNORDERED_LIST FieldBehavior = 6 + // Denotes that this field returns a non-empty default value if not set. + // This indicates that if the user provides the empty value in a request, + // a non-empty value will be returned. The user will not be aware of what + // non-empty value to expect. + FieldBehavior_NON_EMPTY_DEFAULT FieldBehavior = 7 ) // Enum value maps for FieldBehavior. @@ -90,6 +90,7 @@ var ( 4: "INPUT_ONLY", 5: "IMMUTABLE", 6: "UNORDERED_LIST", + 7: "NON_EMPTY_DEFAULT", } FieldBehavior_value = map[string]int32{ "FIELD_BEHAVIOR_UNSPECIFIED": 0, @@ -99,6 +100,7 @@ var ( "INPUT_ONLY": 4, "IMMUTABLE": 5, "UNORDERED_LIST": 6, + "NON_EMPTY_DEFAULT": 7, } ) @@ -147,13 +149,13 @@ var ( // // Examples: // - // string name = 1 [(google.api.field_behavior) = REQUIRED]; - // State state = 1 [(google.api.field_behavior) = OUTPUT_ONLY]; - // google.protobuf.Duration ttl = 1 - // [(google.api.field_behavior) = INPUT_ONLY]; - // google.protobuf.Timestamp expire_time = 1 - // [(google.api.field_behavior) = OUTPUT_ONLY, - // (google.api.field_behavior) = IMMUTABLE]; + // string name = 1 [(google.api.field_behavior) = REQUIRED]; + // State state = 1 [(google.api.field_behavior) = OUTPUT_ONLY]; + // google.protobuf.Duration ttl = 1 + // [(google.api.field_behavior) = INPUT_ONLY]; + // google.protobuf.Timestamp expire_time = 1 + // [(google.api.field_behavior) = OUTPUT_ONLY, + // (google.api.field_behavior) = IMMUTABLE]; // // repeated google.api.FieldBehavior field_behavior = 1052; E_FieldBehavior = &file_google_api_field_behavior_proto_extTypes[0] @@ -167,7 +169,7 @@ var file_google_api_field_behavior_proto_rawDesc = []byte{ 0x6f, 0x12, 0x0a, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2a, - 0x8f, 0x01, 0x0a, 0x0d, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x42, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, + 0xa6, 0x01, 0x0a, 0x0d, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x42, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x12, 0x1e, 0x0a, 0x1a, 0x46, 0x49, 0x45, 0x4c, 0x44, 0x5f, 0x42, 0x45, 0x48, 0x41, 0x56, 0x49, 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x4f, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x41, 0x4c, 0x10, 0x01, 0x12, @@ -176,20 +178,22 @@ var file_google_api_field_behavior_proto_rawDesc = []byte{ 0x0a, 0x0a, 0x49, 0x4e, 0x50, 0x55, 0x54, 0x5f, 0x4f, 0x4e, 0x4c, 0x59, 0x10, 0x04, 0x12, 0x0d, 0x0a, 0x09, 0x49, 0x4d, 0x4d, 0x55, 0x54, 0x41, 0x42, 0x4c, 0x45, 0x10, 0x05, 0x12, 0x12, 0x0a, 0x0e, 0x55, 0x4e, 0x4f, 0x52, 0x44, 0x45, 0x52, 0x45, 0x44, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x10, - 0x06, 0x3a, 0x60, 0x0a, 0x0e, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x62, 0x65, 0x68, 0x61, 0x76, - 0x69, 0x6f, 0x72, 0x12, 0x1d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x18, 0x9c, 0x08, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x42, 0x65, 0x68, 0x61, - 0x76, 0x69, 0x6f, 0x72, 0x52, 0x0d, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x42, 0x65, 0x68, 0x61, 0x76, - 0x69, 0x6f, 0x72, 0x42, 0x70, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x61, 0x70, 0x69, 0x42, 0x12, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x42, 0x65, 0x68, 0x61, - 0x76, 0x69, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x41, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x67, - 0x65, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, - 0x69, 0x73, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x3b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0xa2, 0x02, - 0x04, 0x47, 0x41, 0x50, 0x49, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x06, 0x12, 0x15, 0x0a, 0x11, 0x4e, 0x4f, 0x4e, 0x5f, 0x45, 0x4d, 0x50, 0x54, 0x59, 0x5f, 0x44, + 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x07, 0x3a, 0x60, 0x0a, 0x0e, 0x66, 0x69, 0x65, 0x6c, + 0x64, 0x5f, 0x62, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x12, 0x1d, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, + 0x6c, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x9c, 0x08, 0x20, 0x03, 0x28, 0x0e, + 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x46, 0x69, + 0x65, 0x6c, 0x64, 0x42, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x52, 0x0d, 0x66, 0x69, 0x65, + 0x6c, 0x64, 0x42, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x42, 0x70, 0x0a, 0x0e, 0x63, 0x6f, + 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x42, 0x12, 0x46, 0x69, + 0x65, 0x6c, 0x64, 0x42, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x50, 0x01, 0x5a, 0x41, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, + 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x65, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, + 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0xa2, 0x02, 0x04, 0x47, 0x41, 0x50, 0x49, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/vendor/google.golang.org/genproto/googleapis/api/annotations/http.pb.go b/vendor/google.golang.org/genproto/googleapis/api/annotations/http.pb.go index f36d981ced0..8a0e1c345b9 100644 --- a/vendor/google.golang.org/genproto/googleapis/api/annotations/http.pb.go +++ b/vendor/google.golang.org/genproto/googleapis/api/annotations/http.pb.go @@ -1,4 +1,4 @@ -// Copyright 2020 Google LLC +// Copyright 2023 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -14,8 +14,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.25.0 -// protoc v3.13.0 +// protoc-gen-go v1.26.0 +// protoc v3.21.9 // source: google/api/http.proto package annotations @@ -24,7 +24,6 @@ import ( reflect "reflect" sync "sync" - proto "github.com/golang/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" ) @@ -36,10 +35,6 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - // Defines the HTTP configuration for an API service. It contains a list of // [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method // to one or more HTTP REST API methods. @@ -132,19 +127,19 @@ func (x *Http) GetFullyDecodeReservedExpansion() bool { // // Example: // -// service Messaging { -// rpc GetMessage(GetMessageRequest) returns (Message) { -// option (google.api.http) = { -// get: "/v1/{name=messages/*}" -// }; -// } -// } -// message GetMessageRequest { -// string name = 1; // Mapped to URL path. -// } -// message Message { -// string text = 1; // The resource content. -// } +// service Messaging { +// rpc GetMessage(GetMessageRequest) returns (Message) { +// option (google.api.http) = { +// get: "/v1/{name=messages/*}" +// }; +// } +// } +// message GetMessageRequest { +// string name = 1; // Mapped to URL path. +// } +// message Message { +// string text = 1; // The resource content. +// } // // This enables an HTTP REST to gRPC mapping as below: // @@ -156,21 +151,21 @@ func (x *Http) GetFullyDecodeReservedExpansion() bool { // automatically become HTTP query parameters if there is no HTTP request body. // For example: // -// service Messaging { -// rpc GetMessage(GetMessageRequest) returns (Message) { -// option (google.api.http) = { -// get:"/v1/messages/{message_id}" -// }; -// } -// } -// message GetMessageRequest { -// message SubMessage { -// string subfield = 1; -// } -// string message_id = 1; // Mapped to URL path. -// int64 revision = 2; // Mapped to URL query parameter `revision`. -// SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`. -// } +// service Messaging { +// rpc GetMessage(GetMessageRequest) returns (Message) { +// option (google.api.http) = { +// get:"/v1/messages/{message_id}" +// }; +// } +// } +// message GetMessageRequest { +// message SubMessage { +// string subfield = 1; +// } +// string message_id = 1; // Mapped to URL path. +// int64 revision = 2; // Mapped to URL query parameter `revision`. +// SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`. +// } // // This enables a HTTP JSON to RPC mapping as below: // @@ -191,18 +186,18 @@ func (x *Http) GetFullyDecodeReservedExpansion() bool { // specifies the mapping. Consider a REST update method on the // message resource collection: // -// service Messaging { -// rpc UpdateMessage(UpdateMessageRequest) returns (Message) { -// option (google.api.http) = { -// patch: "/v1/messages/{message_id}" -// body: "message" -// }; -// } -// } -// message UpdateMessageRequest { -// string message_id = 1; // mapped to the URL -// Message message = 2; // mapped to the body -// } +// service Messaging { +// rpc UpdateMessage(UpdateMessageRequest) returns (Message) { +// option (google.api.http) = { +// patch: "/v1/messages/{message_id}" +// body: "message" +// }; +// } +// } +// message UpdateMessageRequest { +// string message_id = 1; // mapped to the URL +// Message message = 2; // mapped to the body +// } // // The following HTTP JSON to RPC mapping is enabled, where the // representation of the JSON in the request body is determined by @@ -218,19 +213,18 @@ func (x *Http) GetFullyDecodeReservedExpansion() bool { // request body. This enables the following alternative definition of // the update method: // -// service Messaging { -// rpc UpdateMessage(Message) returns (Message) { -// option (google.api.http) = { -// patch: "/v1/messages/{message_id}" -// body: "*" -// }; -// } -// } -// message Message { -// string message_id = 1; -// string text = 2; -// } -// +// service Messaging { +// rpc UpdateMessage(Message) returns (Message) { +// option (google.api.http) = { +// patch: "/v1/messages/{message_id}" +// body: "*" +// }; +// } +// } +// message Message { +// string message_id = 1; +// string text = 2; +// } // // The following HTTP JSON to RPC mapping is enabled: // @@ -248,20 +242,20 @@ func (x *Http) GetFullyDecodeReservedExpansion() bool { // It is possible to define multiple HTTP methods for one RPC by using // the `additional_bindings` option. Example: // -// service Messaging { -// rpc GetMessage(GetMessageRequest) returns (Message) { -// option (google.api.http) = { -// get: "/v1/messages/{message_id}" -// additional_bindings { -// get: "/v1/users/{user_id}/messages/{message_id}" -// } -// }; -// } -// } -// message GetMessageRequest { -// string message_id = 1; -// string user_id = 2; -// } +// service Messaging { +// rpc GetMessage(GetMessageRequest) returns (Message) { +// option (google.api.http) = { +// get: "/v1/messages/{message_id}" +// additional_bindings { +// get: "/v1/users/{user_id}/messages/{message_id}" +// } +// }; +// } +// } +// message GetMessageRequest { +// string message_id = 1; +// string user_id = 2; +// } // // This enables the following two alternative HTTP JSON to RPC mappings: // @@ -273,28 +267,31 @@ func (x *Http) GetFullyDecodeReservedExpansion() bool { // // ## Rules for HTTP mapping // -// 1. Leaf request fields (recursive expansion nested messages in the request -// message) are classified into three categories: -// - Fields referred by the path template. They are passed via the URL path. -// - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP -// request body. -// - All other fields are passed via the URL query parameters, and the -// parameter name is the field path in the request message. A repeated -// field can be represented as multiple query parameters under the same -// name. -// 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields +// 1. Leaf request fields (recursive expansion nested messages in the request +// message) are classified into three categories: +// - Fields referred by the path template. They are passed via the URL path. +// - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They +// are passed via the HTTP +// request body. +// - All other fields are passed via the URL query parameters, and the +// parameter name is the field path in the request message. A repeated +// field can be represented as multiple query parameters under the same +// name. +// 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL +// query parameter, all fields // are passed via URL path and HTTP request body. -// 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all +// 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP +// request body, all // fields are passed via URL path and URL query parameters. // // ### Path template syntax // -// Template = "/" Segments [ Verb ] ; -// Segments = Segment { "/" Segment } ; -// Segment = "*" | "**" | LITERAL | Variable ; -// Variable = "{" FieldPath [ "=" Segments ] "}" ; -// FieldPath = IDENT { "." IDENT } ; -// Verb = ":" LITERAL ; +// Template = "/" Segments [ Verb ] ; +// Segments = Segment { "/" Segment } ; +// Segment = "*" | "**" | LITERAL | Variable ; +// Variable = "{" FieldPath [ "=" Segments ] "}" ; +// FieldPath = IDENT { "." IDENT } ; +// Verb = ":" LITERAL ; // // The syntax `*` matches a single URL path segment. The syntax `**` matches // zero or more URL path segments, which must be the last part of the URL path @@ -343,11 +340,11 @@ func (x *Http) GetFullyDecodeReservedExpansion() bool { // // Example: // -// http: -// rules: -// # Selects a gRPC method and applies HttpRule to it. -// - selector: example.v1.Messaging.GetMessage -// get: /v1/messages/{message_id}/{sub.subfield} +// http: +// rules: +// # Selects a gRPC method and applies HttpRule to it. +// - selector: example.v1.Messaging.GetMessage +// get: /v1/messages/{message_id}/{sub.subfield} // // ## Special notes // @@ -383,13 +380,15 @@ type HttpRule struct { // Selects a method to which this rule applies. // - // Refer to [selector][google.api.DocumentationRule.selector] for syntax details. + // Refer to [selector][google.api.DocumentationRule.selector] for syntax + // details. Selector string `protobuf:"bytes,1,opt,name=selector,proto3" json:"selector,omitempty"` // Determines the URL pattern is matched by this rules. This pattern can be // used with any of the {get|put|post|delete|patch} methods. A custom method // can be defined using the 'custom' field. // // Types that are assignable to Pattern: + // // *HttpRule_Get // *HttpRule_Put // *HttpRule_Post diff --git a/vendor/google.golang.org/genproto/googleapis/api/annotations/resource.pb.go b/vendor/google.golang.org/genproto/googleapis/api/annotations/resource.pb.go index 8a422a66b36..bbcc12d29c8 100644 --- a/vendor/google.golang.org/genproto/googleapis/api/annotations/resource.pb.go +++ b/vendor/google.golang.org/genproto/googleapis/api/annotations/resource.pb.go @@ -1,4 +1,4 @@ -// Copyright 2020 Google LLC +// Copyright 2023 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -14,8 +14,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.25.0 -// protoc v3.13.0 +// protoc-gen-go v1.26.0 +// protoc v3.21.9 // source: google/api/resource.proto package annotations @@ -24,7 +24,6 @@ import ( reflect "reflect" sync "sync" - proto "github.com/golang/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" descriptorpb "google.golang.org/protobuf/types/descriptorpb" @@ -37,10 +36,6 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - // A description of the historical or future-looking state of the // resource pattern. type ResourceDescriptor_History int32 @@ -162,106 +157,45 @@ func (ResourceDescriptor_Style) EnumDescriptor() ([]byte, []int) { // // Example: // -// message Topic { -// // Indicates this message defines a resource schema. -// // Declares the resource type in the format of {service}/{kind}. -// // For Kubernetes resources, the format is {api group}/{kind}. -// option (google.api.resource) = { -// type: "pubsub.googleapis.com/Topic" -// name_descriptor: { -// pattern: "projects/{project}/topics/{topic}" -// parent_type: "cloudresourcemanager.googleapis.com/Project" -// parent_name_extractor: "projects/{project}" -// } -// }; -// } +// message Topic { +// // Indicates this message defines a resource schema. +// // Declares the resource type in the format of {service}/{kind}. +// // For Kubernetes resources, the format is {api group}/{kind}. +// option (google.api.resource) = { +// type: "pubsub.googleapis.com/Topic" +// pattern: "projects/{project}/topics/{topic}" +// }; +// } // // The ResourceDescriptor Yaml config will look like: // -// resources: -// - type: "pubsub.googleapis.com/Topic" -// name_descriptor: -// - pattern: "projects/{project}/topics/{topic}" -// parent_type: "cloudresourcemanager.googleapis.com/Project" -// parent_name_extractor: "projects/{project}" +// resources: +// - type: "pubsub.googleapis.com/Topic" +// pattern: "projects/{project}/topics/{topic}" // // Sometimes, resources have multiple patterns, typically because they can // live under multiple parents. // // Example: // -// message LogEntry { -// option (google.api.resource) = { -// type: "logging.googleapis.com/LogEntry" -// name_descriptor: { -// pattern: "projects/{project}/logs/{log}" -// parent_type: "cloudresourcemanager.googleapis.com/Project" -// parent_name_extractor: "projects/{project}" -// } -// name_descriptor: { -// pattern: "folders/{folder}/logs/{log}" -// parent_type: "cloudresourcemanager.googleapis.com/Folder" -// parent_name_extractor: "folders/{folder}" -// } -// name_descriptor: { -// pattern: "organizations/{organization}/logs/{log}" -// parent_type: "cloudresourcemanager.googleapis.com/Organization" -// parent_name_extractor: "organizations/{organization}" -// } -// name_descriptor: { -// pattern: "billingAccounts/{billing_account}/logs/{log}" -// parent_type: "billing.googleapis.com/BillingAccount" -// parent_name_extractor: "billingAccounts/{billing_account}" -// } -// }; -// } -// -// The ResourceDescriptor Yaml config will look like: -// -// resources: -// - type: 'logging.googleapis.com/LogEntry' -// name_descriptor: -// - pattern: "projects/{project}/logs/{log}" -// parent_type: "cloudresourcemanager.googleapis.com/Project" -// parent_name_extractor: "projects/{project}" -// - pattern: "folders/{folder}/logs/{log}" -// parent_type: "cloudresourcemanager.googleapis.com/Folder" -// parent_name_extractor: "folders/{folder}" -// - pattern: "organizations/{organization}/logs/{log}" -// parent_type: "cloudresourcemanager.googleapis.com/Organization" -// parent_name_extractor: "organizations/{organization}" -// - pattern: "billingAccounts/{billing_account}/logs/{log}" -// parent_type: "billing.googleapis.com/BillingAccount" -// parent_name_extractor: "billingAccounts/{billing_account}" -// -// For flexible resources, the resource name doesn't contain parent names, but -// the resource itself has parents for policy evaluation. -// -// Example: -// -// message Shelf { -// option (google.api.resource) = { -// type: "library.googleapis.com/Shelf" -// name_descriptor: { -// pattern: "shelves/{shelf}" -// parent_type: "cloudresourcemanager.googleapis.com/Project" -// } -// name_descriptor: { -// pattern: "shelves/{shelf}" -// parent_type: "cloudresourcemanager.googleapis.com/Folder" -// } -// }; -// } +// message LogEntry { +// option (google.api.resource) = { +// type: "logging.googleapis.com/LogEntry" +// pattern: "projects/{project}/logs/{log}" +// pattern: "folders/{folder}/logs/{log}" +// pattern: "organizations/{organization}/logs/{log}" +// pattern: "billingAccounts/{billing_account}/logs/{log}" +// }; +// } // // The ResourceDescriptor Yaml config will look like: // -// resources: -// - type: 'library.googleapis.com/Shelf' -// name_descriptor: -// - pattern: "shelves/{shelf}" -// parent_type: "cloudresourcemanager.googleapis.com/Project" -// - pattern: "shelves/{shelf}" -// parent_type: "cloudresourcemanager.googleapis.com/Folder" +// resources: +// - type: 'logging.googleapis.com/LogEntry' +// pattern: "projects/{project}/logs/{log}" +// pattern: "folders/{folder}/logs/{log}" +// pattern: "organizations/{organization}/logs/{log}" +// pattern: "billingAccounts/{billing_account}/logs/{log}" type ResourceDescriptor struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -284,14 +218,14 @@ type ResourceDescriptor struct { // The path pattern must follow the syntax, which aligns with HTTP binding // syntax: // - // Template = Segment { "/" Segment } ; - // Segment = LITERAL | Variable ; - // Variable = "{" LITERAL "}" ; + // Template = Segment { "/" Segment } ; + // Segment = LITERAL | Variable ; + // Variable = "{" LITERAL "}" ; // // Examples: // - // - "projects/{project}/topics/{topic}" - // - "projects/{project}/knowledgeBases/{knowledge_base}" + // - "projects/{project}/topics/{topic}" + // - "projects/{project}/knowledgeBases/{knowledge_base}" // // The components in braces correspond to the IDs for each resource in the // hierarchy. It is expected that, if multiple patterns are provided, @@ -305,17 +239,17 @@ type ResourceDescriptor struct { // // Example: // - // // The InspectTemplate message originally only supported resource - // // names with organization, and project was added later. - // message InspectTemplate { - // option (google.api.resource) = { - // type: "dlp.googleapis.com/InspectTemplate" - // pattern: - // "organizations/{organization}/inspectTemplates/{inspect_template}" - // pattern: "projects/{project}/inspectTemplates/{inspect_template}" - // history: ORIGINALLY_SINGLE_PATTERN - // }; - // } + // // The InspectTemplate message originally only supported resource + // // names with organization, and project was added later. + // message InspectTemplate { + // option (google.api.resource) = { + // type: "dlp.googleapis.com/InspectTemplate" + // pattern: + // "organizations/{organization}/inspectTemplates/{inspect_template}" + // pattern: "projects/{project}/inspectTemplates/{inspect_template}" + // history: ORIGINALLY_SINGLE_PATTERN + // }; + // } History ResourceDescriptor_History `protobuf:"varint,4,opt,name=history,proto3,enum=google.api.ResourceDescriptor_History" json:"history,omitempty"` // The plural name used in the resource name and permission names, such as // 'projects' for the resource name of 'projects/{project}' and the permission @@ -428,22 +362,22 @@ type ResourceReference struct { // // Example: // - // message Subscription { - // string topic = 2 [(google.api.resource_reference) = { - // type: "pubsub.googleapis.com/Topic" - // }]; - // } + // message Subscription { + // string topic = 2 [(google.api.resource_reference) = { + // type: "pubsub.googleapis.com/Topic" + // }]; + // } // // Occasionally, a field may reference an arbitrary resource. In this case, // APIs use the special value * in their resource reference. // // Example: // - // message GetIamPolicyRequest { - // string resource = 2 [(google.api.resource_reference) = { - // type: "*" - // }]; - // } + // message GetIamPolicyRequest { + // string resource = 2 [(google.api.resource_reference) = { + // type: "*" + // }]; + // } Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` // The resource type of a child collection that the annotated field // references. This is useful for annotating the `parent` field that @@ -451,11 +385,11 @@ type ResourceReference struct { // // Example: // - // message ListLogEntriesRequest { - // string parent = 1 [(google.api.resource_reference) = { - // child_type: "logging.googleapis.com/LogEntry" - // }; - // } + // message ListLogEntriesRequest { + // string parent = 1 [(google.api.resource_reference) = { + // child_type: "logging.googleapis.com/LogEntry" + // }; + // } ChildType string `protobuf:"bytes,2,opt,name=child_type,json=childType,proto3" json:"child_type,omitempty"` } diff --git a/vendor/google.golang.org/genproto/googleapis/api/annotations/routing.pb.go b/vendor/google.golang.org/genproto/googleapis/api/annotations/routing.pb.go new file mode 100644 index 00000000000..9a9ae04c29a --- /dev/null +++ b/vendor/google.golang.org/genproto/googleapis/api/annotations/routing.pb.go @@ -0,0 +1,693 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.26.0 +// protoc v3.21.9 +// source: google/api/routing.proto + +package annotations + +import ( + reflect "reflect" + sync "sync" + + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + descriptorpb "google.golang.org/protobuf/types/descriptorpb" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// Specifies the routing information that should be sent along with the request +// in the form of routing header. +// **NOTE:** All service configuration rules follow the "last one wins" order. +// +// The examples below will apply to an RPC which has the following request type: +// +// Message Definition: +// +// message Request { +// // The name of the Table +// // Values can be of the following formats: +// // - `projects//tables/` +// // - `projects//instances//tables/
` +// // - `region//zones//tables/
` +// string table_name = 1; +// +// // This value specifies routing for replication. +// // It can be in the following formats: +// // - `profiles/` +// // - a legacy `profile_id` that can be any string +// string app_profile_id = 2; +// } +// +// Example message: +// +// { +// table_name: projects/proj_foo/instances/instance_bar/table/table_baz, +// app_profile_id: profiles/prof_qux +// } +// +// The routing header consists of one or multiple key-value pairs. Every key +// and value must be percent-encoded, and joined together in the format of +// `key1=value1&key2=value2`. +// In the examples below I am skipping the percent-encoding for readablity. +// +// # Example 1 +// +// Extracting a field from the request to put into the routing header +// unchanged, with the key equal to the field name. +// +// annotation: +// +// option (google.api.routing) = { +// // Take the `app_profile_id`. +// routing_parameters { +// field: "app_profile_id" +// } +// }; +// +// result: +// +// x-goog-request-params: app_profile_id=profiles/prof_qux +// +// # Example 2 +// +// Extracting a field from the request to put into the routing header +// unchanged, with the key different from the field name. +// +// annotation: +// +// option (google.api.routing) = { +// // Take the `app_profile_id`, but name it `routing_id` in the header. +// routing_parameters { +// field: "app_profile_id" +// path_template: "{routing_id=**}" +// } +// }; +// +// result: +// +// x-goog-request-params: routing_id=profiles/prof_qux +// +// # Example 3 +// +// Extracting a field from the request to put into the routing +// header, while matching a path template syntax on the field's value. +// +// NB: it is more useful to send nothing than to send garbage for the purpose +// of dynamic routing, since garbage pollutes cache. Thus the matching. +// +// # Sub-example 3a +// +// The field matches the template. +// +// annotation: +// +// option (google.api.routing) = { +// // Take the `table_name`, if it's well-formed (with project-based +// // syntax). +// routing_parameters { +// field: "table_name" +// path_template: "{table_name=projects/*/instances/*/**}" +// } +// }; +// +// result: +// +// x-goog-request-params: +// table_name=projects/proj_foo/instances/instance_bar/table/table_baz +// +// # Sub-example 3b +// +// The field does not match the template. +// +// annotation: +// +// option (google.api.routing) = { +// // Take the `table_name`, if it's well-formed (with region-based +// // syntax). +// routing_parameters { +// field: "table_name" +// path_template: "{table_name=regions/*/zones/*/**}" +// } +// }; +// +// result: +// +// +// +// # Sub-example 3c +// +// Multiple alternative conflictingly named path templates are +// specified. The one that matches is used to construct the header. +// +// annotation: +// +// option (google.api.routing) = { +// // Take the `table_name`, if it's well-formed, whether +// // using the region- or projects-based syntax. +// +// routing_parameters { +// field: "table_name" +// path_template: "{table_name=regions/*/zones/*/**}" +// } +// routing_parameters { +// field: "table_name" +// path_template: "{table_name=projects/*/instances/*/**}" +// } +// }; +// +// result: +// +// x-goog-request-params: +// table_name=projects/proj_foo/instances/instance_bar/table/table_baz +// +// # Example 4 +// +// Extracting a single routing header key-value pair by matching a +// template syntax on (a part of) a single request field. +// +// annotation: +// +// option (google.api.routing) = { +// // Take just the project id from the `table_name` field. +// routing_parameters { +// field: "table_name" +// path_template: "{routing_id=projects/*}/**" +// } +// }; +// +// result: +// +// x-goog-request-params: routing_id=projects/proj_foo +// +// # Example 5 +// +// Extracting a single routing header key-value pair by matching +// several conflictingly named path templates on (parts of) a single request +// field. The last template to match "wins" the conflict. +// +// annotation: +// +// option (google.api.routing) = { +// // If the `table_name` does not have instances information, +// // take just the project id for routing. +// // Otherwise take project + instance. +// +// routing_parameters { +// field: "table_name" +// path_template: "{routing_id=projects/*}/**" +// } +// routing_parameters { +// field: "table_name" +// path_template: "{routing_id=projects/*/instances/*}/**" +// } +// }; +// +// result: +// +// x-goog-request-params: +// routing_id=projects/proj_foo/instances/instance_bar +// +// # Example 6 +// +// Extracting multiple routing header key-value pairs by matching +// several non-conflicting path templates on (parts of) a single request field. +// +// # Sub-example 6a +// +// Make the templates strict, so that if the `table_name` does not +// have an instance information, nothing is sent. +// +// annotation: +// +// option (google.api.routing) = { +// // The routing code needs two keys instead of one composite +// // but works only for the tables with the "project-instance" name +// // syntax. +// +// routing_parameters { +// field: "table_name" +// path_template: "{project_id=projects/*}/instances/*/**" +// } +// routing_parameters { +// field: "table_name" +// path_template: "projects/*/{instance_id=instances/*}/**" +// } +// }; +// +// result: +// +// x-goog-request-params: +// project_id=projects/proj_foo&instance_id=instances/instance_bar +// +// # Sub-example 6b +// +// Make the templates loose, so that if the `table_name` does not +// have an instance information, just the project id part is sent. +// +// annotation: +// +// option (google.api.routing) = { +// // The routing code wants two keys instead of one composite +// // but will work with just the `project_id` for tables without +// // an instance in the `table_name`. +// +// routing_parameters { +// field: "table_name" +// path_template: "{project_id=projects/*}/**" +// } +// routing_parameters { +// field: "table_name" +// path_template: "projects/*/{instance_id=instances/*}/**" +// } +// }; +// +// result (is the same as 6a for our example message because it has the instance +// information): +// +// x-goog-request-params: +// project_id=projects/proj_foo&instance_id=instances/instance_bar +// +// # Example 7 +// +// Extracting multiple routing header key-value pairs by matching +// several path templates on multiple request fields. +// +// NB: note that here there is no way to specify sending nothing if one of the +// fields does not match its template. E.g. if the `table_name` is in the wrong +// format, the `project_id` will not be sent, but the `routing_id` will be. +// The backend routing code has to be aware of that and be prepared to not +// receive a full complement of keys if it expects multiple. +// +// annotation: +// +// option (google.api.routing) = { +// // The routing needs both `project_id` and `routing_id` +// // (from the `app_profile_id` field) for routing. +// +// routing_parameters { +// field: "table_name" +// path_template: "{project_id=projects/*}/**" +// } +// routing_parameters { +// field: "app_profile_id" +// path_template: "{routing_id=**}" +// } +// }; +// +// result: +// +// x-goog-request-params: +// project_id=projects/proj_foo&routing_id=profiles/prof_qux +// +// # Example 8 +// +// Extracting a single routing header key-value pair by matching +// several conflictingly named path templates on several request fields. The +// last template to match "wins" the conflict. +// +// annotation: +// +// option (google.api.routing) = { +// // The `routing_id` can be a project id or a region id depending on +// // the table name format, but only if the `app_profile_id` is not set. +// // If `app_profile_id` is set it should be used instead. +// +// routing_parameters { +// field: "table_name" +// path_template: "{routing_id=projects/*}/**" +// } +// routing_parameters { +// field: "table_name" +// path_template: "{routing_id=regions/*}/**" +// } +// routing_parameters { +// field: "app_profile_id" +// path_template: "{routing_id=**}" +// } +// }; +// +// result: +// +// x-goog-request-params: routing_id=profiles/prof_qux +// +// # Example 9 +// +// Bringing it all together. +// +// annotation: +// +// option (google.api.routing) = { +// // For routing both `table_location` and a `routing_id` are needed. +// // +// // table_location can be either an instance id or a region+zone id. +// // +// // For `routing_id`, take the value of `app_profile_id` +// // - If it's in the format `profiles/`, send +// // just the `` part. +// // - If it's any other literal, send it as is. +// // If the `app_profile_id` is empty, and the `table_name` starts with +// // the project_id, send that instead. +// +// routing_parameters { +// field: "table_name" +// path_template: "projects/*/{table_location=instances/*}/tables/*" +// } +// routing_parameters { +// field: "table_name" +// path_template: "{table_location=regions/*/zones/*}/tables/*" +// } +// routing_parameters { +// field: "table_name" +// path_template: "{routing_id=projects/*}/**" +// } +// routing_parameters { +// field: "app_profile_id" +// path_template: "{routing_id=**}" +// } +// routing_parameters { +// field: "app_profile_id" +// path_template: "profiles/{routing_id=*}" +// } +// }; +// +// result: +// +// x-goog-request-params: +// table_location=instances/instance_bar&routing_id=prof_qux +type RoutingRule struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // A collection of Routing Parameter specifications. + // **NOTE:** If multiple Routing Parameters describe the same key + // (via the `path_template` field or via the `field` field when + // `path_template` is not provided), "last one wins" rule + // determines which Parameter gets used. + // See the examples for more details. + RoutingParameters []*RoutingParameter `protobuf:"bytes,2,rep,name=routing_parameters,json=routingParameters,proto3" json:"routing_parameters,omitempty"` +} + +func (x *RoutingRule) Reset() { + *x = RoutingRule{} + if protoimpl.UnsafeEnabled { + mi := &file_google_api_routing_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RoutingRule) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RoutingRule) ProtoMessage() {} + +func (x *RoutingRule) ProtoReflect() protoreflect.Message { + mi := &file_google_api_routing_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RoutingRule.ProtoReflect.Descriptor instead. +func (*RoutingRule) Descriptor() ([]byte, []int) { + return file_google_api_routing_proto_rawDescGZIP(), []int{0} +} + +func (x *RoutingRule) GetRoutingParameters() []*RoutingParameter { + if x != nil { + return x.RoutingParameters + } + return nil +} + +// A projection from an input message to the GRPC or REST header. +type RoutingParameter struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // A request field to extract the header key-value pair from. + Field string `protobuf:"bytes,1,opt,name=field,proto3" json:"field,omitempty"` + // A pattern matching the key-value field. Optional. + // If not specified, the whole field specified in the `field` field will be + // taken as value, and its name used as key. If specified, it MUST contain + // exactly one named segment (along with any number of unnamed segments) The + // pattern will be matched over the field specified in the `field` field, then + // if the match is successful: + // - the name of the single named segment will be used as a header name, + // - the match value of the segment will be used as a header value; + // if the match is NOT successful, nothing will be sent. + // + // Example: + // + // -- This is a field in the request message + // | that the header value will be extracted from. + // | + // | -- This is the key name in the + // | | routing header. + // V | + // field: "table_name" v + // path_template: "projects/*/{table_location=instances/*}/tables/*" + // ^ ^ + // | | + // In the {} brackets is the pattern that -- | + // specifies what to extract from the | + // field as a value to be sent. | + // | + // The string in the field must match the whole pattern -- + // before brackets, inside brackets, after brackets. + // + // When looking at this specific example, we can see that: + // - A key-value pair with the key `table_location` + // and the value matching `instances/*` should be added + // to the x-goog-request-params routing header. + // - The value is extracted from the request message's `table_name` field + // if it matches the full pattern specified: + // `projects/*/instances/*/tables/*`. + // + // **NB:** If the `path_template` field is not provided, the key name is + // equal to the field name, and the whole field should be sent as a value. + // This makes the pattern for the field and the value functionally equivalent + // to `**`, and the configuration + // + // { + // field: "table_name" + // } + // + // is a functionally equivalent shorthand to: + // + // { + // field: "table_name" + // path_template: "{table_name=**}" + // } + // + // See Example 1 for more details. + PathTemplate string `protobuf:"bytes,2,opt,name=path_template,json=pathTemplate,proto3" json:"path_template,omitempty"` +} + +func (x *RoutingParameter) Reset() { + *x = RoutingParameter{} + if protoimpl.UnsafeEnabled { + mi := &file_google_api_routing_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RoutingParameter) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RoutingParameter) ProtoMessage() {} + +func (x *RoutingParameter) ProtoReflect() protoreflect.Message { + mi := &file_google_api_routing_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RoutingParameter.ProtoReflect.Descriptor instead. +func (*RoutingParameter) Descriptor() ([]byte, []int) { + return file_google_api_routing_proto_rawDescGZIP(), []int{1} +} + +func (x *RoutingParameter) GetField() string { + if x != nil { + return x.Field + } + return "" +} + +func (x *RoutingParameter) GetPathTemplate() string { + if x != nil { + return x.PathTemplate + } + return "" +} + +var file_google_api_routing_proto_extTypes = []protoimpl.ExtensionInfo{ + { + ExtendedType: (*descriptorpb.MethodOptions)(nil), + ExtensionType: (*RoutingRule)(nil), + Field: 72295729, + Name: "google.api.routing", + Tag: "bytes,72295729,opt,name=routing", + Filename: "google/api/routing.proto", + }, +} + +// Extension fields to descriptorpb.MethodOptions. +var ( + // See RoutingRule. + // + // optional google.api.RoutingRule routing = 72295729; + E_Routing = &file_google_api_routing_proto_extTypes[0] +) + +var File_google_api_routing_proto protoreflect.FileDescriptor + +var file_google_api_routing_proto_rawDesc = []byte{ + 0x0a, 0x18, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x6f, 0x75, + 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0a, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x5a, 0x0a, 0x0b, 0x52, 0x6f, 0x75, 0x74, + 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x4b, 0x0a, 0x12, 0x72, 0x6f, 0x75, 0x74, 0x69, + 0x6e, 0x67, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, + 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, + 0x72, 0x52, 0x11, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, + 0x74, 0x65, 0x72, 0x73, 0x22, 0x4d, 0x0a, 0x10, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x50, + 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x69, 0x65, 0x6c, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x23, + 0x0a, 0x0d, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x61, 0x74, 0x68, 0x54, 0x65, 0x6d, 0x70, 0x6c, + 0x61, 0x74, 0x65, 0x3a, 0x54, 0x0a, 0x07, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x1e, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xb1, + 0xca, 0xbc, 0x22, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, + 0x52, 0x07, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x42, 0x6a, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x42, 0x0c, 0x52, 0x6f, 0x75, + 0x74, 0x69, 0x6e, 0x67, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x41, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x67, + 0x65, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, + 0x69, 0x73, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x3b, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0xa2, 0x02, + 0x04, 0x47, 0x41, 0x50, 0x49, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_google_api_routing_proto_rawDescOnce sync.Once + file_google_api_routing_proto_rawDescData = file_google_api_routing_proto_rawDesc +) + +func file_google_api_routing_proto_rawDescGZIP() []byte { + file_google_api_routing_proto_rawDescOnce.Do(func() { + file_google_api_routing_proto_rawDescData = protoimpl.X.CompressGZIP(file_google_api_routing_proto_rawDescData) + }) + return file_google_api_routing_proto_rawDescData +} + +var file_google_api_routing_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_google_api_routing_proto_goTypes = []interface{}{ + (*RoutingRule)(nil), // 0: google.api.RoutingRule + (*RoutingParameter)(nil), // 1: google.api.RoutingParameter + (*descriptorpb.MethodOptions)(nil), // 2: google.protobuf.MethodOptions +} +var file_google_api_routing_proto_depIdxs = []int32{ + 1, // 0: google.api.RoutingRule.routing_parameters:type_name -> google.api.RoutingParameter + 2, // 1: google.api.routing:extendee -> google.protobuf.MethodOptions + 0, // 2: google.api.routing:type_name -> google.api.RoutingRule + 3, // [3:3] is the sub-list for method output_type + 3, // [3:3] is the sub-list for method input_type + 2, // [2:3] is the sub-list for extension type_name + 1, // [1:2] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_google_api_routing_proto_init() } +func file_google_api_routing_proto_init() { + if File_google_api_routing_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_google_api_routing_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RoutingRule); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_api_routing_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RoutingParameter); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_google_api_routing_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 1, + NumServices: 0, + }, + GoTypes: file_google_api_routing_proto_goTypes, + DependencyIndexes: file_google_api_routing_proto_depIdxs, + MessageInfos: file_google_api_routing_proto_msgTypes, + ExtensionInfos: file_google_api_routing_proto_extTypes, + }.Build() + File_google_api_routing_proto = out.File + file_google_api_routing_proto_rawDesc = nil + file_google_api_routing_proto_goTypes = nil + file_google_api_routing_proto_depIdxs = nil +} diff --git a/vendor/google.golang.org/genproto/googleapis/api/launch_stage.pb.go b/vendor/google.golang.org/genproto/googleapis/api/launch_stage.pb.go new file mode 100644 index 00000000000..454948669dc --- /dev/null +++ b/vendor/google.golang.org/genproto/googleapis/api/launch_stage.pb.go @@ -0,0 +1,203 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.26.0 +// protoc v3.21.9 +// source: google/api/launch_stage.proto + +package api + +import ( + reflect "reflect" + sync "sync" + + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// The launch stage as defined by [Google Cloud Platform +// Launch Stages](https://cloud.google.com/terms/launch-stages). +type LaunchStage int32 + +const ( + // Do not use this default value. + LaunchStage_LAUNCH_STAGE_UNSPECIFIED LaunchStage = 0 + // The feature is not yet implemented. Users can not use it. + LaunchStage_UNIMPLEMENTED LaunchStage = 6 + // Prelaunch features are hidden from users and are only visible internally. + LaunchStage_PRELAUNCH LaunchStage = 7 + // Early Access features are limited to a closed group of testers. To use + // these features, you must sign up in advance and sign a Trusted Tester + // agreement (which includes confidentiality provisions). These features may + // be unstable, changed in backward-incompatible ways, and are not + // guaranteed to be released. + LaunchStage_EARLY_ACCESS LaunchStage = 1 + // Alpha is a limited availability test for releases before they are cleared + // for widespread use. By Alpha, all significant design issues are resolved + // and we are in the process of verifying functionality. Alpha customers + // need to apply for access, agree to applicable terms, and have their + // projects allowlisted. Alpha releases don't have to be feature complete, + // no SLAs are provided, and there are no technical support obligations, but + // they will be far enough along that customers can actually use them in + // test environments or for limited-use tests -- just like they would in + // normal production cases. + LaunchStage_ALPHA LaunchStage = 2 + // Beta is the point at which we are ready to open a release for any + // customer to use. There are no SLA or technical support obligations in a + // Beta release. Products will be complete from a feature perspective, but + // may have some open outstanding issues. Beta releases are suitable for + // limited production use cases. + LaunchStage_BETA LaunchStage = 3 + // GA features are open to all developers and are considered stable and + // fully qualified for production use. + LaunchStage_GA LaunchStage = 4 + // Deprecated features are scheduled to be shut down and removed. For more + // information, see the "Deprecation Policy" section of our [Terms of + // Service](https://cloud.google.com/terms/) + // and the [Google Cloud Platform Subject to the Deprecation + // Policy](https://cloud.google.com/terms/deprecation) documentation. + LaunchStage_DEPRECATED LaunchStage = 5 +) + +// Enum value maps for LaunchStage. +var ( + LaunchStage_name = map[int32]string{ + 0: "LAUNCH_STAGE_UNSPECIFIED", + 6: "UNIMPLEMENTED", + 7: "PRELAUNCH", + 1: "EARLY_ACCESS", + 2: "ALPHA", + 3: "BETA", + 4: "GA", + 5: "DEPRECATED", + } + LaunchStage_value = map[string]int32{ + "LAUNCH_STAGE_UNSPECIFIED": 0, + "UNIMPLEMENTED": 6, + "PRELAUNCH": 7, + "EARLY_ACCESS": 1, + "ALPHA": 2, + "BETA": 3, + "GA": 4, + "DEPRECATED": 5, + } +) + +func (x LaunchStage) Enum() *LaunchStage { + p := new(LaunchStage) + *p = x + return p +} + +func (x LaunchStage) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (LaunchStage) Descriptor() protoreflect.EnumDescriptor { + return file_google_api_launch_stage_proto_enumTypes[0].Descriptor() +} + +func (LaunchStage) Type() protoreflect.EnumType { + return &file_google_api_launch_stage_proto_enumTypes[0] +} + +func (x LaunchStage) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use LaunchStage.Descriptor instead. +func (LaunchStage) EnumDescriptor() ([]byte, []int) { + return file_google_api_launch_stage_proto_rawDescGZIP(), []int{0} +} + +var File_google_api_launch_stage_proto protoreflect.FileDescriptor + +var file_google_api_launch_stage_proto_rawDesc = []byte{ + 0x0a, 0x1d, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6c, 0x61, 0x75, + 0x6e, 0x63, 0x68, 0x5f, 0x73, 0x74, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, + 0x0a, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2a, 0x8c, 0x01, 0x0a, 0x0b, + 0x4c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x53, 0x74, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x18, 0x4c, + 0x41, 0x55, 0x4e, 0x43, 0x48, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, + 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x55, 0x4e, 0x49, + 0x4d, 0x50, 0x4c, 0x45, 0x4d, 0x45, 0x4e, 0x54, 0x45, 0x44, 0x10, 0x06, 0x12, 0x0d, 0x0a, 0x09, + 0x50, 0x52, 0x45, 0x4c, 0x41, 0x55, 0x4e, 0x43, 0x48, 0x10, 0x07, 0x12, 0x10, 0x0a, 0x0c, 0x45, + 0x41, 0x52, 0x4c, 0x59, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x01, 0x12, 0x09, 0x0a, + 0x05, 0x41, 0x4c, 0x50, 0x48, 0x41, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x42, 0x45, 0x54, 0x41, + 0x10, 0x03, 0x12, 0x06, 0x0a, 0x02, 0x47, 0x41, 0x10, 0x04, 0x12, 0x0e, 0x0a, 0x0a, 0x44, 0x45, + 0x50, 0x52, 0x45, 0x43, 0x41, 0x54, 0x45, 0x44, 0x10, 0x05, 0x42, 0x5a, 0x0a, 0x0e, 0x63, 0x6f, + 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x42, 0x10, 0x4c, 0x61, + 0x75, 0x6e, 0x63, 0x68, 0x53, 0x74, 0x61, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, + 0x5a, 0x2d, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, + 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x65, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x61, 0x70, 0x69, 0x3b, 0x61, 0x70, 0x69, 0xa2, + 0x02, 0x04, 0x47, 0x41, 0x50, 0x49, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_google_api_launch_stage_proto_rawDescOnce sync.Once + file_google_api_launch_stage_proto_rawDescData = file_google_api_launch_stage_proto_rawDesc +) + +func file_google_api_launch_stage_proto_rawDescGZIP() []byte { + file_google_api_launch_stage_proto_rawDescOnce.Do(func() { + file_google_api_launch_stage_proto_rawDescData = protoimpl.X.CompressGZIP(file_google_api_launch_stage_proto_rawDescData) + }) + return file_google_api_launch_stage_proto_rawDescData +} + +var file_google_api_launch_stage_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_google_api_launch_stage_proto_goTypes = []interface{}{ + (LaunchStage)(0), // 0: google.api.LaunchStage +} +var file_google_api_launch_stage_proto_depIdxs = []int32{ + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_google_api_launch_stage_proto_init() } +func file_google_api_launch_stage_proto_init() { + if File_google_api_launch_stage_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_google_api_launch_stage_proto_rawDesc, + NumEnums: 1, + NumMessages: 0, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_google_api_launch_stage_proto_goTypes, + DependencyIndexes: file_google_api_launch_stage_proto_depIdxs, + EnumInfos: file_google_api_launch_stage_proto_enumTypes, + }.Build() + File_google_api_launch_stage_proto = out.File + file_google_api_launch_stage_proto_rawDesc = nil + file_google_api_launch_stage_proto_goTypes = nil + file_google_api_launch_stage_proto_depIdxs = nil +} diff --git a/vendor/google.golang.org/genproto/googleapis/iam/v1/alias.go b/vendor/google.golang.org/genproto/googleapis/iam/v1/alias.go new file mode 100644 index 00000000000..9fb745926a5 --- /dev/null +++ b/vendor/google.golang.org/genproto/googleapis/iam/v1/alias.go @@ -0,0 +1,208 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by aliasgen. DO NOT EDIT. + +// Package iam aliases all exported identifiers in package +// "cloud.google.com/go/iam/apiv1/iampb". +// +// Deprecated: Please use types in: cloud.google.com/go/iam/apiv1/iampb. +// Please read https://github.com/googleapis/google-cloud-go/blob/main/migration.md +// for more details. +package iam + +import ( + src "cloud.google.com/go/iam/apiv1/iampb" + grpc "google.golang.org/grpc" +) + +// Deprecated: Please use consts in: cloud.google.com/go/iam/apiv1/iampb +const ( + AuditConfigDelta_ACTION_UNSPECIFIED = src.AuditConfigDelta_ACTION_UNSPECIFIED + AuditConfigDelta_ADD = src.AuditConfigDelta_ADD + AuditConfigDelta_REMOVE = src.AuditConfigDelta_REMOVE + AuditLogConfig_ADMIN_READ = src.AuditLogConfig_ADMIN_READ + AuditLogConfig_DATA_READ = src.AuditLogConfig_DATA_READ + AuditLogConfig_DATA_WRITE = src.AuditLogConfig_DATA_WRITE + AuditLogConfig_LOG_TYPE_UNSPECIFIED = src.AuditLogConfig_LOG_TYPE_UNSPECIFIED + BindingDelta_ACTION_UNSPECIFIED = src.BindingDelta_ACTION_UNSPECIFIED + BindingDelta_ADD = src.BindingDelta_ADD + BindingDelta_REMOVE = src.BindingDelta_REMOVE +) + +// Deprecated: Please use vars in: cloud.google.com/go/iam/apiv1/iampb +var ( + AuditConfigDelta_Action_name = src.AuditConfigDelta_Action_name + AuditConfigDelta_Action_value = src.AuditConfigDelta_Action_value + AuditLogConfig_LogType_name = src.AuditLogConfig_LogType_name + AuditLogConfig_LogType_value = src.AuditLogConfig_LogType_value + BindingDelta_Action_name = src.BindingDelta_Action_name + BindingDelta_Action_value = src.BindingDelta_Action_value + File_google_iam_v1_iam_policy_proto = src.File_google_iam_v1_iam_policy_proto + File_google_iam_v1_options_proto = src.File_google_iam_v1_options_proto + File_google_iam_v1_policy_proto = src.File_google_iam_v1_policy_proto +) + +// Specifies the audit configuration for a service. The configuration +// determines which permission types are logged, and what identities, if any, +// are exempted from logging. An AuditConfig must have one or more +// AuditLogConfigs. If there are AuditConfigs for both `allServices` and a +// specific service, the union of the two AuditConfigs is used for that +// service: the log_types specified in each AuditConfig are enabled, and the +// exempted_members in each AuditLogConfig are exempted. Example Policy with +// multiple AuditConfigs: { "audit_configs": [ { "service": "allServices", +// "audit_log_configs": [ { "log_type": "DATA_READ", "exempted_members": [ +// "user:jose@example.com" ] }, { "log_type": "DATA_WRITE" }, { "log_type": +// "ADMIN_READ" } ] }, { "service": "sampleservice.googleapis.com", +// "audit_log_configs": [ { "log_type": "DATA_READ" }, { "log_type": +// "DATA_WRITE", "exempted_members": [ "user:aliya@example.com" ] } ] } ] } For +// sampleservice, this policy enables DATA_READ, DATA_WRITE and ADMIN_READ +// logging. It also exempts jose@example.com from DATA_READ logging, and +// aliya@example.com from DATA_WRITE logging. +// +// Deprecated: Please use types in: cloud.google.com/go/iam/apiv1/iampb +type AuditConfig = src.AuditConfig + +// One delta entry for AuditConfig. Each individual change (only one +// exempted_member in each entry) to a AuditConfig will be a separate entry. +// +// Deprecated: Please use types in: cloud.google.com/go/iam/apiv1/iampb +type AuditConfigDelta = src.AuditConfigDelta + +// The type of action performed on an audit configuration in a policy. +// +// Deprecated: Please use types in: cloud.google.com/go/iam/apiv1/iampb +type AuditConfigDelta_Action = src.AuditConfigDelta_Action + +// Provides the configuration for logging a type of permissions. Example: { +// "audit_log_configs": [ { "log_type": "DATA_READ", "exempted_members": [ +// "user:jose@example.com" ] }, { "log_type": "DATA_WRITE" } ] } This enables +// 'DATA_READ' and 'DATA_WRITE' logging, while exempting jose@example.com from +// DATA_READ logging. +// +// Deprecated: Please use types in: cloud.google.com/go/iam/apiv1/iampb +type AuditLogConfig = src.AuditLogConfig + +// The list of valid permission types for which logging can be configured. +// Admin writes are always logged, and are not configurable. +// +// Deprecated: Please use types in: cloud.google.com/go/iam/apiv1/iampb +type AuditLogConfig_LogType = src.AuditLogConfig_LogType + +// Associates `members`, or principals, with a `role`. +// +// Deprecated: Please use types in: cloud.google.com/go/iam/apiv1/iampb +type Binding = src.Binding + +// One delta entry for Binding. Each individual change (only one member in +// each entry) to a binding will be a separate entry. +// +// Deprecated: Please use types in: cloud.google.com/go/iam/apiv1/iampb +type BindingDelta = src.BindingDelta + +// The type of action performed on a Binding in a policy. +// +// Deprecated: Please use types in: cloud.google.com/go/iam/apiv1/iampb +type BindingDelta_Action = src.BindingDelta_Action + +// Request message for `GetIamPolicy` method. +// +// Deprecated: Please use types in: cloud.google.com/go/iam/apiv1/iampb +type GetIamPolicyRequest = src.GetIamPolicyRequest + +// Encapsulates settings provided to GetIamPolicy. +// +// Deprecated: Please use types in: cloud.google.com/go/iam/apiv1/iampb +type GetPolicyOptions = src.GetPolicyOptions + +// IAMPolicyClient is the client API for IAMPolicy service. For semantics +// around ctx use and closing/ending streaming RPCs, please refer to +// https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +// +// Deprecated: Please use types in: cloud.google.com/go/iam/apiv1/iampb +type IAMPolicyClient = src.IAMPolicyClient + +// IAMPolicyServer is the server API for IAMPolicy service. +// +// Deprecated: Please use types in: cloud.google.com/go/iam/apiv1/iampb +type IAMPolicyServer = src.IAMPolicyServer + +// An Identity and Access Management (IAM) policy, which specifies access +// controls for Google Cloud resources. A `Policy` is a collection of +// `bindings`. A `binding` binds one or more `members`, or principals, to a +// single `role`. Principals can be user accounts, service accounts, Google +// groups, and domains (such as G Suite). A `role` is a named list of +// permissions; each `role` can be an IAM predefined role or a user-created +// custom role. For some types of Google Cloud resources, a `binding` can also +// specify a `condition`, which is a logical expression that allows access to a +// resource only if the expression evaluates to `true`. A condition can add +// constraints based on attributes of the request, the resource, or both. To +// learn which resources support conditions in their IAM policies, see the [IAM +// documentation](https://cloud.google.com/iam/help/conditions/resource-policies). +// **JSON example:** { "bindings": [ { "role": +// "roles/resourcemanager.organizationAdmin", "members": [ +// "user:mike@example.com", "group:admins@example.com", "domain:google.com", +// "serviceAccount:my-project-id@appspot.gserviceaccount.com" ] }, { "role": +// "roles/resourcemanager.organizationViewer", "members": [ +// "user:eve@example.com" ], "condition": { "title": "expirable access", +// "description": "Does not grant access after Sep 2020", "expression": +// "request.time < timestamp('2020-10-01T00:00:00.000Z')", } } ], "etag": +// "BwWWja0YfJA=", "version": 3 } **YAML example:** bindings: - members: - +// user:mike@example.com - group:admins@example.com - domain:google.com - +// serviceAccount:my-project-id@appspot.gserviceaccount.com role: +// roles/resourcemanager.organizationAdmin - members: - user:eve@example.com +// role: roles/resourcemanager.organizationViewer condition: title: expirable +// access description: Does not grant access after Sep 2020 expression: +// request.time < timestamp('2020-10-01T00:00:00.000Z') etag: BwWWja0YfJA= +// version: 3 For a description of IAM and its features, see the [IAM +// documentation](https://cloud.google.com/iam/docs/). +// +// Deprecated: Please use types in: cloud.google.com/go/iam/apiv1/iampb +type Policy = src.Policy + +// The difference delta between two policies. +// +// Deprecated: Please use types in: cloud.google.com/go/iam/apiv1/iampb +type PolicyDelta = src.PolicyDelta + +// Request message for `SetIamPolicy` method. +// +// Deprecated: Please use types in: cloud.google.com/go/iam/apiv1/iampb +type SetIamPolicyRequest = src.SetIamPolicyRequest + +// Request message for `TestIamPermissions` method. +// +// Deprecated: Please use types in: cloud.google.com/go/iam/apiv1/iampb +type TestIamPermissionsRequest = src.TestIamPermissionsRequest + +// Response message for `TestIamPermissions` method. +// +// Deprecated: Please use types in: cloud.google.com/go/iam/apiv1/iampb +type TestIamPermissionsResponse = src.TestIamPermissionsResponse + +// UnimplementedIAMPolicyServer can be embedded to have forward compatible +// implementations. +// +// Deprecated: Please use types in: cloud.google.com/go/iam/apiv1/iampb +type UnimplementedIAMPolicyServer = src.UnimplementedIAMPolicyServer + +// Deprecated: Please use funcs in: cloud.google.com/go/iam/apiv1/iampb +func NewIAMPolicyClient(cc grpc.ClientConnInterface) IAMPolicyClient { + return src.NewIAMPolicyClient(cc) +} + +// Deprecated: Please use funcs in: cloud.google.com/go/iam/apiv1/iampb +func RegisterIAMPolicyServer(s *grpc.Server, srv IAMPolicyServer) { + src.RegisterIAMPolicyServer(s, srv) +} diff --git a/vendor/google.golang.org/genproto/googleapis/iam/v1/policy.pb.go b/vendor/google.golang.org/genproto/googleapis/iam/v1/policy.pb.go deleted file mode 100644 index 78fa9008621..00000000000 --- a/vendor/google.golang.org/genproto/googleapis/iam/v1/policy.pb.go +++ /dev/null @@ -1,818 +0,0 @@ -// Copyright 2019 Google LLC. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.25.0 -// protoc v3.13.0 -// source: google/iam/v1/policy.proto - -package iam - -import ( - reflect "reflect" - sync "sync" - - proto "github.com/golang/protobuf/proto" - _ "google.golang.org/genproto/googleapis/api/annotations" - expr "google.golang.org/genproto/googleapis/type/expr" - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - -// The type of action performed on a Binding in a policy. -type BindingDelta_Action int32 - -const ( - // Unspecified. - BindingDelta_ACTION_UNSPECIFIED BindingDelta_Action = 0 - // Addition of a Binding. - BindingDelta_ADD BindingDelta_Action = 1 - // Removal of a Binding. - BindingDelta_REMOVE BindingDelta_Action = 2 -) - -// Enum value maps for BindingDelta_Action. -var ( - BindingDelta_Action_name = map[int32]string{ - 0: "ACTION_UNSPECIFIED", - 1: "ADD", - 2: "REMOVE", - } - BindingDelta_Action_value = map[string]int32{ - "ACTION_UNSPECIFIED": 0, - "ADD": 1, - "REMOVE": 2, - } -) - -func (x BindingDelta_Action) Enum() *BindingDelta_Action { - p := new(BindingDelta_Action) - *p = x - return p -} - -func (x BindingDelta_Action) String() string { - return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) -} - -func (BindingDelta_Action) Descriptor() protoreflect.EnumDescriptor { - return file_google_iam_v1_policy_proto_enumTypes[0].Descriptor() -} - -func (BindingDelta_Action) Type() protoreflect.EnumType { - return &file_google_iam_v1_policy_proto_enumTypes[0] -} - -func (x BindingDelta_Action) Number() protoreflect.EnumNumber { - return protoreflect.EnumNumber(x) -} - -// Deprecated: Use BindingDelta_Action.Descriptor instead. -func (BindingDelta_Action) EnumDescriptor() ([]byte, []int) { - return file_google_iam_v1_policy_proto_rawDescGZIP(), []int{3, 0} -} - -// The type of action performed on an audit configuration in a policy. -type AuditConfigDelta_Action int32 - -const ( - // Unspecified. - AuditConfigDelta_ACTION_UNSPECIFIED AuditConfigDelta_Action = 0 - // Addition of an audit configuration. - AuditConfigDelta_ADD AuditConfigDelta_Action = 1 - // Removal of an audit configuration. - AuditConfigDelta_REMOVE AuditConfigDelta_Action = 2 -) - -// Enum value maps for AuditConfigDelta_Action. -var ( - AuditConfigDelta_Action_name = map[int32]string{ - 0: "ACTION_UNSPECIFIED", - 1: "ADD", - 2: "REMOVE", - } - AuditConfigDelta_Action_value = map[string]int32{ - "ACTION_UNSPECIFIED": 0, - "ADD": 1, - "REMOVE": 2, - } -) - -func (x AuditConfigDelta_Action) Enum() *AuditConfigDelta_Action { - p := new(AuditConfigDelta_Action) - *p = x - return p -} - -func (x AuditConfigDelta_Action) String() string { - return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) -} - -func (AuditConfigDelta_Action) Descriptor() protoreflect.EnumDescriptor { - return file_google_iam_v1_policy_proto_enumTypes[1].Descriptor() -} - -func (AuditConfigDelta_Action) Type() protoreflect.EnumType { - return &file_google_iam_v1_policy_proto_enumTypes[1] -} - -func (x AuditConfigDelta_Action) Number() protoreflect.EnumNumber { - return protoreflect.EnumNumber(x) -} - -// Deprecated: Use AuditConfigDelta_Action.Descriptor instead. -func (AuditConfigDelta_Action) EnumDescriptor() ([]byte, []int) { - return file_google_iam_v1_policy_proto_rawDescGZIP(), []int{4, 0} -} - -// Defines an Identity and Access Management (IAM) policy. It is used to -// specify access control policies for Cloud Platform resources. -// -// -// A `Policy` is a collection of `bindings`. A `binding` binds one or more -// `members` to a single `role`. Members can be user accounts, service accounts, -// Google groups, and domains (such as G Suite). A `role` is a named list of -// permissions (defined by IAM or configured by users). A `binding` can -// optionally specify a `condition`, which is a logic expression that further -// constrains the role binding based on attributes about the request and/or -// target resource. -// -// **JSON Example** -// -// { -// "bindings": [ -// { -// "role": "roles/resourcemanager.organizationAdmin", -// "members": [ -// "user:mike@example.com", -// "group:admins@example.com", -// "domain:google.com", -// "serviceAccount:my-project-id@appspot.gserviceaccount.com" -// ] -// }, -// { -// "role": "roles/resourcemanager.organizationViewer", -// "members": ["user:eve@example.com"], -// "condition": { -// "title": "expirable access", -// "description": "Does not grant access after Sep 2020", -// "expression": "request.time < -// timestamp('2020-10-01T00:00:00.000Z')", -// } -// } -// ] -// } -// -// **YAML Example** -// -// bindings: -// - members: -// - user:mike@example.com -// - group:admins@example.com -// - domain:google.com -// - serviceAccount:my-project-id@appspot.gserviceaccount.com -// role: roles/resourcemanager.organizationAdmin -// - members: -// - user:eve@example.com -// role: roles/resourcemanager.organizationViewer -// condition: -// title: expirable access -// description: Does not grant access after Sep 2020 -// expression: request.time < timestamp('2020-10-01T00:00:00.000Z') -// -// For a description of IAM and its features, see the -// [IAM developer's guide](https://cloud.google.com/iam/docs). -type Policy struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Specifies the format of the policy. - // - // Valid values are 0, 1, and 3. Requests specifying an invalid value will be - // rejected. - // - // Operations affecting conditional bindings must specify version 3. This can - // be either setting a conditional policy, modifying a conditional binding, - // or removing a binding (conditional or unconditional) from the stored - // conditional policy. - // Operations on non-conditional policies may specify any valid value or - // leave the field unset. - // - // If no etag is provided in the call to `setIamPolicy`, version compliance - // checks against the stored policy is skipped. - Version int32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` - // Associates a list of `members` to a `role`. Optionally may specify a - // `condition` that determines when binding is in effect. - // `bindings` with no members will result in an error. - Bindings []*Binding `protobuf:"bytes,4,rep,name=bindings,proto3" json:"bindings,omitempty"` - // `etag` is used for optimistic concurrency control as a way to help - // prevent simultaneous updates of a policy from overwriting each other. - // It is strongly suggested that systems make use of the `etag` in the - // read-modify-write cycle to perform policy updates in order to avoid race - // conditions: An `etag` is returned in the response to `getIamPolicy`, and - // systems are expected to put that etag in the request to `setIamPolicy` to - // ensure that their change will be applied to the same version of the policy. - // - // If no `etag` is provided in the call to `setIamPolicy`, then the existing - // policy is overwritten. Due to blind-set semantics of an etag-less policy, - // 'setIamPolicy' will not fail even if the incoming policy version does not - // meet the requirements for modifying the stored policy. - Etag []byte `protobuf:"bytes,3,opt,name=etag,proto3" json:"etag,omitempty"` -} - -func (x *Policy) Reset() { - *x = Policy{} - if protoimpl.UnsafeEnabled { - mi := &file_google_iam_v1_policy_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Policy) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Policy) ProtoMessage() {} - -func (x *Policy) ProtoReflect() protoreflect.Message { - mi := &file_google_iam_v1_policy_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Policy.ProtoReflect.Descriptor instead. -func (*Policy) Descriptor() ([]byte, []int) { - return file_google_iam_v1_policy_proto_rawDescGZIP(), []int{0} -} - -func (x *Policy) GetVersion() int32 { - if x != nil { - return x.Version - } - return 0 -} - -func (x *Policy) GetBindings() []*Binding { - if x != nil { - return x.Bindings - } - return nil -} - -func (x *Policy) GetEtag() []byte { - if x != nil { - return x.Etag - } - return nil -} - -// Associates `members` with a `role`. -type Binding struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Role that is assigned to `members`. - // For example, `roles/viewer`, `roles/editor`, or `roles/owner`. - Role string `protobuf:"bytes,1,opt,name=role,proto3" json:"role,omitempty"` - // Specifies the identities requesting access for a Cloud Platform resource. - // `members` can have the following values: - // - // * `allUsers`: A special identifier that represents anyone who is - // on the internet; with or without a Google account. - // - // * `allAuthenticatedUsers`: A special identifier that represents anyone - // who is authenticated with a Google account or a service account. - // - // * `user:{emailid}`: An email address that represents a specific Google - // account. For example, `alice@example.com` . - // - // - // * `serviceAccount:{emailid}`: An email address that represents a service - // account. For example, `my-other-app@appspot.gserviceaccount.com`. - // - // * `group:{emailid}`: An email address that represents a Google group. - // For example, `admins@example.com`. - // - // - // * `domain:{domain}`: The G Suite domain (primary) that represents all the - // users of that domain. For example, `google.com` or `example.com`. - // - // - Members []string `protobuf:"bytes,2,rep,name=members,proto3" json:"members,omitempty"` - // The condition that is associated with this binding. - // NOTE: An unsatisfied condition will not allow user access via current - // binding. Different bindings, including their conditions, are examined - // independently. - Condition *expr.Expr `protobuf:"bytes,3,opt,name=condition,proto3" json:"condition,omitempty"` -} - -func (x *Binding) Reset() { - *x = Binding{} - if protoimpl.UnsafeEnabled { - mi := &file_google_iam_v1_policy_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Binding) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Binding) ProtoMessage() {} - -func (x *Binding) ProtoReflect() protoreflect.Message { - mi := &file_google_iam_v1_policy_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Binding.ProtoReflect.Descriptor instead. -func (*Binding) Descriptor() ([]byte, []int) { - return file_google_iam_v1_policy_proto_rawDescGZIP(), []int{1} -} - -func (x *Binding) GetRole() string { - if x != nil { - return x.Role - } - return "" -} - -func (x *Binding) GetMembers() []string { - if x != nil { - return x.Members - } - return nil -} - -func (x *Binding) GetCondition() *expr.Expr { - if x != nil { - return x.Condition - } - return nil -} - -// The difference delta between two policies. -type PolicyDelta struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // The delta for Bindings between two policies. - BindingDeltas []*BindingDelta `protobuf:"bytes,1,rep,name=binding_deltas,json=bindingDeltas,proto3" json:"binding_deltas,omitempty"` - // The delta for AuditConfigs between two policies. - AuditConfigDeltas []*AuditConfigDelta `protobuf:"bytes,2,rep,name=audit_config_deltas,json=auditConfigDeltas,proto3" json:"audit_config_deltas,omitempty"` -} - -func (x *PolicyDelta) Reset() { - *x = PolicyDelta{} - if protoimpl.UnsafeEnabled { - mi := &file_google_iam_v1_policy_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *PolicyDelta) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*PolicyDelta) ProtoMessage() {} - -func (x *PolicyDelta) ProtoReflect() protoreflect.Message { - mi := &file_google_iam_v1_policy_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use PolicyDelta.ProtoReflect.Descriptor instead. -func (*PolicyDelta) Descriptor() ([]byte, []int) { - return file_google_iam_v1_policy_proto_rawDescGZIP(), []int{2} -} - -func (x *PolicyDelta) GetBindingDeltas() []*BindingDelta { - if x != nil { - return x.BindingDeltas - } - return nil -} - -func (x *PolicyDelta) GetAuditConfigDeltas() []*AuditConfigDelta { - if x != nil { - return x.AuditConfigDeltas - } - return nil -} - -// One delta entry for Binding. Each individual change (only one member in each -// entry) to a binding will be a separate entry. -type BindingDelta struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // The action that was performed on a Binding. - // Required - Action BindingDelta_Action `protobuf:"varint,1,opt,name=action,proto3,enum=google.iam.v1.BindingDelta_Action" json:"action,omitempty"` - // Role that is assigned to `members`. - // For example, `roles/viewer`, `roles/editor`, or `roles/owner`. - // Required - Role string `protobuf:"bytes,2,opt,name=role,proto3" json:"role,omitempty"` - // A single identity requesting access for a Cloud Platform resource. - // Follows the same format of Binding.members. - // Required - Member string `protobuf:"bytes,3,opt,name=member,proto3" json:"member,omitempty"` - // The condition that is associated with this binding. - Condition *expr.Expr `protobuf:"bytes,4,opt,name=condition,proto3" json:"condition,omitempty"` -} - -func (x *BindingDelta) Reset() { - *x = BindingDelta{} - if protoimpl.UnsafeEnabled { - mi := &file_google_iam_v1_policy_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *BindingDelta) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*BindingDelta) ProtoMessage() {} - -func (x *BindingDelta) ProtoReflect() protoreflect.Message { - mi := &file_google_iam_v1_policy_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use BindingDelta.ProtoReflect.Descriptor instead. -func (*BindingDelta) Descriptor() ([]byte, []int) { - return file_google_iam_v1_policy_proto_rawDescGZIP(), []int{3} -} - -func (x *BindingDelta) GetAction() BindingDelta_Action { - if x != nil { - return x.Action - } - return BindingDelta_ACTION_UNSPECIFIED -} - -func (x *BindingDelta) GetRole() string { - if x != nil { - return x.Role - } - return "" -} - -func (x *BindingDelta) GetMember() string { - if x != nil { - return x.Member - } - return "" -} - -func (x *BindingDelta) GetCondition() *expr.Expr { - if x != nil { - return x.Condition - } - return nil -} - -// One delta entry for AuditConfig. Each individual change (only one -// exempted_member in each entry) to a AuditConfig will be a separate entry. -type AuditConfigDelta struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // The action that was performed on an audit configuration in a policy. - // Required - Action AuditConfigDelta_Action `protobuf:"varint,1,opt,name=action,proto3,enum=google.iam.v1.AuditConfigDelta_Action" json:"action,omitempty"` - // Specifies a service that was configured for Cloud Audit Logging. - // For example, `storage.googleapis.com`, `cloudsql.googleapis.com`. - // `allServices` is a special value that covers all services. - // Required - Service string `protobuf:"bytes,2,opt,name=service,proto3" json:"service,omitempty"` - // A single identity that is exempted from "data access" audit - // logging for the `service` specified above. - // Follows the same format of Binding.members. - ExemptedMember string `protobuf:"bytes,3,opt,name=exempted_member,json=exemptedMember,proto3" json:"exempted_member,omitempty"` - // Specifies the log_type that was be enabled. ADMIN_ACTIVITY is always - // enabled, and cannot be configured. - // Required - LogType string `protobuf:"bytes,4,opt,name=log_type,json=logType,proto3" json:"log_type,omitempty"` -} - -func (x *AuditConfigDelta) Reset() { - *x = AuditConfigDelta{} - if protoimpl.UnsafeEnabled { - mi := &file_google_iam_v1_policy_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *AuditConfigDelta) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*AuditConfigDelta) ProtoMessage() {} - -func (x *AuditConfigDelta) ProtoReflect() protoreflect.Message { - mi := &file_google_iam_v1_policy_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use AuditConfigDelta.ProtoReflect.Descriptor instead. -func (*AuditConfigDelta) Descriptor() ([]byte, []int) { - return file_google_iam_v1_policy_proto_rawDescGZIP(), []int{4} -} - -func (x *AuditConfigDelta) GetAction() AuditConfigDelta_Action { - if x != nil { - return x.Action - } - return AuditConfigDelta_ACTION_UNSPECIFIED -} - -func (x *AuditConfigDelta) GetService() string { - if x != nil { - return x.Service - } - return "" -} - -func (x *AuditConfigDelta) GetExemptedMember() string { - if x != nil { - return x.ExemptedMember - } - return "" -} - -func (x *AuditConfigDelta) GetLogType() string { - if x != nil { - return x.LogType - } - return "" -} - -var File_google_iam_v1_policy_proto protoreflect.FileDescriptor - -var file_google_iam_v1_policy_proto_rawDesc = []byte{ - 0x0a, 0x1a, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x69, 0x61, 0x6d, 0x2f, 0x76, 0x31, 0x2f, - 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0d, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x1a, 0x16, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x2f, 0x65, 0x78, 0x70, 0x72, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, - 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x22, 0x6a, 0x0a, 0x06, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x08, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, - 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, - 0x08, 0x62, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x74, 0x61, - 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x65, 0x74, 0x61, 0x67, 0x22, 0x68, 0x0a, - 0x07, 0x42, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x6f, 0x6c, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, - 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x6d, - 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x2f, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, - 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x2e, 0x45, 0x78, 0x70, 0x72, 0x52, 0x09, 0x63, 0x6f, - 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xa2, 0x01, 0x0a, 0x0b, 0x50, 0x6f, 0x6c, 0x69, - 0x63, 0x79, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x12, 0x42, 0x0a, 0x0e, 0x62, 0x69, 0x6e, 0x64, 0x69, - 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x2e, - 0x42, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x52, 0x0d, 0x62, 0x69, - 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x73, 0x12, 0x4f, 0x0a, 0x13, 0x61, - 0x75, 0x64, 0x69, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x64, 0x65, 0x6c, 0x74, - 0x61, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x52, 0x11, 0x61, 0x75, 0x64, 0x69, 0x74, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x73, 0x22, 0xde, 0x01, 0x0a, - 0x0c, 0x42, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x12, 0x3a, 0x0a, - 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x69, - 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x6f, 0x6c, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x12, 0x16, 0x0a, - 0x06, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, - 0x65, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x2f, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x2e, 0x45, 0x78, 0x70, 0x72, 0x52, 0x09, 0x63, 0x6f, 0x6e, - 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x35, 0x0a, 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x16, 0x0a, 0x12, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, - 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x44, 0x44, 0x10, - 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x52, 0x45, 0x4d, 0x4f, 0x56, 0x45, 0x10, 0x02, 0x22, 0xe7, 0x01, - 0x0a, 0x10, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x65, 0x6c, - 0x74, 0x61, 0x12, 0x3e, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x69, 0x61, 0x6d, 0x2e, - 0x76, 0x31, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x44, 0x65, - 0x6c, 0x74, 0x61, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x27, 0x0a, 0x0f, - 0x65, 0x78, 0x65, 0x6d, 0x70, 0x74, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x65, 0x78, 0x65, 0x6d, 0x70, 0x74, 0x65, 0x64, 0x4d, - 0x65, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x6c, 0x6f, 0x67, 0x5f, 0x74, 0x79, 0x70, - 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6c, 0x6f, 0x67, 0x54, 0x79, 0x70, 0x65, - 0x22, 0x35, 0x0a, 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x12, 0x41, 0x43, - 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, - 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x44, 0x44, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x52, - 0x45, 0x4d, 0x4f, 0x56, 0x45, 0x10, 0x02, 0x42, 0x83, 0x01, 0x0a, 0x11, 0x63, 0x6f, 0x6d, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x42, 0x0b, 0x50, - 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, - 0x67, 0x65, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, - 0x70, 0x69, 0x73, 0x2f, 0x69, 0x61, 0x6d, 0x2f, 0x76, 0x31, 0x3b, 0x69, 0x61, 0x6d, 0xf8, 0x01, - 0x01, 0xaa, 0x02, 0x13, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, - 0x2e, 0x49, 0x61, 0x6d, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x13, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x5c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x5c, 0x49, 0x61, 0x6d, 0x5c, 0x56, 0x31, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_google_iam_v1_policy_proto_rawDescOnce sync.Once - file_google_iam_v1_policy_proto_rawDescData = file_google_iam_v1_policy_proto_rawDesc -) - -func file_google_iam_v1_policy_proto_rawDescGZIP() []byte { - file_google_iam_v1_policy_proto_rawDescOnce.Do(func() { - file_google_iam_v1_policy_proto_rawDescData = protoimpl.X.CompressGZIP(file_google_iam_v1_policy_proto_rawDescData) - }) - return file_google_iam_v1_policy_proto_rawDescData -} - -var file_google_iam_v1_policy_proto_enumTypes = make([]protoimpl.EnumInfo, 2) -var file_google_iam_v1_policy_proto_msgTypes = make([]protoimpl.MessageInfo, 5) -var file_google_iam_v1_policy_proto_goTypes = []interface{}{ - (BindingDelta_Action)(0), // 0: google.iam.v1.BindingDelta.Action - (AuditConfigDelta_Action)(0), // 1: google.iam.v1.AuditConfigDelta.Action - (*Policy)(nil), // 2: google.iam.v1.Policy - (*Binding)(nil), // 3: google.iam.v1.Binding - (*PolicyDelta)(nil), // 4: google.iam.v1.PolicyDelta - (*BindingDelta)(nil), // 5: google.iam.v1.BindingDelta - (*AuditConfigDelta)(nil), // 6: google.iam.v1.AuditConfigDelta - (*expr.Expr)(nil), // 7: google.type.Expr -} -var file_google_iam_v1_policy_proto_depIdxs = []int32{ - 3, // 0: google.iam.v1.Policy.bindings:type_name -> google.iam.v1.Binding - 7, // 1: google.iam.v1.Binding.condition:type_name -> google.type.Expr - 5, // 2: google.iam.v1.PolicyDelta.binding_deltas:type_name -> google.iam.v1.BindingDelta - 6, // 3: google.iam.v1.PolicyDelta.audit_config_deltas:type_name -> google.iam.v1.AuditConfigDelta - 0, // 4: google.iam.v1.BindingDelta.action:type_name -> google.iam.v1.BindingDelta.Action - 7, // 5: google.iam.v1.BindingDelta.condition:type_name -> google.type.Expr - 1, // 6: google.iam.v1.AuditConfigDelta.action:type_name -> google.iam.v1.AuditConfigDelta.Action - 7, // [7:7] is the sub-list for method output_type - 7, // [7:7] is the sub-list for method input_type - 7, // [7:7] is the sub-list for extension type_name - 7, // [7:7] is the sub-list for extension extendee - 0, // [0:7] is the sub-list for field type_name -} - -func init() { file_google_iam_v1_policy_proto_init() } -func file_google_iam_v1_policy_proto_init() { - if File_google_iam_v1_policy_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_google_iam_v1_policy_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Policy); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_google_iam_v1_policy_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Binding); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_google_iam_v1_policy_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PolicyDelta); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_google_iam_v1_policy_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BindingDelta); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_google_iam_v1_policy_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AuditConfigDelta); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_google_iam_v1_policy_proto_rawDesc, - NumEnums: 2, - NumMessages: 5, - NumExtensions: 0, - NumServices: 0, - }, - GoTypes: file_google_iam_v1_policy_proto_goTypes, - DependencyIndexes: file_google_iam_v1_policy_proto_depIdxs, - EnumInfos: file_google_iam_v1_policy_proto_enumTypes, - MessageInfos: file_google_iam_v1_policy_proto_msgTypes, - }.Build() - File_google_iam_v1_policy_proto = out.File - file_google_iam_v1_policy_proto_rawDesc = nil - file_google_iam_v1_policy_proto_goTypes = nil - file_google_iam_v1_policy_proto_depIdxs = nil -} diff --git a/vendor/google.golang.org/genproto/googleapis/rpc/code/code.pb.go b/vendor/google.golang.org/genproto/googleapis/rpc/code/code.pb.go index 386fd7b13c4..cc5d52fbcc3 100644 --- a/vendor/google.golang.org/genproto/googleapis/rpc/code/code.pb.go +++ b/vendor/google.golang.org/genproto/googleapis/rpc/code/code.pb.go @@ -1,4 +1,4 @@ -// Copyright 2020 Google LLC +// Copyright 2022 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -14,8 +14,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.25.0 -// protoc v3.13.0 +// protoc-gen-go v1.26.0 +// protoc v3.21.9 // source: google/rpc/code.proto package code @@ -24,7 +24,6 @@ import ( reflect "reflect" sync "sync" - proto "github.com/golang/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" ) @@ -36,13 +35,8 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - // The canonical error codes for gRPC APIs. // -// // Sometimes multiple error codes may apply. Services should return // the most specific error code that applies. For example, prefer // `OUT_OF_RANGE` over `FAILED_PRECONDITION` if both codes apply. @@ -50,7 +44,7 @@ const _ = proto.ProtoPackageIsVersion4 type Code int32 const ( - // Not an error; returned on success + // Not an error; returned on success. // // HTTP Mapping: 200 OK Code_OK Code = 0 @@ -84,7 +78,7 @@ const ( // Some requested entity (e.g., file or directory) was not found. // // Note to server developers: if a request is denied for an entire class - // of users, such as gradual feature rollout or undocumented whitelist, + // of users, such as gradual feature rollout or undocumented allowlist, // `NOT_FOUND` may be used. If a request is denied for some users within // a class of users, such as user-based access control, `PERMISSION_DENIED` // must be used. @@ -124,15 +118,16 @@ const ( // // Service implementors can use the following guidelines to decide // between `FAILED_PRECONDITION`, `ABORTED`, and `UNAVAILABLE`: - // (a) Use `UNAVAILABLE` if the client can retry just the failing call. - // (b) Use `ABORTED` if the client should retry at a higher level - // (e.g., when a client-specified test-and-set fails, indicating the - // client should restart a read-modify-write sequence). - // (c) Use `FAILED_PRECONDITION` if the client should not retry until - // the system state has been explicitly fixed. E.g., if an "rmdir" - // fails because the directory is non-empty, `FAILED_PRECONDITION` - // should be returned since the client should not retry unless - // the files are deleted from the directory. + // + // (a) Use `UNAVAILABLE` if the client can retry just the failing call. + // (b) Use `ABORTED` if the client should retry at a higher level. For + // example, when a client-specified test-and-set fails, indicating the + // client should restart a read-modify-write sequence. + // (c) Use `FAILED_PRECONDITION` if the client should not retry until + // the system state has been explicitly fixed. For example, if an "rmdir" + // fails because the directory is non-empty, `FAILED_PRECONDITION` + // should be returned since the client should not retry unless + // the files are deleted from the directory. // // HTTP Mapping: 400 Bad Request Code_FAILED_PRECONDITION Code = 9 diff --git a/vendor/google.golang.org/genproto/googleapis/rpc/errdetails/error_details.pb.go b/vendor/google.golang.org/genproto/googleapis/rpc/errdetails/error_details.pb.go new file mode 100644 index 00000000000..7bd161e48ad --- /dev/null +++ b/vendor/google.golang.org/genproto/googleapis/rpc/errdetails/error_details.pb.go @@ -0,0 +1,1314 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.26.0 +// protoc v3.21.9 +// source: google/rpc/error_details.proto + +package errdetails + +import ( + reflect "reflect" + sync "sync" + + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + durationpb "google.golang.org/protobuf/types/known/durationpb" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// Describes the cause of the error with structured details. +// +// Example of an error when contacting the "pubsub.googleapis.com" API when it +// is not enabled: +// +// { "reason": "API_DISABLED" +// "domain": "googleapis.com" +// "metadata": { +// "resource": "projects/123", +// "service": "pubsub.googleapis.com" +// } +// } +// +// This response indicates that the pubsub.googleapis.com API is not enabled. +// +// Example of an error that is returned when attempting to create a Spanner +// instance in a region that is out of stock: +// +// { "reason": "STOCKOUT" +// "domain": "spanner.googleapis.com", +// "metadata": { +// "availableRegions": "us-central1,us-east2" +// } +// } +type ErrorInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The reason of the error. This is a constant value that identifies the + // proximate cause of the error. Error reasons are unique within a particular + // domain of errors. This should be at most 63 characters and match a + // regular expression of `[A-Z][A-Z0-9_]+[A-Z0-9]`, which represents + // UPPER_SNAKE_CASE. + Reason string `protobuf:"bytes,1,opt,name=reason,proto3" json:"reason,omitempty"` + // The logical grouping to which the "reason" belongs. The error domain + // is typically the registered service name of the tool or product that + // generates the error. Example: "pubsub.googleapis.com". If the error is + // generated by some common infrastructure, the error domain must be a + // globally unique value that identifies the infrastructure. For Google API + // infrastructure, the error domain is "googleapis.com". + Domain string `protobuf:"bytes,2,opt,name=domain,proto3" json:"domain,omitempty"` + // Additional structured details about this error. + // + // Keys should match /[a-zA-Z0-9-_]/ and be limited to 64 characters in + // length. When identifying the current value of an exceeded limit, the units + // should be contained in the key, not the value. For example, rather than + // {"instanceLimit": "100/request"}, should be returned as, + // {"instanceLimitPerRequest": "100"}, if the client exceeds the number of + // instances that can be created in a single (batch) request. + Metadata map[string]string `protobuf:"bytes,3,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *ErrorInfo) Reset() { + *x = ErrorInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_google_rpc_error_details_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ErrorInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ErrorInfo) ProtoMessage() {} + +func (x *ErrorInfo) ProtoReflect() protoreflect.Message { + mi := &file_google_rpc_error_details_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ErrorInfo.ProtoReflect.Descriptor instead. +func (*ErrorInfo) Descriptor() ([]byte, []int) { + return file_google_rpc_error_details_proto_rawDescGZIP(), []int{0} +} + +func (x *ErrorInfo) GetReason() string { + if x != nil { + return x.Reason + } + return "" +} + +func (x *ErrorInfo) GetDomain() string { + if x != nil { + return x.Domain + } + return "" +} + +func (x *ErrorInfo) GetMetadata() map[string]string { + if x != nil { + return x.Metadata + } + return nil +} + +// Describes when the clients can retry a failed request. Clients could ignore +// the recommendation here or retry when this information is missing from error +// responses. +// +// It's always recommended that clients should use exponential backoff when +// retrying. +// +// Clients should wait until `retry_delay` amount of time has passed since +// receiving the error response before retrying. If retrying requests also +// fail, clients should use an exponential backoff scheme to gradually increase +// the delay between retries based on `retry_delay`, until either a maximum +// number of retries have been reached or a maximum retry delay cap has been +// reached. +type RetryInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Clients should wait at least this long between retrying the same request. + RetryDelay *durationpb.Duration `protobuf:"bytes,1,opt,name=retry_delay,json=retryDelay,proto3" json:"retry_delay,omitempty"` +} + +func (x *RetryInfo) Reset() { + *x = RetryInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_google_rpc_error_details_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RetryInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RetryInfo) ProtoMessage() {} + +func (x *RetryInfo) ProtoReflect() protoreflect.Message { + mi := &file_google_rpc_error_details_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RetryInfo.ProtoReflect.Descriptor instead. +func (*RetryInfo) Descriptor() ([]byte, []int) { + return file_google_rpc_error_details_proto_rawDescGZIP(), []int{1} +} + +func (x *RetryInfo) GetRetryDelay() *durationpb.Duration { + if x != nil { + return x.RetryDelay + } + return nil +} + +// Describes additional debugging info. +type DebugInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The stack trace entries indicating where the error occurred. + StackEntries []string `protobuf:"bytes,1,rep,name=stack_entries,json=stackEntries,proto3" json:"stack_entries,omitempty"` + // Additional debugging information provided by the server. + Detail string `protobuf:"bytes,2,opt,name=detail,proto3" json:"detail,omitempty"` +} + +func (x *DebugInfo) Reset() { + *x = DebugInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_google_rpc_error_details_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DebugInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DebugInfo) ProtoMessage() {} + +func (x *DebugInfo) ProtoReflect() protoreflect.Message { + mi := &file_google_rpc_error_details_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DebugInfo.ProtoReflect.Descriptor instead. +func (*DebugInfo) Descriptor() ([]byte, []int) { + return file_google_rpc_error_details_proto_rawDescGZIP(), []int{2} +} + +func (x *DebugInfo) GetStackEntries() []string { + if x != nil { + return x.StackEntries + } + return nil +} + +func (x *DebugInfo) GetDetail() string { + if x != nil { + return x.Detail + } + return "" +} + +// Describes how a quota check failed. +// +// For example if a daily limit was exceeded for the calling project, +// a service could respond with a QuotaFailure detail containing the project +// id and the description of the quota limit that was exceeded. If the +// calling project hasn't enabled the service in the developer console, then +// a service could respond with the project id and set `service_disabled` +// to true. +// +// Also see RetryInfo and Help types for other details about handling a +// quota failure. +type QuotaFailure struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Describes all quota violations. + Violations []*QuotaFailure_Violation `protobuf:"bytes,1,rep,name=violations,proto3" json:"violations,omitempty"` +} + +func (x *QuotaFailure) Reset() { + *x = QuotaFailure{} + if protoimpl.UnsafeEnabled { + mi := &file_google_rpc_error_details_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *QuotaFailure) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QuotaFailure) ProtoMessage() {} + +func (x *QuotaFailure) ProtoReflect() protoreflect.Message { + mi := &file_google_rpc_error_details_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use QuotaFailure.ProtoReflect.Descriptor instead. +func (*QuotaFailure) Descriptor() ([]byte, []int) { + return file_google_rpc_error_details_proto_rawDescGZIP(), []int{3} +} + +func (x *QuotaFailure) GetViolations() []*QuotaFailure_Violation { + if x != nil { + return x.Violations + } + return nil +} + +// Describes what preconditions have failed. +// +// For example, if an RPC failed because it required the Terms of Service to be +// acknowledged, it could list the terms of service violation in the +// PreconditionFailure message. +type PreconditionFailure struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Describes all precondition violations. + Violations []*PreconditionFailure_Violation `protobuf:"bytes,1,rep,name=violations,proto3" json:"violations,omitempty"` +} + +func (x *PreconditionFailure) Reset() { + *x = PreconditionFailure{} + if protoimpl.UnsafeEnabled { + mi := &file_google_rpc_error_details_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PreconditionFailure) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PreconditionFailure) ProtoMessage() {} + +func (x *PreconditionFailure) ProtoReflect() protoreflect.Message { + mi := &file_google_rpc_error_details_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PreconditionFailure.ProtoReflect.Descriptor instead. +func (*PreconditionFailure) Descriptor() ([]byte, []int) { + return file_google_rpc_error_details_proto_rawDescGZIP(), []int{4} +} + +func (x *PreconditionFailure) GetViolations() []*PreconditionFailure_Violation { + if x != nil { + return x.Violations + } + return nil +} + +// Describes violations in a client request. This error type focuses on the +// syntactic aspects of the request. +type BadRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Describes all violations in a client request. + FieldViolations []*BadRequest_FieldViolation `protobuf:"bytes,1,rep,name=field_violations,json=fieldViolations,proto3" json:"field_violations,omitempty"` +} + +func (x *BadRequest) Reset() { + *x = BadRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_google_rpc_error_details_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BadRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BadRequest) ProtoMessage() {} + +func (x *BadRequest) ProtoReflect() protoreflect.Message { + mi := &file_google_rpc_error_details_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BadRequest.ProtoReflect.Descriptor instead. +func (*BadRequest) Descriptor() ([]byte, []int) { + return file_google_rpc_error_details_proto_rawDescGZIP(), []int{5} +} + +func (x *BadRequest) GetFieldViolations() []*BadRequest_FieldViolation { + if x != nil { + return x.FieldViolations + } + return nil +} + +// Contains metadata about the request that clients can attach when filing a bug +// or providing other forms of feedback. +type RequestInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // An opaque string that should only be interpreted by the service generating + // it. For example, it can be used to identify requests in the service's logs. + RequestId string `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"` + // Any data that was used to serve this request. For example, an encrypted + // stack trace that can be sent back to the service provider for debugging. + ServingData string `protobuf:"bytes,2,opt,name=serving_data,json=servingData,proto3" json:"serving_data,omitempty"` +} + +func (x *RequestInfo) Reset() { + *x = RequestInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_google_rpc_error_details_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RequestInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RequestInfo) ProtoMessage() {} + +func (x *RequestInfo) ProtoReflect() protoreflect.Message { + mi := &file_google_rpc_error_details_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RequestInfo.ProtoReflect.Descriptor instead. +func (*RequestInfo) Descriptor() ([]byte, []int) { + return file_google_rpc_error_details_proto_rawDescGZIP(), []int{6} +} + +func (x *RequestInfo) GetRequestId() string { + if x != nil { + return x.RequestId + } + return "" +} + +func (x *RequestInfo) GetServingData() string { + if x != nil { + return x.ServingData + } + return "" +} + +// Describes the resource that is being accessed. +type ResourceInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // A name for the type of resource being accessed, e.g. "sql table", + // "cloud storage bucket", "file", "Google calendar"; or the type URL + // of the resource: e.g. "type.googleapis.com/google.pubsub.v1.Topic". + ResourceType string `protobuf:"bytes,1,opt,name=resource_type,json=resourceType,proto3" json:"resource_type,omitempty"` + // The name of the resource being accessed. For example, a shared calendar + // name: "example.com_4fghdhgsrgh@group.calendar.google.com", if the current + // error is + // [google.rpc.Code.PERMISSION_DENIED][google.rpc.Code.PERMISSION_DENIED]. + ResourceName string `protobuf:"bytes,2,opt,name=resource_name,json=resourceName,proto3" json:"resource_name,omitempty"` + // The owner of the resource (optional). + // For example, "user:" or "project:". + Owner string `protobuf:"bytes,3,opt,name=owner,proto3" json:"owner,omitempty"` + // Describes what error is encountered when accessing this resource. + // For example, updating a cloud project may require the `writer` permission + // on the developer console project. + Description string `protobuf:"bytes,4,opt,name=description,proto3" json:"description,omitempty"` +} + +func (x *ResourceInfo) Reset() { + *x = ResourceInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_google_rpc_error_details_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ResourceInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ResourceInfo) ProtoMessage() {} + +func (x *ResourceInfo) ProtoReflect() protoreflect.Message { + mi := &file_google_rpc_error_details_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ResourceInfo.ProtoReflect.Descriptor instead. +func (*ResourceInfo) Descriptor() ([]byte, []int) { + return file_google_rpc_error_details_proto_rawDescGZIP(), []int{7} +} + +func (x *ResourceInfo) GetResourceType() string { + if x != nil { + return x.ResourceType + } + return "" +} + +func (x *ResourceInfo) GetResourceName() string { + if x != nil { + return x.ResourceName + } + return "" +} + +func (x *ResourceInfo) GetOwner() string { + if x != nil { + return x.Owner + } + return "" +} + +func (x *ResourceInfo) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +// Provides links to documentation or for performing an out of band action. +// +// For example, if a quota check failed with an error indicating the calling +// project hasn't enabled the accessed service, this can contain a URL pointing +// directly to the right place in the developer console to flip the bit. +type Help struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // URL(s) pointing to additional information on handling the current error. + Links []*Help_Link `protobuf:"bytes,1,rep,name=links,proto3" json:"links,omitempty"` +} + +func (x *Help) Reset() { + *x = Help{} + if protoimpl.UnsafeEnabled { + mi := &file_google_rpc_error_details_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Help) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Help) ProtoMessage() {} + +func (x *Help) ProtoReflect() protoreflect.Message { + mi := &file_google_rpc_error_details_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Help.ProtoReflect.Descriptor instead. +func (*Help) Descriptor() ([]byte, []int) { + return file_google_rpc_error_details_proto_rawDescGZIP(), []int{8} +} + +func (x *Help) GetLinks() []*Help_Link { + if x != nil { + return x.Links + } + return nil +} + +// Provides a localized error message that is safe to return to the user +// which can be attached to an RPC error. +type LocalizedMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The locale used following the specification defined at + // https://www.rfc-editor.org/rfc/bcp/bcp47.txt. + // Examples are: "en-US", "fr-CH", "es-MX" + Locale string `protobuf:"bytes,1,opt,name=locale,proto3" json:"locale,omitempty"` + // The localized error message in the above locale. + Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` +} + +func (x *LocalizedMessage) Reset() { + *x = LocalizedMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_google_rpc_error_details_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LocalizedMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LocalizedMessage) ProtoMessage() {} + +func (x *LocalizedMessage) ProtoReflect() protoreflect.Message { + mi := &file_google_rpc_error_details_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LocalizedMessage.ProtoReflect.Descriptor instead. +func (*LocalizedMessage) Descriptor() ([]byte, []int) { + return file_google_rpc_error_details_proto_rawDescGZIP(), []int{9} +} + +func (x *LocalizedMessage) GetLocale() string { + if x != nil { + return x.Locale + } + return "" +} + +func (x *LocalizedMessage) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +// A message type used to describe a single quota violation. For example, a +// daily quota or a custom quota that was exceeded. +type QuotaFailure_Violation struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The subject on which the quota check failed. + // For example, "clientip:" or "project:". + Subject string `protobuf:"bytes,1,opt,name=subject,proto3" json:"subject,omitempty"` + // A description of how the quota check failed. Clients can use this + // description to find more about the quota configuration in the service's + // public documentation, or find the relevant quota limit to adjust through + // developer console. + // + // For example: "Service disabled" or "Daily Limit for read operations + // exceeded". + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` +} + +func (x *QuotaFailure_Violation) Reset() { + *x = QuotaFailure_Violation{} + if protoimpl.UnsafeEnabled { + mi := &file_google_rpc_error_details_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *QuotaFailure_Violation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QuotaFailure_Violation) ProtoMessage() {} + +func (x *QuotaFailure_Violation) ProtoReflect() protoreflect.Message { + mi := &file_google_rpc_error_details_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use QuotaFailure_Violation.ProtoReflect.Descriptor instead. +func (*QuotaFailure_Violation) Descriptor() ([]byte, []int) { + return file_google_rpc_error_details_proto_rawDescGZIP(), []int{3, 0} +} + +func (x *QuotaFailure_Violation) GetSubject() string { + if x != nil { + return x.Subject + } + return "" +} + +func (x *QuotaFailure_Violation) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +// A message type used to describe a single precondition failure. +type PreconditionFailure_Violation struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The type of PreconditionFailure. We recommend using a service-specific + // enum type to define the supported precondition violation subjects. For + // example, "TOS" for "Terms of Service violation". + Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` + // The subject, relative to the type, that failed. + // For example, "google.com/cloud" relative to the "TOS" type would indicate + // which terms of service is being referenced. + Subject string `protobuf:"bytes,2,opt,name=subject,proto3" json:"subject,omitempty"` + // A description of how the precondition failed. Developers can use this + // description to understand how to fix the failure. + // + // For example: "Terms of service not accepted". + Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` +} + +func (x *PreconditionFailure_Violation) Reset() { + *x = PreconditionFailure_Violation{} + if protoimpl.UnsafeEnabled { + mi := &file_google_rpc_error_details_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PreconditionFailure_Violation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PreconditionFailure_Violation) ProtoMessage() {} + +func (x *PreconditionFailure_Violation) ProtoReflect() protoreflect.Message { + mi := &file_google_rpc_error_details_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PreconditionFailure_Violation.ProtoReflect.Descriptor instead. +func (*PreconditionFailure_Violation) Descriptor() ([]byte, []int) { + return file_google_rpc_error_details_proto_rawDescGZIP(), []int{4, 0} +} + +func (x *PreconditionFailure_Violation) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *PreconditionFailure_Violation) GetSubject() string { + if x != nil { + return x.Subject + } + return "" +} + +func (x *PreconditionFailure_Violation) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +// A message type used to describe a single bad request field. +type BadRequest_FieldViolation struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // A path that leads to a field in the request body. The value will be a + // sequence of dot-separated identifiers that identify a protocol buffer + // field. + // + // Consider the following: + // + // message CreateContactRequest { + // message EmailAddress { + // enum Type { + // TYPE_UNSPECIFIED = 0; + // HOME = 1; + // WORK = 2; + // } + // + // optional string email = 1; + // repeated EmailType type = 2; + // } + // + // string full_name = 1; + // repeated EmailAddress email_addresses = 2; + // } + // + // In this example, in proto `field` could take one of the following values: + // + // - `full_name` for a violation in the `full_name` value + // - `email_addresses[1].email` for a violation in the `email` field of the + // first `email_addresses` message + // - `email_addresses[3].type[2]` for a violation in the second `type` + // value in the third `email_addresses` message. + // + // In JSON, the same values are represented as: + // + // - `fullName` for a violation in the `fullName` value + // - `emailAddresses[1].email` for a violation in the `email` field of the + // first `emailAddresses` message + // - `emailAddresses[3].type[2]` for a violation in the second `type` + // value in the third `emailAddresses` message. + Field string `protobuf:"bytes,1,opt,name=field,proto3" json:"field,omitempty"` + // A description of why the request element is bad. + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` +} + +func (x *BadRequest_FieldViolation) Reset() { + *x = BadRequest_FieldViolation{} + if protoimpl.UnsafeEnabled { + mi := &file_google_rpc_error_details_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BadRequest_FieldViolation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BadRequest_FieldViolation) ProtoMessage() {} + +func (x *BadRequest_FieldViolation) ProtoReflect() protoreflect.Message { + mi := &file_google_rpc_error_details_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BadRequest_FieldViolation.ProtoReflect.Descriptor instead. +func (*BadRequest_FieldViolation) Descriptor() ([]byte, []int) { + return file_google_rpc_error_details_proto_rawDescGZIP(), []int{5, 0} +} + +func (x *BadRequest_FieldViolation) GetField() string { + if x != nil { + return x.Field + } + return "" +} + +func (x *BadRequest_FieldViolation) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +// Describes a URL link. +type Help_Link struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Describes what the link offers. + Description string `protobuf:"bytes,1,opt,name=description,proto3" json:"description,omitempty"` + // The URL of the link. + Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` +} + +func (x *Help_Link) Reset() { + *x = Help_Link{} + if protoimpl.UnsafeEnabled { + mi := &file_google_rpc_error_details_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Help_Link) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Help_Link) ProtoMessage() {} + +func (x *Help_Link) ProtoReflect() protoreflect.Message { + mi := &file_google_rpc_error_details_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Help_Link.ProtoReflect.Descriptor instead. +func (*Help_Link) Descriptor() ([]byte, []int) { + return file_google_rpc_error_details_proto_rawDescGZIP(), []int{8, 0} +} + +func (x *Help_Link) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *Help_Link) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +var File_google_rpc_error_details_proto protoreflect.FileDescriptor + +var file_google_rpc_error_details_proto_rawDesc = []byte{ + 0x0a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x65, 0x72, 0x72, + 0x6f, 0x72, 0x5f, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x12, 0x0a, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x72, 0x70, 0x63, 0x1a, 0x1e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x75, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb9, 0x01, 0x0a, + 0x09, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, + 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, + 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x3f, 0x0a, 0x08, 0x6d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x49, + 0x6e, 0x66, 0x6f, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, + 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, + 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x47, 0x0a, 0x09, 0x52, 0x65, 0x74, 0x72, + 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3a, 0x0a, 0x0b, 0x72, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x64, + 0x65, 0x6c, 0x61, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x72, 0x65, 0x74, 0x72, 0x79, 0x44, 0x65, 0x6c, 0x61, + 0x79, 0x22, 0x48, 0x0a, 0x09, 0x44, 0x65, 0x62, 0x75, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x23, + 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x5f, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x45, 0x6e, 0x74, 0x72, + 0x69, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x22, 0x9b, 0x01, 0x0a, 0x0c, + 0x51, 0x75, 0x6f, 0x74, 0x61, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x12, 0x42, 0x0a, 0x0a, + 0x76, 0x69, 0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, + 0x6f, 0x74, 0x61, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x2e, 0x56, 0x69, 0x6f, 0x6c, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x76, 0x69, 0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x1a, 0x47, 0x0a, 0x09, 0x56, 0x69, 0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, + 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xbd, 0x01, 0x0a, 0x13, 0x50, 0x72, + 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, + 0x65, 0x12, 0x49, 0x0a, 0x0a, 0x76, 0x69, 0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x72, + 0x70, 0x63, 0x2e, 0x50, 0x72, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x46, + 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x2e, 0x56, 0x69, 0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x0a, 0x76, 0x69, 0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x5b, 0x0a, 0x09, + 0x56, 0x69, 0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, + 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xa8, 0x01, 0x0a, 0x0a, 0x42, 0x61, + 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x50, 0x0a, 0x10, 0x66, 0x69, 0x65, 0x6c, + 0x64, 0x5f, 0x76, 0x69, 0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x72, 0x70, 0x63, 0x2e, + 0x42, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, + 0x56, 0x69, 0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0f, 0x66, 0x69, 0x65, 0x6c, 0x64, + 0x56, 0x69, 0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x48, 0x0a, 0x0e, 0x46, 0x69, + 0x65, 0x6c, 0x64, 0x56, 0x69, 0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, + 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x66, 0x69, 0x65, + 0x6c, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x4f, 0x0a, 0x0b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, + 0x6e, 0x66, 0x6f, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x61, + 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x6e, + 0x67, 0x44, 0x61, 0x74, 0x61, 0x22, 0x90, 0x01, 0x0a, 0x0c, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, + 0x12, 0x14, 0x0a, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x6f, 0x0a, 0x04, 0x48, 0x65, 0x6c, 0x70, + 0x12, 0x2b, 0x0a, 0x05, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x15, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x48, 0x65, 0x6c, + 0x70, 0x2e, 0x4c, 0x69, 0x6e, 0x6b, 0x52, 0x05, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x1a, 0x3a, 0x0a, + 0x04, 0x4c, 0x69, 0x6e, 0x6b, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x22, 0x44, 0x0a, 0x10, 0x4c, 0x6f, 0x63, + 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x16, 0x0a, + 0x06, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6c, + 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, + 0x6c, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x72, 0x70, + 0x63, 0x42, 0x11, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x50, + 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, + 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x65, 0x6e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x72, 0x70, + 0x63, 0x2f, 0x65, 0x72, 0x72, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x3b, 0x65, 0x72, 0x72, + 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0xa2, 0x02, 0x03, 0x52, 0x50, 0x43, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_google_rpc_error_details_proto_rawDescOnce sync.Once + file_google_rpc_error_details_proto_rawDescData = file_google_rpc_error_details_proto_rawDesc +) + +func file_google_rpc_error_details_proto_rawDescGZIP() []byte { + file_google_rpc_error_details_proto_rawDescOnce.Do(func() { + file_google_rpc_error_details_proto_rawDescData = protoimpl.X.CompressGZIP(file_google_rpc_error_details_proto_rawDescData) + }) + return file_google_rpc_error_details_proto_rawDescData +} + +var file_google_rpc_error_details_proto_msgTypes = make([]protoimpl.MessageInfo, 15) +var file_google_rpc_error_details_proto_goTypes = []interface{}{ + (*ErrorInfo)(nil), // 0: google.rpc.ErrorInfo + (*RetryInfo)(nil), // 1: google.rpc.RetryInfo + (*DebugInfo)(nil), // 2: google.rpc.DebugInfo + (*QuotaFailure)(nil), // 3: google.rpc.QuotaFailure + (*PreconditionFailure)(nil), // 4: google.rpc.PreconditionFailure + (*BadRequest)(nil), // 5: google.rpc.BadRequest + (*RequestInfo)(nil), // 6: google.rpc.RequestInfo + (*ResourceInfo)(nil), // 7: google.rpc.ResourceInfo + (*Help)(nil), // 8: google.rpc.Help + (*LocalizedMessage)(nil), // 9: google.rpc.LocalizedMessage + nil, // 10: google.rpc.ErrorInfo.MetadataEntry + (*QuotaFailure_Violation)(nil), // 11: google.rpc.QuotaFailure.Violation + (*PreconditionFailure_Violation)(nil), // 12: google.rpc.PreconditionFailure.Violation + (*BadRequest_FieldViolation)(nil), // 13: google.rpc.BadRequest.FieldViolation + (*Help_Link)(nil), // 14: google.rpc.Help.Link + (*durationpb.Duration)(nil), // 15: google.protobuf.Duration +} +var file_google_rpc_error_details_proto_depIdxs = []int32{ + 10, // 0: google.rpc.ErrorInfo.metadata:type_name -> google.rpc.ErrorInfo.MetadataEntry + 15, // 1: google.rpc.RetryInfo.retry_delay:type_name -> google.protobuf.Duration + 11, // 2: google.rpc.QuotaFailure.violations:type_name -> google.rpc.QuotaFailure.Violation + 12, // 3: google.rpc.PreconditionFailure.violations:type_name -> google.rpc.PreconditionFailure.Violation + 13, // 4: google.rpc.BadRequest.field_violations:type_name -> google.rpc.BadRequest.FieldViolation + 14, // 5: google.rpc.Help.links:type_name -> google.rpc.Help.Link + 6, // [6:6] is the sub-list for method output_type + 6, // [6:6] is the sub-list for method input_type + 6, // [6:6] is the sub-list for extension type_name + 6, // [6:6] is the sub-list for extension extendee + 0, // [0:6] is the sub-list for field type_name +} + +func init() { file_google_rpc_error_details_proto_init() } +func file_google_rpc_error_details_proto_init() { + if File_google_rpc_error_details_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_google_rpc_error_details_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ErrorInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_rpc_error_details_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RetryInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_rpc_error_details_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DebugInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_rpc_error_details_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*QuotaFailure); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_rpc_error_details_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PreconditionFailure); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_rpc_error_details_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BadRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_rpc_error_details_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RequestInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_rpc_error_details_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ResourceInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_rpc_error_details_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Help); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_rpc_error_details_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LocalizedMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_rpc_error_details_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*QuotaFailure_Violation); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_rpc_error_details_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PreconditionFailure_Violation); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_rpc_error_details_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BadRequest_FieldViolation); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_google_rpc_error_details_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Help_Link); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_google_rpc_error_details_proto_rawDesc, + NumEnums: 0, + NumMessages: 15, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_google_rpc_error_details_proto_goTypes, + DependencyIndexes: file_google_rpc_error_details_proto_depIdxs, + MessageInfos: file_google_rpc_error_details_proto_msgTypes, + }.Build() + File_google_rpc_error_details_proto = out.File + file_google_rpc_error_details_proto_rawDesc = nil + file_google_rpc_error_details_proto_goTypes = nil + file_google_rpc_error_details_proto_depIdxs = nil +} diff --git a/vendor/google.golang.org/genproto/googleapis/rpc/status/status.pb.go b/vendor/google.golang.org/genproto/googleapis/rpc/status/status.pb.go index e79a5388465..a6b5081888b 100644 --- a/vendor/google.golang.org/genproto/googleapis/rpc/status/status.pb.go +++ b/vendor/google.golang.org/genproto/googleapis/rpc/status/status.pb.go @@ -1,4 +1,4 @@ -// Copyright 2020 Google LLC +// Copyright 2022 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -14,8 +14,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.25.0 -// protoc v3.13.0 +// protoc-gen-go v1.26.0 +// protoc v3.21.9 // source: google/rpc/status.proto package status @@ -24,7 +24,6 @@ import ( reflect "reflect" sync "sync" - proto "github.com/golang/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" anypb "google.golang.org/protobuf/types/known/anypb" @@ -37,10 +36,6 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - // The `Status` type defines a logical error model that is suitable for // different programming environments, including REST APIs and RPC APIs. It is // used by [gRPC](https://github.com/grpc). Each `Status` message contains @@ -53,11 +48,13 @@ type Status struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]. + // The status code, which should be an enum value of + // [google.rpc.Code][google.rpc.Code]. Code int32 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"` // A developer-facing error message, which should be in English. Any // user-facing error message should be localized and sent in the - // [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client. + // [google.rpc.Status.details][google.rpc.Status.details] field, or localized + // by the client. Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` // A list of messages that carry the error details. There is a common set of // message types for APIs to use. diff --git a/vendor/google.golang.org/genproto/googleapis/type/date/date.pb.go b/vendor/google.golang.org/genproto/googleapis/type/date/date.pb.go new file mode 100644 index 00000000000..72afd8b000e --- /dev/null +++ b/vendor/google.golang.org/genproto/googleapis/type/date/date.pb.go @@ -0,0 +1,200 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.26.0 +// protoc v3.12.2 +// source: google/type/date.proto + +package date + +import ( + reflect "reflect" + sync "sync" + + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// Represents a whole or partial calendar date, such as a birthday. The time of +// day and time zone are either specified elsewhere or are insignificant. The +// date is relative to the Gregorian Calendar. This can represent one of the +// following: +// +// * A full date, with non-zero year, month, and day values +// * A month and day value, with a zero year, such as an anniversary +// * A year on its own, with zero month and day values +// * A year and month value, with a zero day, such as a credit card expiration +// date +// +// Related types are [google.type.TimeOfDay][google.type.TimeOfDay] and +// `google.protobuf.Timestamp`. +type Date struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Year of the date. Must be from 1 to 9999, or 0 to specify a date without + // a year. + Year int32 `protobuf:"varint,1,opt,name=year,proto3" json:"year,omitempty"` + // Month of a year. Must be from 1 to 12, or 0 to specify a year without a + // month and day. + Month int32 `protobuf:"varint,2,opt,name=month,proto3" json:"month,omitempty"` + // Day of a month. Must be from 1 to 31 and valid for the year and month, or 0 + // to specify a year by itself or a year and month where the day isn't + // significant. + Day int32 `protobuf:"varint,3,opt,name=day,proto3" json:"day,omitempty"` +} + +func (x *Date) Reset() { + *x = Date{} + if protoimpl.UnsafeEnabled { + mi := &file_google_type_date_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Date) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Date) ProtoMessage() {} + +func (x *Date) ProtoReflect() protoreflect.Message { + mi := &file_google_type_date_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Date.ProtoReflect.Descriptor instead. +func (*Date) Descriptor() ([]byte, []int) { + return file_google_type_date_proto_rawDescGZIP(), []int{0} +} + +func (x *Date) GetYear() int32 { + if x != nil { + return x.Year + } + return 0 +} + +func (x *Date) GetMonth() int32 { + if x != nil { + return x.Month + } + return 0 +} + +func (x *Date) GetDay() int32 { + if x != nil { + return x.Day + } + return 0 +} + +var File_google_type_date_proto protoreflect.FileDescriptor + +var file_google_type_date_proto_rawDesc = []byte{ + 0x0a, 0x16, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x2f, 0x64, 0x61, + 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x74, 0x79, 0x70, 0x65, 0x22, 0x42, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x65, 0x12, 0x12, 0x0a, + 0x04, 0x79, 0x65, 0x61, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x79, 0x65, 0x61, + 0x72, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x6f, 0x6e, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x05, 0x6d, 0x6f, 0x6e, 0x74, 0x68, 0x12, 0x10, 0x0a, 0x03, 0x64, 0x61, 0x79, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x64, 0x61, 0x79, 0x42, 0x5d, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x42, 0x09, 0x44, 0x61, + 0x74, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x34, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x65, 0x6e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, + 0x2f, 0x74, 0x79, 0x70, 0x65, 0x2f, 0x64, 0x61, 0x74, 0x65, 0x3b, 0x64, 0x61, 0x74, 0x65, 0xf8, + 0x01, 0x01, 0xa2, 0x02, 0x03, 0x47, 0x54, 0x50, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_google_type_date_proto_rawDescOnce sync.Once + file_google_type_date_proto_rawDescData = file_google_type_date_proto_rawDesc +) + +func file_google_type_date_proto_rawDescGZIP() []byte { + file_google_type_date_proto_rawDescOnce.Do(func() { + file_google_type_date_proto_rawDescData = protoimpl.X.CompressGZIP(file_google_type_date_proto_rawDescData) + }) + return file_google_type_date_proto_rawDescData +} + +var file_google_type_date_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_google_type_date_proto_goTypes = []interface{}{ + (*Date)(nil), // 0: google.type.Date +} +var file_google_type_date_proto_depIdxs = []int32{ + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_google_type_date_proto_init() } +func file_google_type_date_proto_init() { + if File_google_type_date_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_google_type_date_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Date); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_google_type_date_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_google_type_date_proto_goTypes, + DependencyIndexes: file_google_type_date_proto_depIdxs, + MessageInfos: file_google_type_date_proto_msgTypes, + }.Build() + File_google_type_date_proto = out.File + file_google_type_date_proto_rawDesc = nil + file_google_type_date_proto_goTypes = nil + file_google_type_date_proto_depIdxs = nil +} diff --git a/vendor/google.golang.org/genproto/googleapis/type/expr/expr.pb.go b/vendor/google.golang.org/genproto/googleapis/type/expr/expr.pb.go index 8d283a3c1ea..38ef56f73ca 100644 --- a/vendor/google.golang.org/genproto/googleapis/type/expr/expr.pb.go +++ b/vendor/google.golang.org/genproto/googleapis/type/expr/expr.pb.go @@ -1,4 +1,4 @@ -// Copyright 2020 Google LLC +// Copyright 2021 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -14,8 +14,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.25.0 -// protoc v3.13.0 +// protoc-gen-go v1.26.0 +// protoc v3.12.2 // source: google/type/expr.proto package expr @@ -24,7 +24,6 @@ import ( reflect "reflect" sync "sync" - proto "github.com/golang/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" ) @@ -36,37 +35,33 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - // Represents a textual expression in the Common Expression Language (CEL) // syntax. CEL is a C-like expression language. The syntax and semantics of CEL // are documented at https://github.com/google/cel-spec. // // Example (Comparison): // -// title: "Summary size limit" -// description: "Determines if a summary is less than 100 chars" -// expression: "document.summary.size() < 100" +// title: "Summary size limit" +// description: "Determines if a summary is less than 100 chars" +// expression: "document.summary.size() < 100" // // Example (Equality): // -// title: "Requestor is owner" -// description: "Determines if requestor is the document owner" -// expression: "document.owner == request.auth.claims.email" +// title: "Requestor is owner" +// description: "Determines if requestor is the document owner" +// expression: "document.owner == request.auth.claims.email" // // Example (Logic): // -// title: "Public documents" -// description: "Determine whether the document should be publicly visible" -// expression: "document.type != 'private' && document.type != 'internal'" +// title: "Public documents" +// description: "Determine whether the document should be publicly visible" +// expression: "document.type != 'private' && document.type != 'internal'" // // Example (Data Manipulation): // -// title: "Notification string" -// description: "Create a notification string with a timestamp." -// expression: "'New message received at ' + string(document.create_time)" +// title: "Notification string" +// description: "Create a notification string with a timestamp." +// expression: "'New message received at ' + string(document.create_time)" // // The exact variables and functions that may be referenced within an expression // are determined by the service that evaluates it. See the service diff --git a/vendor/google.golang.org/grpc/.travis.yml b/vendor/google.golang.org/grpc/.travis.yml deleted file mode 100644 index 5847d94e551..00000000000 --- a/vendor/google.golang.org/grpc/.travis.yml +++ /dev/null @@ -1,42 +0,0 @@ -language: go - -matrix: - include: - - go: 1.14.x - env: VET=1 GO111MODULE=on - - go: 1.14.x - env: RACE=1 GO111MODULE=on - - go: 1.14.x - env: RUN386=1 - - go: 1.14.x - env: GRPC_GO_RETRY=on - - go: 1.14.x - env: TESTEXTRAS=1 - - go: 1.13.x - env: GO111MODULE=on - - go: 1.12.x - env: GO111MODULE=on - - go: 1.11.x # Keep until interop tests no longer require Go1.11 - env: GO111MODULE=on - -go_import_path: google.golang.org/grpc - -before_install: - - if [[ "${GO111MODULE}" = "on" ]]; then mkdir "${HOME}/go"; export GOPATH="${HOME}/go"; fi - - if [[ -n "${RUN386}" ]]; then export GOARCH=386; fi - - if [[ "${TRAVIS_EVENT_TYPE}" = "cron" && -z "${RUN386}" ]]; then RACE=1; fi - - if [[ "${TRAVIS_EVENT_TYPE}" != "cron" ]]; then export VET_SKIP_PROTO=1; fi - -install: - - try3() { eval "$*" || eval "$*" || eval "$*"; } - - try3 'if [[ "${GO111MODULE}" = "on" ]]; then go mod download; else make testdeps; fi' - - if [[ -n "${GAE}" ]]; then source ./install_gae.sh; make testappenginedeps; fi - - if [[ -n "${VET}" ]]; then ./vet.sh -install; fi - -script: - - set -e - - if [[ -n "${TESTEXTRAS}" ]]; then examples/examples_test.sh; security/advancedtls/examples/examples_test.sh; interop/interop_test.sh; make testsubmodule; exit 0; fi - - if [[ -n "${VET}" ]]; then ./vet.sh; fi - - if [[ -n "${GAE}" ]]; then make testappengine; exit 0; fi - - if [[ -n "${RACE}" ]]; then make testrace; exit 0; fi - - make test diff --git a/vendor/google.golang.org/grpc/CONTRIBUTING.md b/vendor/google.golang.org/grpc/CONTRIBUTING.md index cd03f8c7688..608aa6e1ac5 100644 --- a/vendor/google.golang.org/grpc/CONTRIBUTING.md +++ b/vendor/google.golang.org/grpc/CONTRIBUTING.md @@ -20,6 +20,15 @@ How to get your contributions merged smoothly and quickly. both author's & review's time is wasted. Create more PRs to address different concerns and everyone will be happy. +- If you are searching for features to work on, issues labeled [Status: Help + Wanted](https://github.com/grpc/grpc-go/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22Status%3A+Help+Wanted%22) + is a great place to start. These issues are well-documented and usually can be + resolved with a single pull request. + +- If you are adding a new file, make sure it has the copyright message template + at the top as a comment. You can copy over the message from an existing file + and update the year. + - The grpc package should only depend on standard Go packages and a small number of exceptions. If your contribution introduces new dependencies which are NOT in the [list](https://godoc.org/google.golang.org/grpc?imports), you need a @@ -32,14 +41,18 @@ How to get your contributions merged smoothly and quickly. - Provide a good **PR description** as a record of **what** change is being made and **why** it was made. Link to a github issue if it exists. -- Don't fix code style and formatting unless you are already changing that line - to address an issue. PRs with irrelevant changes won't be merged. If you do - want to fix formatting or style, do that in a separate PR. +- If you want to fix formatting or style, consider whether your changes are an + obvious improvement or might be considered a personal preference. If a style + change is based on preference, it likely will not be accepted. If it corrects + widely agreed-upon anti-patterns, then please do create a PR and explain the + benefits of the change. - Unless your PR is trivial, you should expect there will be reviewer comments - that you'll need to address before merging. We expect you to be reasonably - responsive to those comments, otherwise the PR will be closed after 2-3 weeks - of inactivity. + that you'll need to address before merging. We'll mark it as `Status: Requires + Reporter Clarification` if we expect you to respond to these comments in a + timely manner. If the PR remains inactive for 6 days, it will be marked as + `stale` and automatically close 7 days after that if we don't hear back from + you. - Maintain **clean commit history** and use **meaningful commit messages**. PRs with messy commit history are difficult to review and won't be merged. Use @@ -53,9 +66,8 @@ How to get your contributions merged smoothly and quickly. - **All tests need to be passing** before your change can be merged. We recommend you **run tests locally** before creating your PR to catch breakages early on. - - `make all` to test everything, OR - - `make vet` to catch vet errors - - `make test` to run the tests - - `make testrace` to run tests in race mode + - `VET_SKIP_PROTO=1 ./vet.sh` to catch vet errors + - `go test -cpu 1,4 -timeout 7m ./...` to run the tests + - `go test -race -cpu 1,4 -timeout 7m ./...` to run tests in race mode - Exceptions to the rules can be made if there's a compelling reason for doing so. diff --git a/vendor/google.golang.org/grpc/MAINTAINERS.md b/vendor/google.golang.org/grpc/MAINTAINERS.md index 093c82b3afe..c6672c0a3ef 100644 --- a/vendor/google.golang.org/grpc/MAINTAINERS.md +++ b/vendor/google.golang.org/grpc/MAINTAINERS.md @@ -8,17 +8,18 @@ See [CONTRIBUTING.md](https://github.com/grpc/grpc-community/blob/master/CONTRIB for general contribution guidelines. ## Maintainers (in alphabetical order) -- [canguler](https://github.com/canguler), Google LLC + - [cesarghali](https://github.com/cesarghali), Google LLC - [dfawley](https://github.com/dfawley), Google LLC - [easwars](https://github.com/easwars), Google LLC -- [jadekler](https://github.com/jadekler), Google LLC - [menghanl](https://github.com/menghanl), Google LLC - [srini100](https://github.com/srini100), Google LLC ## Emeritus Maintainers (in alphabetical order) - [adelez](https://github.com/adelez), Google LLC +- [canguler](https://github.com/canguler), Google LLC - [iamqizhao](https://github.com/iamqizhao), Google LLC +- [jadekler](https://github.com/jadekler), Google LLC - [jtattermusch](https://github.com/jtattermusch), Google LLC - [lyuxuan](https://github.com/lyuxuan), Google LLC - [makmukhi](https://github.com/makmukhi), Google LLC diff --git a/vendor/google.golang.org/grpc/Makefile b/vendor/google.golang.org/grpc/Makefile index 1f0722f1624..1f8960922b3 100644 --- a/vendor/google.golang.org/grpc/Makefile +++ b/vendor/google.golang.org/grpc/Makefile @@ -41,8 +41,6 @@ vetdeps: clean \ proto \ test \ - testappengine \ - testappenginedeps \ testrace \ vet \ vetdeps diff --git a/vendor/google.golang.org/grpc/NOTICE.txt b/vendor/google.golang.org/grpc/NOTICE.txt new file mode 100644 index 00000000000..530197749e9 --- /dev/null +++ b/vendor/google.golang.org/grpc/NOTICE.txt @@ -0,0 +1,13 @@ +Copyright 2014 gRPC authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/google.golang.org/grpc/README.md b/vendor/google.golang.org/grpc/README.md index 3949a683fb5..0e6ae69a584 100644 --- a/vendor/google.golang.org/grpc/README.md +++ b/vendor/google.golang.org/grpc/README.md @@ -136,6 +136,6 @@ errors. [Go module]: https://github.com/golang/go/wiki/Modules [gRPC]: https://grpc.io [Go gRPC docs]: https://grpc.io/docs/languages/go -[Performance benchmark]: https://performance-dot-grpc-testing.appspot.com/explore?dashboard=5652536396611584&widget=490377658&container=1286539696 +[Performance benchmark]: https://performance-dot-grpc-testing.appspot.com/explore?dashboard=5180705743044608 [quick start]: https://grpc.io/docs/languages/go/quickstart [go-releases]: https://golang.org/doc/devel/release.html diff --git a/vendor/google.golang.org/grpc/attributes/attributes.go b/vendor/google.golang.org/grpc/attributes/attributes.go index 3220d87be40..3efca459149 100644 --- a/vendor/google.golang.org/grpc/attributes/attributes.go +++ b/vendor/google.golang.org/grpc/attributes/attributes.go @@ -19,61 +19,112 @@ // Package attributes defines a generic key/value store used in various gRPC // components. // -// Experimental +// # Experimental // // Notice: This package is EXPERIMENTAL and may be changed or removed in a // later release. package attributes -import "fmt" +import ( + "fmt" + "strings" +) // Attributes is an immutable struct for storing and retrieving generic // key/value pairs. Keys must be hashable, and users should define their own -// types for keys. +// types for keys. Values should not be modified after they are added to an +// Attributes or if they were received from one. If values implement 'Equal(o +// interface{}) bool', it will be called by (*Attributes).Equal to determine +// whether two values with the same key should be considered equal. type Attributes struct { m map[interface{}]interface{} } -// New returns a new Attributes containing all key/value pairs in kvs. If the -// same key appears multiple times, the last value overwrites all previous -// values for that key. Panics if len(kvs) is not even. -func New(kvs ...interface{}) *Attributes { - if len(kvs)%2 != 0 { - panic(fmt.Sprintf("attributes.New called with unexpected input: len(kvs) = %v", len(kvs))) - } - a := &Attributes{m: make(map[interface{}]interface{}, len(kvs)/2)} - for i := 0; i < len(kvs)/2; i++ { - a.m[kvs[i*2]] = kvs[i*2+1] - } - return a +// New returns a new Attributes containing the key/value pair. +func New(key, value interface{}) *Attributes { + return &Attributes{m: map[interface{}]interface{}{key: value}} } -// WithValues returns a new Attributes containing all key/value pairs in a and -// kvs. Panics if len(kvs) is not even. If the same key appears multiple -// times, the last value overwrites all previous values for that key. To -// remove an existing key, use a nil value. -func (a *Attributes) WithValues(kvs ...interface{}) *Attributes { +// WithValue returns a new Attributes containing the previous keys and values +// and the new key/value pair. If the same key appears multiple times, the +// last value overwrites all previous values for that key. To remove an +// existing key, use a nil value. value should not be modified later. +func (a *Attributes) WithValue(key, value interface{}) *Attributes { if a == nil { - return New(kvs...) + return New(key, value) } - if len(kvs)%2 != 0 { - panic(fmt.Sprintf("attributes.New called with unexpected input: len(kvs) = %v", len(kvs))) - } - n := &Attributes{m: make(map[interface{}]interface{}, len(a.m)+len(kvs)/2)} + n := &Attributes{m: make(map[interface{}]interface{}, len(a.m)+1)} for k, v := range a.m { n.m[k] = v } - for i := 0; i < len(kvs)/2; i++ { - n.m[kvs[i*2]] = kvs[i*2+1] - } + n.m[key] = value return n } // Value returns the value associated with these attributes for key, or nil if -// no value is associated with key. +// no value is associated with key. The returned value should not be modified. func (a *Attributes) Value(key interface{}) interface{} { if a == nil { return nil } return a.m[key] } + +// Equal returns whether a and o are equivalent. If 'Equal(o interface{}) +// bool' is implemented for a value in the attributes, it is called to +// determine if the value matches the one stored in the other attributes. If +// Equal is not implemented, standard equality is used to determine if the two +// values are equal. Note that some types (e.g. maps) aren't comparable by +// default, so they must be wrapped in a struct, or in an alias type, with Equal +// defined. +func (a *Attributes) Equal(o *Attributes) bool { + if a == nil && o == nil { + return true + } + if a == nil || o == nil { + return false + } + if len(a.m) != len(o.m) { + return false + } + for k, v := range a.m { + ov, ok := o.m[k] + if !ok { + // o missing element of a + return false + } + if eq, ok := v.(interface{ Equal(o interface{}) bool }); ok { + if !eq.Equal(ov) { + return false + } + } else if v != ov { + // Fallback to a standard equality check if Value is unimplemented. + return false + } + } + return true +} + +// String prints the attribute map. If any key or values throughout the map +// implement fmt.Stringer, it calls that method and appends. +func (a *Attributes) String() string { + var sb strings.Builder + sb.WriteString("{") + first := true + for k, v := range a.m { + var key, val string + if str, ok := k.(interface{ String() string }); ok { + key = str.String() + } + if str, ok := v.(interface{ String() string }); ok { + val = str.String() + } + if !first { + sb.WriteString(", ") + } + sb.WriteString(fmt.Sprintf("%q: %q, ", key, val)) + first = false + } + sb.WriteString("}") + return sb.String() +} diff --git a/vendor/google.golang.org/grpc/backoff.go b/vendor/google.golang.org/grpc/backoff.go index 542594f5cc5..29475e31c97 100644 --- a/vendor/google.golang.org/grpc/backoff.go +++ b/vendor/google.golang.org/grpc/backoff.go @@ -48,7 +48,7 @@ type BackoffConfig struct { // here for more details: // https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. diff --git a/vendor/google.golang.org/grpc/balancer/balancer.go b/vendor/google.golang.org/grpc/balancer/balancer.go index 788759bde4b..8f00523c0e2 100644 --- a/vendor/google.golang.org/grpc/balancer/balancer.go +++ b/vendor/google.golang.org/grpc/balancer/balancer.go @@ -27,6 +27,7 @@ import ( "net" "strings" + "google.golang.org/grpc/channelz" "google.golang.org/grpc/connectivity" "google.golang.org/grpc/credentials" "google.golang.org/grpc/internal" @@ -75,24 +76,26 @@ func Get(name string) Builder { return nil } -// SubConn represents a gRPC sub connection. -// Each sub connection contains a list of addresses. gRPC will -// try to connect to them (in sequence), and stop trying the -// remainder once one connection is successful. +// A SubConn represents a single connection to a gRPC backend service. // -// The reconnect backoff will be applied on the list, not a single address. -// For example, try_on_all_addresses -> backoff -> try_on_all_addresses. +// Each SubConn contains a list of addresses. // -// All SubConns start in IDLE, and will not try to connect. To trigger -// the connecting, Balancers must call Connect. -// When the connection encounters an error, it will reconnect immediately. -// When the connection becomes IDLE, it will not reconnect unless Connect is -// called. +// All SubConns start in IDLE, and will not try to connect. To trigger the +// connecting, Balancers must call Connect. If a connection re-enters IDLE, +// Balancers must call Connect again to trigger a new connection attempt. // -// This interface is to be implemented by gRPC. Users should not need a -// brand new implementation of this interface. For the situations like -// testing, the new implementation should embed this interface. This allows -// gRPC to add new methods to this interface. +// gRPC will try to connect to the addresses in sequence, and stop trying the +// remainder once the first connection is successful. If an attempt to connect +// to all addresses encounters an error, the SubConn will enter +// TRANSIENT_FAILURE for a backoff period, and then transition to IDLE. +// +// Once established, if a connection is lost, the SubConn will transition +// directly to IDLE. +// +// This interface is to be implemented by gRPC. Users should not need their own +// implementation of this interface. For situations like testing, any +// implementations should embed this interface. This allows gRPC to add new +// methods to this interface. type SubConn interface { // UpdateAddresses updates the addresses used in this SubConn. // gRPC checks if currently-connected address is still in the new list. @@ -101,9 +104,17 @@ type SubConn interface { // a new connection will be created. // // This will trigger a state transition for the SubConn. + // + // Deprecated: This method is now part of the ClientConn interface and will + // eventually be removed from here. UpdateAddresses([]resolver.Address) // Connect starts the connecting for this SubConn. Connect() + // GetOrBuildProducer returns a reference to the existing Producer for this + // ProducerBuilder in this SubConn, or, if one does not currently exist, + // creates a new one and returns it. Returns a close function which must + // be called when the Producer is no longer needed. + GetOrBuildProducer(ProducerBuilder) (p Producer, close func()) } // NewSubConnOptions contains options to create new SubConn. @@ -143,6 +154,13 @@ type ClientConn interface { // RemoveSubConn removes the SubConn from ClientConn. // The SubConn will be shutdown. RemoveSubConn(SubConn) + // UpdateAddresses updates the addresses used in the passed in SubConn. + // gRPC checks if the currently connected address is still in the new list. + // If so, the connection will be kept. Else, the connection will be + // gracefully closed, and a new connection will be created. + // + // This will trigger a state transition for the SubConn. + UpdateAddresses(SubConn, []resolver.Address) // UpdateState notifies gRPC that the balancer's internal state has // changed. @@ -162,25 +180,32 @@ type ClientConn interface { // BuildOptions contains additional information for Build. type BuildOptions struct { - // DialCreds is the transport credential the Balancer implementation can - // use to dial to a remote load balancer server. The Balancer implementations - // can ignore this if it does not need to talk to another party securely. + // DialCreds is the transport credentials to use when communicating with a + // remote load balancer server. Balancer implementations which do not + // communicate with a remote load balancer server can ignore this field. DialCreds credentials.TransportCredentials - // CredsBundle is the credentials bundle that the Balancer can use. + // CredsBundle is the credentials bundle to use when communicating with a + // remote load balancer server. Balancer implementations which do not + // communicate with a remote load balancer server can ignore this field. CredsBundle credentials.Bundle - // Dialer is the custom dialer the Balancer implementation can use to dial - // to a remote load balancer server. The Balancer implementations - // can ignore this if it doesn't need to talk to remote balancer. + // Dialer is the custom dialer to use when communicating with a remote load + // balancer server. Balancer implementations which do not communicate with a + // remote load balancer server can ignore this field. Dialer func(context.Context, string) (net.Conn, error) - // ChannelzParentID is the entity parent's channelz unique identification number. - ChannelzParentID int64 + // Authority is the server name to use as part of the authentication + // handshake when communicating with a remote load balancer server. Balancer + // implementations which do not communicate with a remote load balancer + // server can ignore this field. + Authority string + // ChannelzParentID is the parent ClientConn's channelz ID. + ChannelzParentID *channelz.Identifier // CustomUserAgent is the custom user agent set on the parent ClientConn. // The balancer should set the same custom user agent if it creates a // ClientConn. CustomUserAgent string - // Target contains the parsed address info of the dial target. It is the same resolver.Target as - // passed to the resolver. - // See the documentation for the resolver.Target type for details about what it contains. + // Target contains the parsed address info of the dial target. It is the + // same resolver.Target as passed to the resolver. See the documentation for + // the resolver.Target type for details about what it contains. Target resolver.Target } @@ -224,7 +249,7 @@ type DoneInfo struct { // ServerLoad is the load received from server. It's usually sent as part of // trailing metadata. // - // The only supported type now is *orca_v1.LoadReport. + // The only supported type now is *orca_v3.LoadReport. ServerLoad interface{} } @@ -254,6 +279,14 @@ type PickResult struct { // type, Done may not be called. May be nil if the balancer does not wish // to be notified when the RPC completes. Done func(DoneInfo) + + // Metadata provides a way for LB policies to inject arbitrary per-call + // metadata. Any metadata returned here will be merged with existing + // metadata added by the client application. + // + // LB policies with child policies are responsible for propagating metadata + // injected by their children to the ClientConn, as part of Pick(). + Metadata metadata.MD } // TransientFailureError returns e. It exists for backward compatibility and @@ -316,6 +349,20 @@ type Balancer interface { Close() } +// ExitIdler is an optional interface for balancers to implement. If +// implemented, ExitIdle will be called when ClientConn.Connect is called, if +// the ClientConn is idle. If unimplemented, ClientConn.Connect will cause +// all SubConns to connect. +// +// Notice: it will be required for all balancers to implement this in a future +// release. +type ExitIdler interface { + // ExitIdle instructs the LB policy to reconnect to backends / exit the + // IDLE state, if appropriate and possible. Note that SubConns that enter + // the IDLE state will not reconnect until SubConn.Connect is called. + ExitIdle() +} + // SubConnState describes the state of a SubConn. type SubConnState struct { // ConnectivityState is the connectivity state of the SubConn. @@ -338,41 +385,20 @@ type ClientConnState struct { // problem with the provided name resolver data. var ErrBadResolverState = errors.New("bad resolver state") -// ConnectivityStateEvaluator takes the connectivity states of multiple SubConns -// and returns one aggregated connectivity state. -// -// It's not thread safe. -type ConnectivityStateEvaluator struct { - numReady uint64 // Number of addrConns in ready state. - numConnecting uint64 // Number of addrConns in connecting state. +// A ProducerBuilder is a simple constructor for a Producer. It is used by the +// SubConn to create producers when needed. +type ProducerBuilder interface { + // Build creates a Producer. The first parameter is always a + // grpc.ClientConnInterface (a type to allow creating RPCs/streams on the + // associated SubConn), but is declared as interface{} to avoid a + // dependency cycle. Should also return a close function that will be + // called when all references to the Producer have been given up. + Build(grpcClientConnInterface interface{}) (p Producer, close func()) } -// RecordTransition records state change happening in subConn and based on that -// it evaluates what aggregated state should be. -// -// - If at least one SubConn in Ready, the aggregated state is Ready; -// - Else if at least one SubConn in Connecting, the aggregated state is Connecting; -// - Else the aggregated state is TransientFailure. -// -// Idle and Shutdown are not considered. -func (cse *ConnectivityStateEvaluator) RecordTransition(oldState, newState connectivity.State) connectivity.State { - // Update counters. - for idx, state := range []connectivity.State{oldState, newState} { - updateVal := 2*uint64(idx) - 1 // -1 for oldState and +1 for new. - switch state { - case connectivity.Ready: - cse.numReady += updateVal - case connectivity.Connecting: - cse.numConnecting += updateVal - } - } - - // Evaluate. - if cse.numReady > 0 { - return connectivity.Ready - } - if cse.numConnecting > 0 { - return connectivity.Connecting - } - return connectivity.TransientFailure +// A Producer is a type shared among potentially many consumers. It is +// associated with a SubConn, and an implementation will typically contain +// other methods to provide additional functionality, e.g. configuration or +// subscription registration. +type Producer interface { } diff --git a/vendor/google.golang.org/grpc/balancer/base/balancer.go b/vendor/google.golang.org/grpc/balancer/base/balancer.go index e0d34288ccf..3929c26d31e 100644 --- a/vendor/google.golang.org/grpc/balancer/base/balancer.go +++ b/vendor/google.golang.org/grpc/balancer/base/balancer.go @@ -41,10 +41,11 @@ func (bb *baseBuilder) Build(cc balancer.ClientConn, opt balancer.BuildOptions) cc: cc, pickerBuilder: bb.pickerBuilder, - subConns: make(map[resolver.Address]balancer.SubConn), + subConns: resolver.NewAddressMap(), scStates: make(map[balancer.SubConn]connectivity.State), csEvltr: &balancer.ConnectivityStateEvaluator{}, config: bb.config, + state: connectivity.Connecting, } // Initialize picker to a picker that always returns // ErrNoSubConnAvailable, because when state of a SubConn changes, we @@ -64,7 +65,7 @@ type baseBalancer struct { csEvltr *balancer.ConnectivityStateEvaluator state connectivity.State - subConns map[resolver.Address]balancer.SubConn // `attributes` is stripped from the keys of this map (the addresses) + subConns *resolver.AddressMap scStates map[balancer.SubConn]connectivity.State picker balancer.Picker config Config @@ -75,7 +76,7 @@ type baseBalancer struct { func (b *baseBalancer) ResolverError(err error) { b.resolverErr = err - if len(b.subConns) == 0 { + if b.subConns.Len() == 0 { b.state = connectivity.TransientFailure } @@ -99,50 +100,29 @@ func (b *baseBalancer) UpdateClientConnState(s balancer.ClientConnState) error { // Successful resolution; clear resolver error and ensure we return nil. b.resolverErr = nil // addrsSet is the set converted from addrs, it's used for quick lookup of an address. - addrsSet := make(map[resolver.Address]struct{}) + addrsSet := resolver.NewAddressMap() for _, a := range s.ResolverState.Addresses { - // Strip attributes from addresses before using them as map keys. So - // that when two addresses only differ in attributes pointers (but with - // the same attribute content), they are considered the same address. - // - // Note that this doesn't handle the case where the attribute content is - // different. So if users want to set different attributes to create - // duplicate connections to the same backend, it doesn't work. This is - // fine for now, because duplicate is done by setting Metadata today. - // - // TODO: read attributes to handle duplicate connections. - aNoAttrs := a - aNoAttrs.Attributes = nil - addrsSet[aNoAttrs] = struct{}{} - if sc, ok := b.subConns[aNoAttrs]; !ok { + addrsSet.Set(a, nil) + if _, ok := b.subConns.Get(a); !ok { // a is a new address (not existing in b.subConns). - // - // When creating SubConn, the original address with attributes is - // passed through. So that connection configurations in attributes - // (like creds) will be used. sc, err := b.cc.NewSubConn([]resolver.Address{a}, balancer.NewSubConnOptions{HealthCheckEnabled: b.config.HealthCheck}) if err != nil { logger.Warningf("base.baseBalancer: failed to create new SubConn: %v", err) continue } - b.subConns[aNoAttrs] = sc + b.subConns.Set(a, sc) b.scStates[sc] = connectivity.Idle + b.csEvltr.RecordTransition(connectivity.Shutdown, connectivity.Idle) sc.Connect() - } else { - // Always update the subconn's address in case the attributes - // changed. - // - // The SubConn does a reflect.DeepEqual of the new and old - // addresses. So this is a noop if the current address is the same - // as the old one (including attributes). - sc.UpdateAddresses([]resolver.Address{a}) } } - for a, sc := range b.subConns { + for _, a := range b.subConns.Keys() { + sci, _ := b.subConns.Get(a) + sc := sci.(balancer.SubConn) // a was removed by resolver. - if _, ok := addrsSet[a]; !ok { + if _, ok := addrsSet.Get(a); !ok { b.cc.RemoveSubConn(sc) - delete(b.subConns, a) + b.subConns.Delete(a) // Keep the state of this sc in b.scStates until sc's state becomes Shutdown. // The entry will be deleted in UpdateSubConnState. } @@ -155,6 +135,9 @@ func (b *baseBalancer) UpdateClientConnState(s balancer.ClientConnState) error { b.ResolverError(errors.New("produced zero addresses")) return balancer.ErrBadResolverState } + + b.regeneratePicker() + b.cc.UpdateState(balancer.State{ConnectivityState: b.state, Picker: b.picker}) return nil } @@ -174,8 +157,8 @@ func (b *baseBalancer) mergeErrors() error { // regeneratePicker takes a snapshot of the balancer, and generates a picker // from it. The picker is -// - errPicker if the balancer is in TransientFailure, -// - built by the pickerBuilder with all READY SubConns otherwise. +// - errPicker if the balancer is in TransientFailure, +// - built by the pickerBuilder with all READY SubConns otherwise. func (b *baseBalancer) regeneratePicker() { if b.state == connectivity.TransientFailure { b.picker = NewErrPicker(b.mergeErrors()) @@ -184,7 +167,9 @@ func (b *baseBalancer) regeneratePicker() { readySCs := make(map[balancer.SubConn]SubConnInfo) // Filter out all ready SCs from full subConn map. - for addr, sc := range b.subConns { + for _, addr := range b.subConns.Keys() { + sci, _ := b.subConns.Get(addr) + sc := sci.(balancer.SubConn) if st, ok := b.scStates[sc]; ok && st == connectivity.Ready { readySCs[sc] = SubConnInfo{Address: addr} } @@ -204,10 +189,14 @@ func (b *baseBalancer) UpdateSubConnState(sc balancer.SubConn, state balancer.Su } return } - if oldS == connectivity.TransientFailure && s == connectivity.Connecting { - // Once a subconn enters TRANSIENT_FAILURE, ignore subsequent + if oldS == connectivity.TransientFailure && + (s == connectivity.Connecting || s == connectivity.Idle) { + // Once a subconn enters TRANSIENT_FAILURE, ignore subsequent IDLE or // CONNECTING transitions to prevent the aggregated state from being // always CONNECTING when many backends exist but are all down. + if s == connectivity.Idle { + sc.Connect() + } return } b.scStates[sc] = s @@ -233,7 +222,6 @@ func (b *baseBalancer) UpdateSubConnState(sc balancer.SubConn, state balancer.Su b.state == connectivity.TransientFailure { b.regeneratePicker() } - b.cc.UpdateState(balancer.State{ConnectivityState: b.state, Picker: b.picker}) } @@ -242,6 +230,11 @@ func (b *baseBalancer) UpdateSubConnState(sc balancer.SubConn, state balancer.Su func (b *baseBalancer) Close() { } +// ExitIdle is a nop because the base balancer attempts to stay connected to +// all SubConns at all times. +func (b *baseBalancer) ExitIdle() { +} + // NewErrPicker returns a Picker that always returns err on Pick(). func NewErrPicker(err error) balancer.Picker { return &errPicker{err: err} diff --git a/vendor/google.golang.org/grpc/balancer/conn_state_evaluator.go b/vendor/google.golang.org/grpc/balancer/conn_state_evaluator.go new file mode 100644 index 00000000000..c3341358109 --- /dev/null +++ b/vendor/google.golang.org/grpc/balancer/conn_state_evaluator.go @@ -0,0 +1,74 @@ +/* + * + * Copyright 2022 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package balancer + +import "google.golang.org/grpc/connectivity" + +// ConnectivityStateEvaluator takes the connectivity states of multiple SubConns +// and returns one aggregated connectivity state. +// +// It's not thread safe. +type ConnectivityStateEvaluator struct { + numReady uint64 // Number of addrConns in ready state. + numConnecting uint64 // Number of addrConns in connecting state. + numTransientFailure uint64 // Number of addrConns in transient failure state. + numIdle uint64 // Number of addrConns in idle state. +} + +// RecordTransition records state change happening in subConn and based on that +// it evaluates what aggregated state should be. +// +// - If at least one SubConn in Ready, the aggregated state is Ready; +// - Else if at least one SubConn in Connecting, the aggregated state is Connecting; +// - Else if at least one SubConn is Idle, the aggregated state is Idle; +// - Else if at least one SubConn is TransientFailure (or there are no SubConns), the aggregated state is Transient Failure. +// +// Shutdown is not considered. +func (cse *ConnectivityStateEvaluator) RecordTransition(oldState, newState connectivity.State) connectivity.State { + // Update counters. + for idx, state := range []connectivity.State{oldState, newState} { + updateVal := 2*uint64(idx) - 1 // -1 for oldState and +1 for new. + switch state { + case connectivity.Ready: + cse.numReady += updateVal + case connectivity.Connecting: + cse.numConnecting += updateVal + case connectivity.TransientFailure: + cse.numTransientFailure += updateVal + case connectivity.Idle: + cse.numIdle += updateVal + } + } + return cse.CurrentState() +} + +// CurrentState returns the current aggregate conn state by evaluating the counters +func (cse *ConnectivityStateEvaluator) CurrentState() connectivity.State { + // Evaluate. + if cse.numReady > 0 { + return connectivity.Ready + } + if cse.numConnecting > 0 { + return connectivity.Connecting + } + if cse.numIdle > 0 { + return connectivity.Idle + } + return connectivity.TransientFailure +} diff --git a/vendor/google.golang.org/grpc/balancer/grpclb/grpc_lb_v1/load_balancer.pb.go b/vendor/google.golang.org/grpc/balancer/grpclb/grpc_lb_v1/load_balancer.pb.go new file mode 100644 index 00000000000..f070878bd99 --- /dev/null +++ b/vendor/google.golang.org/grpc/balancer/grpclb/grpc_lb_v1/load_balancer.pb.go @@ -0,0 +1,957 @@ +// Copyright 2015 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// This file defines the GRPCLB LoadBalancing protocol. +// +// The canonical version of this proto can be found at +// https://github.com/grpc/grpc-proto/blob/master/grpc/lb/v1/load_balancer.proto + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.30.0 +// protoc v4.22.0 +// source: grpc/lb/v1/load_balancer.proto + +package grpc_lb_v1 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + durationpb "google.golang.org/protobuf/types/known/durationpb" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type LoadBalanceRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to LoadBalanceRequestType: + // + // *LoadBalanceRequest_InitialRequest + // *LoadBalanceRequest_ClientStats + LoadBalanceRequestType isLoadBalanceRequest_LoadBalanceRequestType `protobuf_oneof:"load_balance_request_type"` +} + +func (x *LoadBalanceRequest) Reset() { + *x = LoadBalanceRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_grpc_lb_v1_load_balancer_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LoadBalanceRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LoadBalanceRequest) ProtoMessage() {} + +func (x *LoadBalanceRequest) ProtoReflect() protoreflect.Message { + mi := &file_grpc_lb_v1_load_balancer_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LoadBalanceRequest.ProtoReflect.Descriptor instead. +func (*LoadBalanceRequest) Descriptor() ([]byte, []int) { + return file_grpc_lb_v1_load_balancer_proto_rawDescGZIP(), []int{0} +} + +func (m *LoadBalanceRequest) GetLoadBalanceRequestType() isLoadBalanceRequest_LoadBalanceRequestType { + if m != nil { + return m.LoadBalanceRequestType + } + return nil +} + +func (x *LoadBalanceRequest) GetInitialRequest() *InitialLoadBalanceRequest { + if x, ok := x.GetLoadBalanceRequestType().(*LoadBalanceRequest_InitialRequest); ok { + return x.InitialRequest + } + return nil +} + +func (x *LoadBalanceRequest) GetClientStats() *ClientStats { + if x, ok := x.GetLoadBalanceRequestType().(*LoadBalanceRequest_ClientStats); ok { + return x.ClientStats + } + return nil +} + +type isLoadBalanceRequest_LoadBalanceRequestType interface { + isLoadBalanceRequest_LoadBalanceRequestType() +} + +type LoadBalanceRequest_InitialRequest struct { + // This message should be sent on the first request to the load balancer. + InitialRequest *InitialLoadBalanceRequest `protobuf:"bytes,1,opt,name=initial_request,json=initialRequest,proto3,oneof"` +} + +type LoadBalanceRequest_ClientStats struct { + // The client stats should be periodically reported to the load balancer + // based on the duration defined in the InitialLoadBalanceResponse. + ClientStats *ClientStats `protobuf:"bytes,2,opt,name=client_stats,json=clientStats,proto3,oneof"` +} + +func (*LoadBalanceRequest_InitialRequest) isLoadBalanceRequest_LoadBalanceRequestType() {} + +func (*LoadBalanceRequest_ClientStats) isLoadBalanceRequest_LoadBalanceRequestType() {} + +type InitialLoadBalanceRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The name of the load balanced service (e.g., service.googleapis.com). Its + // length should be less than 256 bytes. + // The name might include a port number. How to handle the port number is up + // to the balancer. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` +} + +func (x *InitialLoadBalanceRequest) Reset() { + *x = InitialLoadBalanceRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_grpc_lb_v1_load_balancer_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *InitialLoadBalanceRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InitialLoadBalanceRequest) ProtoMessage() {} + +func (x *InitialLoadBalanceRequest) ProtoReflect() protoreflect.Message { + mi := &file_grpc_lb_v1_load_balancer_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InitialLoadBalanceRequest.ProtoReflect.Descriptor instead. +func (*InitialLoadBalanceRequest) Descriptor() ([]byte, []int) { + return file_grpc_lb_v1_load_balancer_proto_rawDescGZIP(), []int{1} +} + +func (x *InitialLoadBalanceRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +// Contains the number of calls finished for a particular load balance token. +type ClientStatsPerToken struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // See Server.load_balance_token. + LoadBalanceToken string `protobuf:"bytes,1,opt,name=load_balance_token,json=loadBalanceToken,proto3" json:"load_balance_token,omitempty"` + // The total number of RPCs that finished associated with the token. + NumCalls int64 `protobuf:"varint,2,opt,name=num_calls,json=numCalls,proto3" json:"num_calls,omitempty"` +} + +func (x *ClientStatsPerToken) Reset() { + *x = ClientStatsPerToken{} + if protoimpl.UnsafeEnabled { + mi := &file_grpc_lb_v1_load_balancer_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ClientStatsPerToken) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ClientStatsPerToken) ProtoMessage() {} + +func (x *ClientStatsPerToken) ProtoReflect() protoreflect.Message { + mi := &file_grpc_lb_v1_load_balancer_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ClientStatsPerToken.ProtoReflect.Descriptor instead. +func (*ClientStatsPerToken) Descriptor() ([]byte, []int) { + return file_grpc_lb_v1_load_balancer_proto_rawDescGZIP(), []int{2} +} + +func (x *ClientStatsPerToken) GetLoadBalanceToken() string { + if x != nil { + return x.LoadBalanceToken + } + return "" +} + +func (x *ClientStatsPerToken) GetNumCalls() int64 { + if x != nil { + return x.NumCalls + } + return 0 +} + +// Contains client level statistics that are useful to load balancing. Each +// count except the timestamp should be reset to zero after reporting the stats. +type ClientStats struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The timestamp of generating the report. + Timestamp *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + // The total number of RPCs that started. + NumCallsStarted int64 `protobuf:"varint,2,opt,name=num_calls_started,json=numCallsStarted,proto3" json:"num_calls_started,omitempty"` + // The total number of RPCs that finished. + NumCallsFinished int64 `protobuf:"varint,3,opt,name=num_calls_finished,json=numCallsFinished,proto3" json:"num_calls_finished,omitempty"` + // The total number of RPCs that failed to reach a server except dropped RPCs. + NumCallsFinishedWithClientFailedToSend int64 `protobuf:"varint,6,opt,name=num_calls_finished_with_client_failed_to_send,json=numCallsFinishedWithClientFailedToSend,proto3" json:"num_calls_finished_with_client_failed_to_send,omitempty"` + // The total number of RPCs that finished and are known to have been received + // by a server. + NumCallsFinishedKnownReceived int64 `protobuf:"varint,7,opt,name=num_calls_finished_known_received,json=numCallsFinishedKnownReceived,proto3" json:"num_calls_finished_known_received,omitempty"` + // The list of dropped calls. + CallsFinishedWithDrop []*ClientStatsPerToken `protobuf:"bytes,8,rep,name=calls_finished_with_drop,json=callsFinishedWithDrop,proto3" json:"calls_finished_with_drop,omitempty"` +} + +func (x *ClientStats) Reset() { + *x = ClientStats{} + if protoimpl.UnsafeEnabled { + mi := &file_grpc_lb_v1_load_balancer_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ClientStats) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ClientStats) ProtoMessage() {} + +func (x *ClientStats) ProtoReflect() protoreflect.Message { + mi := &file_grpc_lb_v1_load_balancer_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ClientStats.ProtoReflect.Descriptor instead. +func (*ClientStats) Descriptor() ([]byte, []int) { + return file_grpc_lb_v1_load_balancer_proto_rawDescGZIP(), []int{3} +} + +func (x *ClientStats) GetTimestamp() *timestamppb.Timestamp { + if x != nil { + return x.Timestamp + } + return nil +} + +func (x *ClientStats) GetNumCallsStarted() int64 { + if x != nil { + return x.NumCallsStarted + } + return 0 +} + +func (x *ClientStats) GetNumCallsFinished() int64 { + if x != nil { + return x.NumCallsFinished + } + return 0 +} + +func (x *ClientStats) GetNumCallsFinishedWithClientFailedToSend() int64 { + if x != nil { + return x.NumCallsFinishedWithClientFailedToSend + } + return 0 +} + +func (x *ClientStats) GetNumCallsFinishedKnownReceived() int64 { + if x != nil { + return x.NumCallsFinishedKnownReceived + } + return 0 +} + +func (x *ClientStats) GetCallsFinishedWithDrop() []*ClientStatsPerToken { + if x != nil { + return x.CallsFinishedWithDrop + } + return nil +} + +type LoadBalanceResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to LoadBalanceResponseType: + // + // *LoadBalanceResponse_InitialResponse + // *LoadBalanceResponse_ServerList + // *LoadBalanceResponse_FallbackResponse + LoadBalanceResponseType isLoadBalanceResponse_LoadBalanceResponseType `protobuf_oneof:"load_balance_response_type"` +} + +func (x *LoadBalanceResponse) Reset() { + *x = LoadBalanceResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_grpc_lb_v1_load_balancer_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LoadBalanceResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LoadBalanceResponse) ProtoMessage() {} + +func (x *LoadBalanceResponse) ProtoReflect() protoreflect.Message { + mi := &file_grpc_lb_v1_load_balancer_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LoadBalanceResponse.ProtoReflect.Descriptor instead. +func (*LoadBalanceResponse) Descriptor() ([]byte, []int) { + return file_grpc_lb_v1_load_balancer_proto_rawDescGZIP(), []int{4} +} + +func (m *LoadBalanceResponse) GetLoadBalanceResponseType() isLoadBalanceResponse_LoadBalanceResponseType { + if m != nil { + return m.LoadBalanceResponseType + } + return nil +} + +func (x *LoadBalanceResponse) GetInitialResponse() *InitialLoadBalanceResponse { + if x, ok := x.GetLoadBalanceResponseType().(*LoadBalanceResponse_InitialResponse); ok { + return x.InitialResponse + } + return nil +} + +func (x *LoadBalanceResponse) GetServerList() *ServerList { + if x, ok := x.GetLoadBalanceResponseType().(*LoadBalanceResponse_ServerList); ok { + return x.ServerList + } + return nil +} + +func (x *LoadBalanceResponse) GetFallbackResponse() *FallbackResponse { + if x, ok := x.GetLoadBalanceResponseType().(*LoadBalanceResponse_FallbackResponse); ok { + return x.FallbackResponse + } + return nil +} + +type isLoadBalanceResponse_LoadBalanceResponseType interface { + isLoadBalanceResponse_LoadBalanceResponseType() +} + +type LoadBalanceResponse_InitialResponse struct { + // This message should be sent on the first response to the client. + InitialResponse *InitialLoadBalanceResponse `protobuf:"bytes,1,opt,name=initial_response,json=initialResponse,proto3,oneof"` +} + +type LoadBalanceResponse_ServerList struct { + // Contains the list of servers selected by the load balancer. The client + // should send requests to these servers in the specified order. + ServerList *ServerList `protobuf:"bytes,2,opt,name=server_list,json=serverList,proto3,oneof"` +} + +type LoadBalanceResponse_FallbackResponse struct { + // If this field is set, then the client should eagerly enter fallback + // mode (even if there are existing, healthy connections to backends). + FallbackResponse *FallbackResponse `protobuf:"bytes,3,opt,name=fallback_response,json=fallbackResponse,proto3,oneof"` +} + +func (*LoadBalanceResponse_InitialResponse) isLoadBalanceResponse_LoadBalanceResponseType() {} + +func (*LoadBalanceResponse_ServerList) isLoadBalanceResponse_LoadBalanceResponseType() {} + +func (*LoadBalanceResponse_FallbackResponse) isLoadBalanceResponse_LoadBalanceResponseType() {} + +type FallbackResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *FallbackResponse) Reset() { + *x = FallbackResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_grpc_lb_v1_load_balancer_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FallbackResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FallbackResponse) ProtoMessage() {} + +func (x *FallbackResponse) ProtoReflect() protoreflect.Message { + mi := &file_grpc_lb_v1_load_balancer_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FallbackResponse.ProtoReflect.Descriptor instead. +func (*FallbackResponse) Descriptor() ([]byte, []int) { + return file_grpc_lb_v1_load_balancer_proto_rawDescGZIP(), []int{5} +} + +type InitialLoadBalanceResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // This interval defines how often the client should send the client stats + // to the load balancer. Stats should only be reported when the duration is + // positive. + ClientStatsReportInterval *durationpb.Duration `protobuf:"bytes,2,opt,name=client_stats_report_interval,json=clientStatsReportInterval,proto3" json:"client_stats_report_interval,omitempty"` +} + +func (x *InitialLoadBalanceResponse) Reset() { + *x = InitialLoadBalanceResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_grpc_lb_v1_load_balancer_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *InitialLoadBalanceResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InitialLoadBalanceResponse) ProtoMessage() {} + +func (x *InitialLoadBalanceResponse) ProtoReflect() protoreflect.Message { + mi := &file_grpc_lb_v1_load_balancer_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InitialLoadBalanceResponse.ProtoReflect.Descriptor instead. +func (*InitialLoadBalanceResponse) Descriptor() ([]byte, []int) { + return file_grpc_lb_v1_load_balancer_proto_rawDescGZIP(), []int{6} +} + +func (x *InitialLoadBalanceResponse) GetClientStatsReportInterval() *durationpb.Duration { + if x != nil { + return x.ClientStatsReportInterval + } + return nil +} + +type ServerList struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Contains a list of servers selected by the load balancer. The list will + // be updated when server resolutions change or as needed to balance load + // across more servers. The client should consume the server list in order + // unless instructed otherwise via the client_config. + Servers []*Server `protobuf:"bytes,1,rep,name=servers,proto3" json:"servers,omitempty"` +} + +func (x *ServerList) Reset() { + *x = ServerList{} + if protoimpl.UnsafeEnabled { + mi := &file_grpc_lb_v1_load_balancer_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ServerList) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServerList) ProtoMessage() {} + +func (x *ServerList) ProtoReflect() protoreflect.Message { + mi := &file_grpc_lb_v1_load_balancer_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServerList.ProtoReflect.Descriptor instead. +func (*ServerList) Descriptor() ([]byte, []int) { + return file_grpc_lb_v1_load_balancer_proto_rawDescGZIP(), []int{7} +} + +func (x *ServerList) GetServers() []*Server { + if x != nil { + return x.Servers + } + return nil +} + +// Contains server information. When the drop field is not true, use the other +// fields. +type Server struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // A resolved address for the server, serialized in network-byte-order. It may + // either be an IPv4 or IPv6 address. + IpAddress []byte `protobuf:"bytes,1,opt,name=ip_address,json=ipAddress,proto3" json:"ip_address,omitempty"` + // A resolved port number for the server. + Port int32 `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"` + // An opaque but printable token for load reporting. The client must include + // the token of the picked server into the initial metadata when it starts a + // call to that server. The token is used by the server to verify the request + // and to allow the server to report load to the gRPC LB system. The token is + // also used in client stats for reporting dropped calls. + // + // Its length can be variable but must be less than 50 bytes. + LoadBalanceToken string `protobuf:"bytes,3,opt,name=load_balance_token,json=loadBalanceToken,proto3" json:"load_balance_token,omitempty"` + // Indicates whether this particular request should be dropped by the client. + // If the request is dropped, there will be a corresponding entry in + // ClientStats.calls_finished_with_drop. + Drop bool `protobuf:"varint,4,opt,name=drop,proto3" json:"drop,omitempty"` +} + +func (x *Server) Reset() { + *x = Server{} + if protoimpl.UnsafeEnabled { + mi := &file_grpc_lb_v1_load_balancer_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Server) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Server) ProtoMessage() {} + +func (x *Server) ProtoReflect() protoreflect.Message { + mi := &file_grpc_lb_v1_load_balancer_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Server.ProtoReflect.Descriptor instead. +func (*Server) Descriptor() ([]byte, []int) { + return file_grpc_lb_v1_load_balancer_proto_rawDescGZIP(), []int{8} +} + +func (x *Server) GetIpAddress() []byte { + if x != nil { + return x.IpAddress + } + return nil +} + +func (x *Server) GetPort() int32 { + if x != nil { + return x.Port + } + return 0 +} + +func (x *Server) GetLoadBalanceToken() string { + if x != nil { + return x.LoadBalanceToken + } + return "" +} + +func (x *Server) GetDrop() bool { + if x != nil { + return x.Drop + } + return false +} + +var File_grpc_lb_v1_load_balancer_proto protoreflect.FileDescriptor + +var file_grpc_lb_v1_load_balancer_proto_rawDesc = []byte{ + 0x0a, 0x1e, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x6c, 0x62, 0x2f, 0x76, 0x31, 0x2f, 0x6c, 0x6f, 0x61, + 0x64, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x12, 0x0a, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x6c, 0x62, 0x2e, 0x76, 0x31, 0x1a, 0x1e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x75, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc1, 0x01, + 0x0a, 0x12, 0x4c, 0x6f, 0x61, 0x64, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x50, 0x0a, 0x0f, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x5f, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x6c, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x69, + 0x61, 0x6c, 0x4c, 0x6f, 0x61, 0x64, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0e, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3c, 0x0a, 0x0c, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x5f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, + 0x72, 0x70, 0x63, 0x2e, 0x6c, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x53, 0x74, 0x61, 0x74, 0x73, 0x48, 0x00, 0x52, 0x0b, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, + 0x74, 0x61, 0x74, 0x73, 0x42, 0x1b, 0x0a, 0x19, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x62, 0x61, 0x6c, + 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x74, 0x79, 0x70, + 0x65, 0x22, 0x2f, 0x0a, 0x19, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x6f, 0x61, 0x64, + 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, + 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x22, 0x60, 0x0a, 0x13, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, + 0x73, 0x50, 0x65, 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x2c, 0x0a, 0x12, 0x6c, 0x6f, 0x61, + 0x64, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x6c, 0x6f, 0x61, 0x64, 0x42, 0x61, 0x6c, 0x61, 0x6e, + 0x63, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x75, 0x6d, 0x5f, 0x63, + 0x61, 0x6c, 0x6c, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x6e, 0x75, 0x6d, 0x43, + 0x61, 0x6c, 0x6c, 0x73, 0x22, 0xb0, 0x03, 0x0a, 0x0b, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, + 0x74, 0x61, 0x74, 0x73, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2a, + 0x0a, 0x11, 0x6e, 0x75, 0x6d, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x73, 0x5f, 0x73, 0x74, 0x61, 0x72, + 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x6e, 0x75, 0x6d, 0x43, 0x61, + 0x6c, 0x6c, 0x73, 0x53, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x12, 0x2c, 0x0a, 0x12, 0x6e, 0x75, + 0x6d, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x73, 0x5f, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x6e, 0x75, 0x6d, 0x43, 0x61, 0x6c, 0x6c, 0x73, + 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x12, 0x5d, 0x0a, 0x2d, 0x6e, 0x75, 0x6d, 0x5f, + 0x63, 0x61, 0x6c, 0x6c, 0x73, 0x5f, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x5f, 0x77, + 0x69, 0x74, 0x68, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x66, 0x61, 0x69, 0x6c, 0x65, + 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x73, 0x65, 0x6e, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x26, 0x6e, 0x75, 0x6d, 0x43, 0x61, 0x6c, 0x6c, 0x73, 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, + 0x64, 0x57, 0x69, 0x74, 0x68, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x46, 0x61, 0x69, 0x6c, 0x65, + 0x64, 0x54, 0x6f, 0x53, 0x65, 0x6e, 0x64, 0x12, 0x48, 0x0a, 0x21, 0x6e, 0x75, 0x6d, 0x5f, 0x63, + 0x61, 0x6c, 0x6c, 0x73, 0x5f, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x5f, 0x6b, 0x6e, + 0x6f, 0x77, 0x6e, 0x5f, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x1d, 0x6e, 0x75, 0x6d, 0x43, 0x61, 0x6c, 0x6c, 0x73, 0x46, 0x69, 0x6e, 0x69, + 0x73, 0x68, 0x65, 0x64, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, + 0x64, 0x12, 0x58, 0x0a, 0x18, 0x63, 0x61, 0x6c, 0x6c, 0x73, 0x5f, 0x66, 0x69, 0x6e, 0x69, 0x73, + 0x68, 0x65, 0x64, 0x5f, 0x77, 0x69, 0x74, 0x68, 0x5f, 0x64, 0x72, 0x6f, 0x70, 0x18, 0x08, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x6c, 0x62, 0x2e, 0x76, 0x31, + 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x50, 0x65, 0x72, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x15, 0x63, 0x61, 0x6c, 0x6c, 0x73, 0x46, 0x69, 0x6e, 0x69, 0x73, + 0x68, 0x65, 0x64, 0x57, 0x69, 0x74, 0x68, 0x44, 0x72, 0x6f, 0x70, 0x4a, 0x04, 0x08, 0x04, 0x10, + 0x05, 0x4a, 0x04, 0x08, 0x05, 0x10, 0x06, 0x22, 0x90, 0x02, 0x0a, 0x13, 0x4c, 0x6f, 0x61, 0x64, + 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x53, 0x0a, 0x10, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x67, 0x72, 0x70, 0x63, + 0x2e, 0x6c, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x6f, + 0x61, 0x64, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x48, 0x00, 0x52, 0x0f, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x6c, + 0x69, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x72, 0x70, 0x63, + 0x2e, 0x6c, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x69, 0x73, + 0x74, 0x48, 0x00, 0x52, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x12, + 0x4b, 0x0a, 0x11, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x72, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x72, 0x70, + 0x63, 0x2e, 0x6c, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x10, 0x66, 0x61, 0x6c, 0x6c, + 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x1c, 0x0a, 0x1a, + 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x22, 0x12, 0x0a, 0x10, 0x46, 0x61, + 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x7e, + 0x0a, 0x1a, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x4c, 0x6f, 0x61, 0x64, 0x42, 0x61, 0x6c, + 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5a, 0x0a, 0x1c, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x5f, 0x72, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x19, 0x63, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0x40, + 0x0a, 0x0a, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x2c, 0x0a, 0x07, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x6c, 0x62, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, + 0x22, 0x83, 0x01, 0x0a, 0x06, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x69, + 0x70, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x09, 0x69, 0x70, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, + 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x2c, + 0x0a, 0x12, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x74, + 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x6c, 0x6f, 0x61, 0x64, + 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x12, 0x0a, 0x04, + 0x64, 0x72, 0x6f, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x64, 0x72, 0x6f, 0x70, + 0x4a, 0x04, 0x08, 0x05, 0x10, 0x06, 0x32, 0x62, 0x0a, 0x0c, 0x4c, 0x6f, 0x61, 0x64, 0x42, 0x61, + 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x12, 0x52, 0x0a, 0x0b, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, + 0x65, 0x4c, 0x6f, 0x61, 0x64, 0x12, 0x1e, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x6c, 0x62, 0x2e, + 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x61, 0x64, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x6c, 0x62, 0x2e, + 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x61, 0x64, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 0x42, 0x57, 0x0a, 0x0d, 0x69, 0x6f, + 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x6c, 0x62, 0x2e, 0x76, 0x31, 0x42, 0x11, 0x4c, 0x6f, 0x61, + 0x64, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, + 0x5a, 0x31, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, + 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, + 0x72, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x6c, 0x62, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x5f, 0x6c, 0x62, + 0x5f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_grpc_lb_v1_load_balancer_proto_rawDescOnce sync.Once + file_grpc_lb_v1_load_balancer_proto_rawDescData = file_grpc_lb_v1_load_balancer_proto_rawDesc +) + +func file_grpc_lb_v1_load_balancer_proto_rawDescGZIP() []byte { + file_grpc_lb_v1_load_balancer_proto_rawDescOnce.Do(func() { + file_grpc_lb_v1_load_balancer_proto_rawDescData = protoimpl.X.CompressGZIP(file_grpc_lb_v1_load_balancer_proto_rawDescData) + }) + return file_grpc_lb_v1_load_balancer_proto_rawDescData +} + +var file_grpc_lb_v1_load_balancer_proto_msgTypes = make([]protoimpl.MessageInfo, 9) +var file_grpc_lb_v1_load_balancer_proto_goTypes = []interface{}{ + (*LoadBalanceRequest)(nil), // 0: grpc.lb.v1.LoadBalanceRequest + (*InitialLoadBalanceRequest)(nil), // 1: grpc.lb.v1.InitialLoadBalanceRequest + (*ClientStatsPerToken)(nil), // 2: grpc.lb.v1.ClientStatsPerToken + (*ClientStats)(nil), // 3: grpc.lb.v1.ClientStats + (*LoadBalanceResponse)(nil), // 4: grpc.lb.v1.LoadBalanceResponse + (*FallbackResponse)(nil), // 5: grpc.lb.v1.FallbackResponse + (*InitialLoadBalanceResponse)(nil), // 6: grpc.lb.v1.InitialLoadBalanceResponse + (*ServerList)(nil), // 7: grpc.lb.v1.ServerList + (*Server)(nil), // 8: grpc.lb.v1.Server + (*timestamppb.Timestamp)(nil), // 9: google.protobuf.Timestamp + (*durationpb.Duration)(nil), // 10: google.protobuf.Duration +} +var file_grpc_lb_v1_load_balancer_proto_depIdxs = []int32{ + 1, // 0: grpc.lb.v1.LoadBalanceRequest.initial_request:type_name -> grpc.lb.v1.InitialLoadBalanceRequest + 3, // 1: grpc.lb.v1.LoadBalanceRequest.client_stats:type_name -> grpc.lb.v1.ClientStats + 9, // 2: grpc.lb.v1.ClientStats.timestamp:type_name -> google.protobuf.Timestamp + 2, // 3: grpc.lb.v1.ClientStats.calls_finished_with_drop:type_name -> grpc.lb.v1.ClientStatsPerToken + 6, // 4: grpc.lb.v1.LoadBalanceResponse.initial_response:type_name -> grpc.lb.v1.InitialLoadBalanceResponse + 7, // 5: grpc.lb.v1.LoadBalanceResponse.server_list:type_name -> grpc.lb.v1.ServerList + 5, // 6: grpc.lb.v1.LoadBalanceResponse.fallback_response:type_name -> grpc.lb.v1.FallbackResponse + 10, // 7: grpc.lb.v1.InitialLoadBalanceResponse.client_stats_report_interval:type_name -> google.protobuf.Duration + 8, // 8: grpc.lb.v1.ServerList.servers:type_name -> grpc.lb.v1.Server + 0, // 9: grpc.lb.v1.LoadBalancer.BalanceLoad:input_type -> grpc.lb.v1.LoadBalanceRequest + 4, // 10: grpc.lb.v1.LoadBalancer.BalanceLoad:output_type -> grpc.lb.v1.LoadBalanceResponse + 10, // [10:11] is the sub-list for method output_type + 9, // [9:10] is the sub-list for method input_type + 9, // [9:9] is the sub-list for extension type_name + 9, // [9:9] is the sub-list for extension extendee + 0, // [0:9] is the sub-list for field type_name +} + +func init() { file_grpc_lb_v1_load_balancer_proto_init() } +func file_grpc_lb_v1_load_balancer_proto_init() { + if File_grpc_lb_v1_load_balancer_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_grpc_lb_v1_load_balancer_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LoadBalanceRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_grpc_lb_v1_load_balancer_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*InitialLoadBalanceRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_grpc_lb_v1_load_balancer_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ClientStatsPerToken); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_grpc_lb_v1_load_balancer_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ClientStats); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_grpc_lb_v1_load_balancer_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LoadBalanceResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_grpc_lb_v1_load_balancer_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FallbackResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_grpc_lb_v1_load_balancer_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*InitialLoadBalanceResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_grpc_lb_v1_load_balancer_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ServerList); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_grpc_lb_v1_load_balancer_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Server); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_grpc_lb_v1_load_balancer_proto_msgTypes[0].OneofWrappers = []interface{}{ + (*LoadBalanceRequest_InitialRequest)(nil), + (*LoadBalanceRequest_ClientStats)(nil), + } + file_grpc_lb_v1_load_balancer_proto_msgTypes[4].OneofWrappers = []interface{}{ + (*LoadBalanceResponse_InitialResponse)(nil), + (*LoadBalanceResponse_ServerList)(nil), + (*LoadBalanceResponse_FallbackResponse)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_grpc_lb_v1_load_balancer_proto_rawDesc, + NumEnums: 0, + NumMessages: 9, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_grpc_lb_v1_load_balancer_proto_goTypes, + DependencyIndexes: file_grpc_lb_v1_load_balancer_proto_depIdxs, + MessageInfos: file_grpc_lb_v1_load_balancer_proto_msgTypes, + }.Build() + File_grpc_lb_v1_load_balancer_proto = out.File + file_grpc_lb_v1_load_balancer_proto_rawDesc = nil + file_grpc_lb_v1_load_balancer_proto_goTypes = nil + file_grpc_lb_v1_load_balancer_proto_depIdxs = nil +} diff --git a/vendor/google.golang.org/grpc/balancer/grpclb/grpc_lb_v1/load_balancer_grpc.pb.go b/vendor/google.golang.org/grpc/balancer/grpclb/grpc_lb_v1/load_balancer_grpc.pb.go new file mode 100644 index 00000000000..00d0954b38a --- /dev/null +++ b/vendor/google.golang.org/grpc/balancer/grpclb/grpc_lb_v1/load_balancer_grpc.pb.go @@ -0,0 +1,160 @@ +// Copyright 2015 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// This file defines the GRPCLB LoadBalancing protocol. +// +// The canonical version of this proto can be found at +// https://github.com/grpc/grpc-proto/blob/master/grpc/lb/v1/load_balancer.proto + +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.3.0 +// - protoc v4.22.0 +// source: grpc/lb/v1/load_balancer.proto + +package grpc_lb_v1 + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +const ( + LoadBalancer_BalanceLoad_FullMethodName = "/grpc.lb.v1.LoadBalancer/BalanceLoad" +) + +// LoadBalancerClient is the client API for LoadBalancer service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type LoadBalancerClient interface { + // Bidirectional rpc to get a list of servers. + BalanceLoad(ctx context.Context, opts ...grpc.CallOption) (LoadBalancer_BalanceLoadClient, error) +} + +type loadBalancerClient struct { + cc grpc.ClientConnInterface +} + +func NewLoadBalancerClient(cc grpc.ClientConnInterface) LoadBalancerClient { + return &loadBalancerClient{cc} +} + +func (c *loadBalancerClient) BalanceLoad(ctx context.Context, opts ...grpc.CallOption) (LoadBalancer_BalanceLoadClient, error) { + stream, err := c.cc.NewStream(ctx, &LoadBalancer_ServiceDesc.Streams[0], LoadBalancer_BalanceLoad_FullMethodName, opts...) + if err != nil { + return nil, err + } + x := &loadBalancerBalanceLoadClient{stream} + return x, nil +} + +type LoadBalancer_BalanceLoadClient interface { + Send(*LoadBalanceRequest) error + Recv() (*LoadBalanceResponse, error) + grpc.ClientStream +} + +type loadBalancerBalanceLoadClient struct { + grpc.ClientStream +} + +func (x *loadBalancerBalanceLoadClient) Send(m *LoadBalanceRequest) error { + return x.ClientStream.SendMsg(m) +} + +func (x *loadBalancerBalanceLoadClient) Recv() (*LoadBalanceResponse, error) { + m := new(LoadBalanceResponse) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +// LoadBalancerServer is the server API for LoadBalancer service. +// All implementations should embed UnimplementedLoadBalancerServer +// for forward compatibility +type LoadBalancerServer interface { + // Bidirectional rpc to get a list of servers. + BalanceLoad(LoadBalancer_BalanceLoadServer) error +} + +// UnimplementedLoadBalancerServer should be embedded to have forward compatible implementations. +type UnimplementedLoadBalancerServer struct { +} + +func (UnimplementedLoadBalancerServer) BalanceLoad(LoadBalancer_BalanceLoadServer) error { + return status.Errorf(codes.Unimplemented, "method BalanceLoad not implemented") +} + +// UnsafeLoadBalancerServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to LoadBalancerServer will +// result in compilation errors. +type UnsafeLoadBalancerServer interface { + mustEmbedUnimplementedLoadBalancerServer() +} + +func RegisterLoadBalancerServer(s grpc.ServiceRegistrar, srv LoadBalancerServer) { + s.RegisterService(&LoadBalancer_ServiceDesc, srv) +} + +func _LoadBalancer_BalanceLoad_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(LoadBalancerServer).BalanceLoad(&loadBalancerBalanceLoadServer{stream}) +} + +type LoadBalancer_BalanceLoadServer interface { + Send(*LoadBalanceResponse) error + Recv() (*LoadBalanceRequest, error) + grpc.ServerStream +} + +type loadBalancerBalanceLoadServer struct { + grpc.ServerStream +} + +func (x *loadBalancerBalanceLoadServer) Send(m *LoadBalanceResponse) error { + return x.ServerStream.SendMsg(m) +} + +func (x *loadBalancerBalanceLoadServer) Recv() (*LoadBalanceRequest, error) { + m := new(LoadBalanceRequest) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +// LoadBalancer_ServiceDesc is the grpc.ServiceDesc for LoadBalancer service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var LoadBalancer_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "grpc.lb.v1.LoadBalancer", + HandlerType: (*LoadBalancerServer)(nil), + Methods: []grpc.MethodDesc{}, + Streams: []grpc.StreamDesc{ + { + StreamName: "BalanceLoad", + Handler: _LoadBalancer_BalanceLoad_Handler, + ServerStreams: true, + ClientStreams: true, + }, + }, + Metadata: "grpc/lb/v1/load_balancer.proto", +} diff --git a/vendor/google.golang.org/grpc/balancer/grpclb/grpclb.go b/vendor/google.golang.org/grpc/balancer/grpclb/grpclb.go new file mode 100644 index 00000000000..6d698229a34 --- /dev/null +++ b/vendor/google.golang.org/grpc/balancer/grpclb/grpclb.go @@ -0,0 +1,520 @@ +/* + * + * Copyright 2016 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Package grpclb defines a grpclb balancer. +// +// To install grpclb balancer, import this package as: +// +// import _ "google.golang.org/grpc/balancer/grpclb" +package grpclb + +import ( + "context" + "errors" + "fmt" + "sync" + "time" + + "google.golang.org/grpc" + "google.golang.org/grpc/balancer" + grpclbstate "google.golang.org/grpc/balancer/grpclb/state" + "google.golang.org/grpc/connectivity" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/internal" + "google.golang.org/grpc/internal/backoff" + "google.golang.org/grpc/internal/resolver/dns" + "google.golang.org/grpc/resolver" + + durationpb "github.com/golang/protobuf/ptypes/duration" + lbpb "google.golang.org/grpc/balancer/grpclb/grpc_lb_v1" +) + +const ( + lbTokenKey = "lb-token" + defaultFallbackTimeout = 10 * time.Second + grpclbName = "grpclb" +) + +var errServerTerminatedConnection = errors.New("grpclb: failed to recv server list: server terminated connection") +var logger = grpclog.Component("grpclb") + +func convertDuration(d *durationpb.Duration) time.Duration { + if d == nil { + return 0 + } + return time.Duration(d.Seconds)*time.Second + time.Duration(d.Nanos)*time.Nanosecond +} + +// Client API for LoadBalancer service. +// Mostly copied from generated pb.go file. +// To avoid circular dependency. +type loadBalancerClient struct { + cc *grpc.ClientConn +} + +func (c *loadBalancerClient) BalanceLoad(ctx context.Context, opts ...grpc.CallOption) (*balanceLoadClientStream, error) { + desc := &grpc.StreamDesc{ + StreamName: "BalanceLoad", + ServerStreams: true, + ClientStreams: true, + } + stream, err := c.cc.NewStream(ctx, desc, "/grpc.lb.v1.LoadBalancer/BalanceLoad", opts...) + if err != nil { + return nil, err + } + x := &balanceLoadClientStream{stream} + return x, nil +} + +type balanceLoadClientStream struct { + grpc.ClientStream +} + +func (x *balanceLoadClientStream) Send(m *lbpb.LoadBalanceRequest) error { + return x.ClientStream.SendMsg(m) +} + +func (x *balanceLoadClientStream) Recv() (*lbpb.LoadBalanceResponse, error) { + m := new(lbpb.LoadBalanceResponse) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func init() { + balancer.Register(newLBBuilder()) + dns.EnableSRVLookups = true +} + +// newLBBuilder creates a builder for grpclb. +func newLBBuilder() balancer.Builder { + return newLBBuilderWithFallbackTimeout(defaultFallbackTimeout) +} + +// newLBBuilderWithFallbackTimeout creates a grpclb builder with the given +// fallbackTimeout. If no response is received from the remote balancer within +// fallbackTimeout, the backend addresses from the resolved address list will be +// used. +// +// Only call this function when a non-default fallback timeout is needed. +func newLBBuilderWithFallbackTimeout(fallbackTimeout time.Duration) balancer.Builder { + return &lbBuilder{ + fallbackTimeout: fallbackTimeout, + } +} + +type lbBuilder struct { + fallbackTimeout time.Duration +} + +func (b *lbBuilder) Name() string { + return grpclbName +} + +func (b *lbBuilder) Build(cc balancer.ClientConn, opt balancer.BuildOptions) balancer.Balancer { + // This generates a manual resolver builder with a fixed scheme. This + // scheme will be used to dial to remote LB, so we can send filtered + // address updates to remote LB ClientConn using this manual resolver. + r := &lbManualResolver{scheme: "grpclb-internal", ccb: cc} + + lb := &lbBalancer{ + cc: newLBCacheClientConn(cc), + dialTarget: opt.Target.Endpoint(), + target: opt.Target.Endpoint(), + opt: opt, + fallbackTimeout: b.fallbackTimeout, + doneCh: make(chan struct{}), + + manualResolver: r, + subConns: make(map[resolver.Address]balancer.SubConn), + scStates: make(map[balancer.SubConn]connectivity.State), + picker: &errPicker{err: balancer.ErrNoSubConnAvailable}, + clientStats: newRPCStats(), + backoff: backoff.DefaultExponential, // TODO: make backoff configurable. + } + + var err error + if opt.CredsBundle != nil { + lb.grpclbClientConnCreds, err = opt.CredsBundle.NewWithMode(internal.CredsBundleModeBalancer) + if err != nil { + logger.Warningf("lbBalancer: client connection creds NewWithMode failed: %v", err) + } + lb.grpclbBackendCreds, err = opt.CredsBundle.NewWithMode(internal.CredsBundleModeBackendFromBalancer) + if err != nil { + logger.Warningf("lbBalancer: backend creds NewWithMode failed: %v", err) + } + } + + return lb +} + +type lbBalancer struct { + cc *lbCacheClientConn + dialTarget string // user's dial target + target string // same as dialTarget unless overridden in service config + opt balancer.BuildOptions + + usePickFirst bool + + // grpclbClientConnCreds is the creds bundle to be used to connect to grpclb + // servers. If it's nil, use the TransportCredentials from BuildOptions + // instead. + grpclbClientConnCreds credentials.Bundle + // grpclbBackendCreds is the creds bundle to be used for addresses that are + // returned by grpclb server. If it's nil, don't set anything when creating + // SubConns. + grpclbBackendCreds credentials.Bundle + + fallbackTimeout time.Duration + doneCh chan struct{} + + // manualResolver is used in the remote LB ClientConn inside grpclb. When + // resolved address updates are received by grpclb, filtered updates will be + // send to remote LB ClientConn through this resolver. + manualResolver *lbManualResolver + // The ClientConn to talk to the remote balancer. + ccRemoteLB *remoteBalancerCCWrapper + // backoff for calling remote balancer. + backoff backoff.Strategy + + // Support client side load reporting. Each picker gets a reference to this, + // and will update its content. + clientStats *rpcStats + + mu sync.Mutex // guards everything following. + // The full server list including drops, used to check if the newly received + // serverList contains anything new. Each generate picker will also have + // reference to this list to do the first layer pick. + fullServerList []*lbpb.Server + // Backend addresses. It's kept so the addresses are available when + // switching between round_robin and pickfirst. + backendAddrs []resolver.Address + // All backends addresses, with metadata set to nil. This list contains all + // backend addresses in the same order and with the same duplicates as in + // serverlist. When generating picker, a SubConn slice with the same order + // but with only READY SCs will be gerenated. + backendAddrsWithoutMetadata []resolver.Address + // Roundrobin functionalities. + state connectivity.State + subConns map[resolver.Address]balancer.SubConn // Used to new/remove SubConn. + scStates map[balancer.SubConn]connectivity.State // Used to filter READY SubConns. + picker balancer.Picker + // Support fallback to resolved backend addresses if there's no response + // from remote balancer within fallbackTimeout. + remoteBalancerConnected bool + serverListReceived bool + inFallback bool + // resolvedBackendAddrs is resolvedAddrs minus remote balancers. It's set + // when resolved address updates are received, and read in the goroutine + // handling fallback. + resolvedBackendAddrs []resolver.Address + connErr error // the last connection error +} + +// regeneratePicker takes a snapshot of the balancer, and generates a picker from +// it. The picker +// - always returns ErrTransientFailure if the balancer is in TransientFailure, +// - does two layer roundrobin pick otherwise. +// +// Caller must hold lb.mu. +func (lb *lbBalancer) regeneratePicker(resetDrop bool) { + if lb.state == connectivity.TransientFailure { + lb.picker = &errPicker{err: fmt.Errorf("all SubConns are in TransientFailure, last connection error: %v", lb.connErr)} + return + } + + if lb.state == connectivity.Connecting { + lb.picker = &errPicker{err: balancer.ErrNoSubConnAvailable} + return + } + + var readySCs []balancer.SubConn + if lb.usePickFirst { + for _, sc := range lb.subConns { + readySCs = append(readySCs, sc) + break + } + } else { + for _, a := range lb.backendAddrsWithoutMetadata { + if sc, ok := lb.subConns[a]; ok { + if st, ok := lb.scStates[sc]; ok && st == connectivity.Ready { + readySCs = append(readySCs, sc) + } + } + } + } + + if len(readySCs) <= 0 { + // If there's no ready SubConns, always re-pick. This is to avoid drops + // unless at least one SubConn is ready. Otherwise we may drop more + // often than want because of drops + re-picks(which become re-drops). + // + // This doesn't seem to be necessary after the connecting check above. + // Kept for safety. + lb.picker = &errPicker{err: balancer.ErrNoSubConnAvailable} + return + } + if lb.inFallback { + lb.picker = newRRPicker(readySCs) + return + } + if resetDrop { + lb.picker = newLBPicker(lb.fullServerList, readySCs, lb.clientStats) + return + } + prevLBPicker, ok := lb.picker.(*lbPicker) + if !ok { + lb.picker = newLBPicker(lb.fullServerList, readySCs, lb.clientStats) + return + } + prevLBPicker.updateReadySCs(readySCs) +} + +// aggregateSubConnStats calculate the aggregated state of SubConns in +// lb.SubConns. These SubConns are subconns in use (when switching between +// fallback and grpclb). lb.scState contains states for all SubConns, including +// those in cache (SubConns are cached for 10 seconds after remove). +// +// The aggregated state is: +// - If at least one SubConn in Ready, the aggregated state is Ready; +// - Else if at least one SubConn in Connecting or IDLE, the aggregated state is Connecting; +// - It's OK to consider IDLE as Connecting. SubConns never stay in IDLE, +// they start to connect immediately. But there's a race between the overall +// state is reported, and when the new SubConn state arrives. And SubConns +// never go back to IDLE. +// - Else the aggregated state is TransientFailure. +func (lb *lbBalancer) aggregateSubConnStates() connectivity.State { + var numConnecting uint64 + + for _, sc := range lb.subConns { + if state, ok := lb.scStates[sc]; ok { + switch state { + case connectivity.Ready: + return connectivity.Ready + case connectivity.Connecting, connectivity.Idle: + numConnecting++ + } + } + } + if numConnecting > 0 { + return connectivity.Connecting + } + return connectivity.TransientFailure +} + +func (lb *lbBalancer) UpdateSubConnState(sc balancer.SubConn, scs balancer.SubConnState) { + s := scs.ConnectivityState + if logger.V(2) { + logger.Infof("lbBalancer: handle SubConn state change: %p, %v", sc, s) + } + lb.mu.Lock() + defer lb.mu.Unlock() + + oldS, ok := lb.scStates[sc] + if !ok { + if logger.V(2) { + logger.Infof("lbBalancer: got state changes for an unknown SubConn: %p, %v", sc, s) + } + return + } + lb.scStates[sc] = s + switch s { + case connectivity.Idle: + sc.Connect() + case connectivity.Shutdown: + // When an address was removed by resolver, b called RemoveSubConn but + // kept the sc's state in scStates. Remove state for this sc here. + delete(lb.scStates, sc) + case connectivity.TransientFailure: + lb.connErr = scs.ConnectionError + } + // Force regenerate picker if + // - this sc became ready from not-ready + // - this sc became not-ready from ready + lb.updateStateAndPicker((oldS == connectivity.Ready) != (s == connectivity.Ready), false) + + // Enter fallback when the aggregated state is not Ready and the connection + // to remote balancer is lost. + if lb.state != connectivity.Ready { + if !lb.inFallback && !lb.remoteBalancerConnected { + // Enter fallback. + lb.refreshSubConns(lb.resolvedBackendAddrs, true, lb.usePickFirst) + } + } +} + +// updateStateAndPicker re-calculate the aggregated state, and regenerate picker +// if overall state is changed. +// +// If forceRegeneratePicker is true, picker will be regenerated. +func (lb *lbBalancer) updateStateAndPicker(forceRegeneratePicker bool, resetDrop bool) { + oldAggrState := lb.state + lb.state = lb.aggregateSubConnStates() + // Regenerate picker when one of the following happens: + // - caller wants to regenerate + // - the aggregated state changed + if forceRegeneratePicker || (lb.state != oldAggrState) { + lb.regeneratePicker(resetDrop) + } + + lb.cc.UpdateState(balancer.State{ConnectivityState: lb.state, Picker: lb.picker}) +} + +// fallbackToBackendsAfter blocks for fallbackTimeout and falls back to use +// resolved backends (backends received from resolver, not from remote balancer) +// if no connection to remote balancers was successful. +func (lb *lbBalancer) fallbackToBackendsAfter(fallbackTimeout time.Duration) { + timer := time.NewTimer(fallbackTimeout) + defer timer.Stop() + select { + case <-timer.C: + case <-lb.doneCh: + return + } + lb.mu.Lock() + if lb.inFallback || lb.serverListReceived { + lb.mu.Unlock() + return + } + // Enter fallback. + lb.refreshSubConns(lb.resolvedBackendAddrs, true, lb.usePickFirst) + lb.mu.Unlock() +} + +func (lb *lbBalancer) handleServiceConfig(gc *grpclbServiceConfig) { + lb.mu.Lock() + defer lb.mu.Unlock() + + // grpclb uses the user's dial target to populate the `Name` field of the + // `InitialLoadBalanceRequest` message sent to the remote balancer. But when + // grpclb is used a child policy in the context of RLS, we want the `Name` + // field to be populated with the value received from the RLS server. To + // support this use case, an optional "target_name" field has been added to + // the grpclb LB policy's config. If specified, it overrides the name of + // the target to be sent to the remote balancer; if not, the target to be + // sent to the balancer will continue to be obtained from the target URI + // passed to the gRPC client channel. Whenever that target to be sent to the + // balancer is updated, we need to restart the stream to the balancer as + // this target is sent in the first message on the stream. + if gc != nil { + target := lb.dialTarget + if gc.ServiceName != "" { + target = gc.ServiceName + } + if target != lb.target { + lb.target = target + if lb.ccRemoteLB != nil { + lb.ccRemoteLB.cancelRemoteBalancerCall() + } + } + } + + newUsePickFirst := childIsPickFirst(gc) + if lb.usePickFirst == newUsePickFirst { + return + } + if logger.V(2) { + logger.Infof("lbBalancer: switching mode, new usePickFirst: %+v", newUsePickFirst) + } + lb.refreshSubConns(lb.backendAddrs, lb.inFallback, newUsePickFirst) +} + +func (lb *lbBalancer) ResolverError(error) { + // Ignore resolver errors. GRPCLB is not selected unless the resolver + // works at least once. +} + +func (lb *lbBalancer) UpdateClientConnState(ccs balancer.ClientConnState) error { + if logger.V(2) { + logger.Infof("lbBalancer: UpdateClientConnState: %+v", ccs) + } + gc, _ := ccs.BalancerConfig.(*grpclbServiceConfig) + lb.handleServiceConfig(gc) + + addrs := ccs.ResolverState.Addresses + + var remoteBalancerAddrs, backendAddrs []resolver.Address + for _, a := range addrs { + if a.Type == resolver.GRPCLB { + a.Type = resolver.Backend + remoteBalancerAddrs = append(remoteBalancerAddrs, a) + } else { + backendAddrs = append(backendAddrs, a) + } + } + if sd := grpclbstate.Get(ccs.ResolverState); sd != nil { + // Override any balancer addresses provided via + // ccs.ResolverState.Addresses. + remoteBalancerAddrs = sd.BalancerAddresses + } + + if len(backendAddrs)+len(remoteBalancerAddrs) == 0 { + // There should be at least one address, either grpclb server or + // fallback. Empty address is not valid. + return balancer.ErrBadResolverState + } + + if len(remoteBalancerAddrs) == 0 { + if lb.ccRemoteLB != nil { + lb.ccRemoteLB.close() + lb.ccRemoteLB = nil + } + } else if lb.ccRemoteLB == nil { + // First time receiving resolved addresses, create a cc to remote + // balancers. + lb.newRemoteBalancerCCWrapper() + // Start the fallback goroutine. + go lb.fallbackToBackendsAfter(lb.fallbackTimeout) + } + + if lb.ccRemoteLB != nil { + // cc to remote balancers uses lb.manualResolver. Send the updated remote + // balancer addresses to it through manualResolver. + lb.manualResolver.UpdateState(resolver.State{Addresses: remoteBalancerAddrs}) + } + + lb.mu.Lock() + lb.resolvedBackendAddrs = backendAddrs + if len(remoteBalancerAddrs) == 0 || lb.inFallback { + // If there's no remote balancer address in ClientConn update, grpclb + // enters fallback mode immediately. + // + // If a new update is received while grpclb is in fallback, update the + // list of backends being used to the new fallback backends. + lb.refreshSubConns(lb.resolvedBackendAddrs, true, lb.usePickFirst) + } + lb.mu.Unlock() + return nil +} + +func (lb *lbBalancer) Close() { + select { + case <-lb.doneCh: + return + default: + } + close(lb.doneCh) + if lb.ccRemoteLB != nil { + lb.ccRemoteLB.close() + } + lb.cc.close() +} + +func (lb *lbBalancer) ExitIdle() {} diff --git a/vendor/google.golang.org/grpc/balancer/grpclb/grpclb_config.go b/vendor/google.golang.org/grpc/balancer/grpclb/grpclb_config.go new file mode 100644 index 00000000000..8942c31310a --- /dev/null +++ b/vendor/google.golang.org/grpc/balancer/grpclb/grpclb_config.go @@ -0,0 +1,67 @@ +/* + * + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package grpclb + +import ( + "encoding/json" + + "google.golang.org/grpc" + "google.golang.org/grpc/balancer/roundrobin" + "google.golang.org/grpc/serviceconfig" +) + +const ( + roundRobinName = roundrobin.Name + pickFirstName = grpc.PickFirstBalancerName +) + +type grpclbServiceConfig struct { + serviceconfig.LoadBalancingConfig + ChildPolicy *[]map[string]json.RawMessage + ServiceName string +} + +func (b *lbBuilder) ParseConfig(lbConfig json.RawMessage) (serviceconfig.LoadBalancingConfig, error) { + ret := &grpclbServiceConfig{} + if err := json.Unmarshal(lbConfig, ret); err != nil { + return nil, err + } + return ret, nil +} + +func childIsPickFirst(sc *grpclbServiceConfig) bool { + if sc == nil { + return false + } + childConfigs := sc.ChildPolicy + if childConfigs == nil { + return false + } + for _, childC := range *childConfigs { + // If round_robin exists before pick_first, return false + if _, ok := childC[roundRobinName]; ok { + return false + } + // If pick_first is before round_robin, return true + if _, ok := childC[pickFirstName]; ok { + return true + } + } + return false +} diff --git a/vendor/google.golang.org/grpc/balancer/grpclb/grpclb_picker.go b/vendor/google.golang.org/grpc/balancer/grpclb/grpclb_picker.go new file mode 100644 index 00000000000..39bc5cc71e8 --- /dev/null +++ b/vendor/google.golang.org/grpc/balancer/grpclb/grpclb_picker.go @@ -0,0 +1,202 @@ +/* + * + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package grpclb + +import ( + "sync" + "sync/atomic" + + "google.golang.org/grpc/balancer" + lbpb "google.golang.org/grpc/balancer/grpclb/grpc_lb_v1" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/internal/grpcrand" + "google.golang.org/grpc/status" +) + +// rpcStats is same as lbpb.ClientStats, except that numCallsDropped is a map +// instead of a slice. +type rpcStats struct { + // Only access the following fields atomically. + numCallsStarted int64 + numCallsFinished int64 + numCallsFinishedWithClientFailedToSend int64 + numCallsFinishedKnownReceived int64 + + mu sync.Mutex + // map load_balance_token -> num_calls_dropped + numCallsDropped map[string]int64 +} + +func newRPCStats() *rpcStats { + return &rpcStats{ + numCallsDropped: make(map[string]int64), + } +} + +func isZeroStats(stats *lbpb.ClientStats) bool { + return len(stats.CallsFinishedWithDrop) == 0 && + stats.NumCallsStarted == 0 && + stats.NumCallsFinished == 0 && + stats.NumCallsFinishedWithClientFailedToSend == 0 && + stats.NumCallsFinishedKnownReceived == 0 +} + +// toClientStats converts rpcStats to lbpb.ClientStats, and clears rpcStats. +func (s *rpcStats) toClientStats() *lbpb.ClientStats { + stats := &lbpb.ClientStats{ + NumCallsStarted: atomic.SwapInt64(&s.numCallsStarted, 0), + NumCallsFinished: atomic.SwapInt64(&s.numCallsFinished, 0), + NumCallsFinishedWithClientFailedToSend: atomic.SwapInt64(&s.numCallsFinishedWithClientFailedToSend, 0), + NumCallsFinishedKnownReceived: atomic.SwapInt64(&s.numCallsFinishedKnownReceived, 0), + } + s.mu.Lock() + dropped := s.numCallsDropped + s.numCallsDropped = make(map[string]int64) + s.mu.Unlock() + for token, count := range dropped { + stats.CallsFinishedWithDrop = append(stats.CallsFinishedWithDrop, &lbpb.ClientStatsPerToken{ + LoadBalanceToken: token, + NumCalls: count, + }) + } + return stats +} + +func (s *rpcStats) drop(token string) { + atomic.AddInt64(&s.numCallsStarted, 1) + s.mu.Lock() + s.numCallsDropped[token]++ + s.mu.Unlock() + atomic.AddInt64(&s.numCallsFinished, 1) +} + +func (s *rpcStats) failedToSend() { + atomic.AddInt64(&s.numCallsStarted, 1) + atomic.AddInt64(&s.numCallsFinishedWithClientFailedToSend, 1) + atomic.AddInt64(&s.numCallsFinished, 1) +} + +func (s *rpcStats) knownReceived() { + atomic.AddInt64(&s.numCallsStarted, 1) + atomic.AddInt64(&s.numCallsFinishedKnownReceived, 1) + atomic.AddInt64(&s.numCallsFinished, 1) +} + +type errPicker struct { + // Pick always returns this err. + err error +} + +func (p *errPicker) Pick(balancer.PickInfo) (balancer.PickResult, error) { + return balancer.PickResult{}, p.err +} + +// rrPicker does roundrobin on subConns. It's typically used when there's no +// response from remote balancer, and grpclb falls back to the resolved +// backends. +// +// It guaranteed that len(subConns) > 0. +type rrPicker struct { + mu sync.Mutex + subConns []balancer.SubConn // The subConns that were READY when taking the snapshot. + subConnsNext int +} + +func newRRPicker(readySCs []balancer.SubConn) *rrPicker { + return &rrPicker{ + subConns: readySCs, + subConnsNext: grpcrand.Intn(len(readySCs)), + } +} + +func (p *rrPicker) Pick(balancer.PickInfo) (balancer.PickResult, error) { + p.mu.Lock() + defer p.mu.Unlock() + sc := p.subConns[p.subConnsNext] + p.subConnsNext = (p.subConnsNext + 1) % len(p.subConns) + return balancer.PickResult{SubConn: sc}, nil +} + +// lbPicker does two layers of picks: +// +// First layer: roundrobin on all servers in serverList, including drops and backends. +// - If it picks a drop, the RPC will fail as being dropped. +// - If it picks a backend, do a second layer pick to pick the real backend. +// +// Second layer: roundrobin on all READY backends. +// +// It's guaranteed that len(serverList) > 0. +type lbPicker struct { + mu sync.Mutex + serverList []*lbpb.Server + serverListNext int + subConns []balancer.SubConn // The subConns that were READY when taking the snapshot. + subConnsNext int + + stats *rpcStats +} + +func newLBPicker(serverList []*lbpb.Server, readySCs []balancer.SubConn, stats *rpcStats) *lbPicker { + return &lbPicker{ + serverList: serverList, + subConns: readySCs, + subConnsNext: grpcrand.Intn(len(readySCs)), + stats: stats, + } +} + +func (p *lbPicker) Pick(balancer.PickInfo) (balancer.PickResult, error) { + p.mu.Lock() + defer p.mu.Unlock() + + // Layer one roundrobin on serverList. + s := p.serverList[p.serverListNext] + p.serverListNext = (p.serverListNext + 1) % len(p.serverList) + + // If it's a drop, return an error and fail the RPC. + if s.Drop { + p.stats.drop(s.LoadBalanceToken) + return balancer.PickResult{}, status.Errorf(codes.Unavailable, "request dropped by grpclb") + } + + // If not a drop but there's no ready subConns. + if len(p.subConns) <= 0 { + return balancer.PickResult{}, balancer.ErrNoSubConnAvailable + } + + // Return the next ready subConn in the list, also collect rpc stats. + sc := p.subConns[p.subConnsNext] + p.subConnsNext = (p.subConnsNext + 1) % len(p.subConns) + done := func(info balancer.DoneInfo) { + if !info.BytesSent { + p.stats.failedToSend() + } else if info.BytesReceived { + p.stats.knownReceived() + } + } + return balancer.PickResult{SubConn: sc, Done: done}, nil +} + +func (p *lbPicker) updateReadySCs(readySCs []balancer.SubConn) { + p.mu.Lock() + defer p.mu.Unlock() + + p.subConns = readySCs + p.subConnsNext = p.subConnsNext % len(readySCs) +} diff --git a/vendor/google.golang.org/grpc/balancer/grpclb/grpclb_remote_balancer.go b/vendor/google.golang.org/grpc/balancer/grpclb/grpclb_remote_balancer.go new file mode 100644 index 00000000000..e56006d7131 --- /dev/null +++ b/vendor/google.golang.org/grpc/balancer/grpclb/grpclb_remote_balancer.go @@ -0,0 +1,449 @@ +/* + * + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package grpclb + +import ( + "context" + "fmt" + "io" + "net" + "sync" + "time" + + "github.com/golang/protobuf/proto" + timestamppb "github.com/golang/protobuf/ptypes/timestamp" + "github.com/google/go-cmp/cmp" + "google.golang.org/grpc" + "google.golang.org/grpc/balancer" + lbpb "google.golang.org/grpc/balancer/grpclb/grpc_lb_v1" + "google.golang.org/grpc/connectivity" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/internal/backoff" + imetadata "google.golang.org/grpc/internal/metadata" + "google.golang.org/grpc/keepalive" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/resolver" +) + +// processServerList updates balancer's internal state, create/remove SubConns +// and regenerates picker using the received serverList. +func (lb *lbBalancer) processServerList(l *lbpb.ServerList) { + if logger.V(2) { + logger.Infof("lbBalancer: processing server list: %+v", l) + } + lb.mu.Lock() + defer lb.mu.Unlock() + + // Set serverListReceived to true so fallback will not take effect if it has + // not hit timeout. + lb.serverListReceived = true + + // If the new server list == old server list, do nothing. + if cmp.Equal(lb.fullServerList, l.Servers, cmp.Comparer(proto.Equal)) { + if logger.V(2) { + logger.Infof("lbBalancer: new serverlist same as the previous one, ignoring") + } + return + } + lb.fullServerList = l.Servers + + var backendAddrs []resolver.Address + for i, s := range l.Servers { + if s.Drop { + continue + } + + md := metadata.Pairs(lbTokenKey, s.LoadBalanceToken) + ip := net.IP(s.IpAddress) + ipStr := ip.String() + if ip.To4() == nil { + // Add square brackets to ipv6 addresses, otherwise net.Dial() and + // net.SplitHostPort() will return too many colons error. + ipStr = fmt.Sprintf("[%s]", ipStr) + } + addr := imetadata.Set(resolver.Address{Addr: fmt.Sprintf("%s:%d", ipStr, s.Port)}, md) + if logger.V(2) { + logger.Infof("lbBalancer: server list entry[%d]: ipStr:|%s|, port:|%d|, load balancer token:|%v|", + i, ipStr, s.Port, s.LoadBalanceToken) + } + backendAddrs = append(backendAddrs, addr) + } + + // Call refreshSubConns to create/remove SubConns. If we are in fallback, + // this is also exiting fallback. + lb.refreshSubConns(backendAddrs, false, lb.usePickFirst) +} + +// refreshSubConns creates/removes SubConns with backendAddrs, and refreshes +// balancer state and picker. +// +// Caller must hold lb.mu. +func (lb *lbBalancer) refreshSubConns(backendAddrs []resolver.Address, fallback bool, pickFirst bool) { + opts := balancer.NewSubConnOptions{} + if !fallback { + opts.CredsBundle = lb.grpclbBackendCreds + } + + lb.backendAddrs = backendAddrs + lb.backendAddrsWithoutMetadata = nil + + fallbackModeChanged := lb.inFallback != fallback + lb.inFallback = fallback + if fallbackModeChanged && lb.inFallback { + // Clear previous received list when entering fallback, so if the server + // comes back and sends the same list again, the new addresses will be + // used. + lb.fullServerList = nil + } + + balancingPolicyChanged := lb.usePickFirst != pickFirst + oldUsePickFirst := lb.usePickFirst + lb.usePickFirst = pickFirst + + if fallbackModeChanged || balancingPolicyChanged { + // Remove all SubConns when switching balancing policy or switching + // fallback mode. + // + // For fallback mode switching with pickfirst, we want to recreate the + // SubConn because the creds could be different. + for a, sc := range lb.subConns { + if oldUsePickFirst { + // If old SubConn were created for pickfirst, bypass cache and + // remove directly. + lb.cc.cc.RemoveSubConn(sc) + } else { + lb.cc.RemoveSubConn(sc) + } + delete(lb.subConns, a) + } + } + + if lb.usePickFirst { + var ( + scKey resolver.Address + sc balancer.SubConn + ) + for scKey, sc = range lb.subConns { + break + } + if sc != nil { + if len(backendAddrs) == 0 { + lb.cc.cc.RemoveSubConn(sc) + delete(lb.subConns, scKey) + return + } + lb.cc.cc.UpdateAddresses(sc, backendAddrs) + sc.Connect() + return + } + // This bypasses the cc wrapper with SubConn cache. + sc, err := lb.cc.cc.NewSubConn(backendAddrs, opts) + if err != nil { + logger.Warningf("grpclb: failed to create new SubConn: %v", err) + return + } + sc.Connect() + lb.subConns[backendAddrs[0]] = sc + lb.scStates[sc] = connectivity.Idle + return + } + + // addrsSet is the set converted from backendAddrsWithoutMetadata, it's used to quick + // lookup for an address. + addrsSet := make(map[resolver.Address]struct{}) + // Create new SubConns. + for _, addr := range backendAddrs { + addrWithoutAttrs := addr + addrWithoutAttrs.Attributes = nil + addrsSet[addrWithoutAttrs] = struct{}{} + lb.backendAddrsWithoutMetadata = append(lb.backendAddrsWithoutMetadata, addrWithoutAttrs) + + if _, ok := lb.subConns[addrWithoutAttrs]; !ok { + // Use addrWithMD to create the SubConn. + sc, err := lb.cc.NewSubConn([]resolver.Address{addr}, opts) + if err != nil { + logger.Warningf("grpclb: failed to create new SubConn: %v", err) + continue + } + lb.subConns[addrWithoutAttrs] = sc // Use the addr without MD as key for the map. + if _, ok := lb.scStates[sc]; !ok { + // Only set state of new sc to IDLE. The state could already be + // READY for cached SubConns. + lb.scStates[sc] = connectivity.Idle + } + sc.Connect() + } + } + + for a, sc := range lb.subConns { + // a was removed by resolver. + if _, ok := addrsSet[a]; !ok { + lb.cc.RemoveSubConn(sc) + delete(lb.subConns, a) + // Keep the state of this sc in b.scStates until sc's state becomes Shutdown. + // The entry will be deleted in UpdateSubConnState. + } + } + + // Regenerate and update picker after refreshing subconns because with + // cache, even if SubConn was newed/removed, there might be no state + // changes (the subconn will be kept in cache, not actually + // newed/removed). + lb.updateStateAndPicker(true, true) +} + +type remoteBalancerCCWrapper struct { + cc *grpc.ClientConn + lb *lbBalancer + backoff backoff.Strategy + done chan struct{} + + streamMu sync.Mutex + streamCancel func() + + // waitgroup to wait for all goroutines to exit. + wg sync.WaitGroup +} + +func (lb *lbBalancer) newRemoteBalancerCCWrapper() { + var dopts []grpc.DialOption + if creds := lb.opt.DialCreds; creds != nil { + dopts = append(dopts, grpc.WithTransportCredentials(creds)) + } else if bundle := lb.grpclbClientConnCreds; bundle != nil { + dopts = append(dopts, grpc.WithCredentialsBundle(bundle)) + } else { + dopts = append(dopts, grpc.WithTransportCredentials(insecure.NewCredentials())) + } + if lb.opt.Dialer != nil { + dopts = append(dopts, grpc.WithContextDialer(lb.opt.Dialer)) + } + if lb.opt.CustomUserAgent != "" { + dopts = append(dopts, grpc.WithUserAgent(lb.opt.CustomUserAgent)) + } + // Explicitly set pickfirst as the balancer. + dopts = append(dopts, grpc.WithDefaultServiceConfig(`{"loadBalancingPolicy":"pick_first"}`)) + dopts = append(dopts, grpc.WithResolvers(lb.manualResolver)) + dopts = append(dopts, grpc.WithChannelzParentID(lb.opt.ChannelzParentID)) + + // Enable Keepalive for grpclb client. + dopts = append(dopts, grpc.WithKeepaliveParams(keepalive.ClientParameters{ + Time: 20 * time.Second, + Timeout: 10 * time.Second, + PermitWithoutStream: true, + })) + + // The dial target is not important. + // + // The grpclb server addresses will set field ServerName, and creds will + // receive ServerName as authority. + cc, err := grpc.DialContext(context.Background(), lb.manualResolver.Scheme()+":///grpclb.subClientConn", dopts...) + if err != nil { + logger.Fatalf("failed to dial: %v", err) + } + ccw := &remoteBalancerCCWrapper{ + cc: cc, + lb: lb, + backoff: lb.backoff, + done: make(chan struct{}), + } + lb.ccRemoteLB = ccw + ccw.wg.Add(1) + go ccw.watchRemoteBalancer() +} + +// close closed the ClientConn to remote balancer, and waits until all +// goroutines to finish. +func (ccw *remoteBalancerCCWrapper) close() { + close(ccw.done) + ccw.cc.Close() + ccw.wg.Wait() +} + +func (ccw *remoteBalancerCCWrapper) readServerList(s *balanceLoadClientStream) error { + for { + reply, err := s.Recv() + if err != nil { + if err == io.EOF { + return errServerTerminatedConnection + } + return fmt.Errorf("grpclb: failed to recv server list: %v", err) + } + if serverList := reply.GetServerList(); serverList != nil { + ccw.lb.processServerList(serverList) + } + if reply.GetFallbackResponse() != nil { + // Eagerly enter fallback + ccw.lb.mu.Lock() + ccw.lb.refreshSubConns(ccw.lb.resolvedBackendAddrs, true, ccw.lb.usePickFirst) + ccw.lb.mu.Unlock() + } + } +} + +func (ccw *remoteBalancerCCWrapper) sendLoadReport(s *balanceLoadClientStream, interval time.Duration) { + ticker := time.NewTicker(interval) + defer ticker.Stop() + lastZero := false + for { + select { + case <-ticker.C: + case <-s.Context().Done(): + return + } + stats := ccw.lb.clientStats.toClientStats() + zero := isZeroStats(stats) + if zero && lastZero { + // Quash redundant empty load reports. + continue + } + lastZero = zero + t := time.Now() + stats.Timestamp = ×tamppb.Timestamp{ + Seconds: t.Unix(), + Nanos: int32(t.Nanosecond()), + } + if err := s.Send(&lbpb.LoadBalanceRequest{ + LoadBalanceRequestType: &lbpb.LoadBalanceRequest_ClientStats{ + ClientStats: stats, + }, + }); err != nil { + return + } + } +} + +func (ccw *remoteBalancerCCWrapper) callRemoteBalancer(ctx context.Context) (backoff bool, _ error) { + lbClient := &loadBalancerClient{cc: ccw.cc} + stream, err := lbClient.BalanceLoad(ctx, grpc.WaitForReady(true)) + if err != nil { + return true, fmt.Errorf("grpclb: failed to perform RPC to the remote balancer: %v", err) + } + ccw.lb.mu.Lock() + ccw.lb.remoteBalancerConnected = true + ccw.lb.mu.Unlock() + + // grpclb handshake on the stream. + initReq := &lbpb.LoadBalanceRequest{ + LoadBalanceRequestType: &lbpb.LoadBalanceRequest_InitialRequest{ + InitialRequest: &lbpb.InitialLoadBalanceRequest{ + Name: ccw.lb.target, + }, + }, + } + if err := stream.Send(initReq); err != nil { + return true, fmt.Errorf("grpclb: failed to send init request: %v", err) + } + reply, err := stream.Recv() + if err != nil { + return true, fmt.Errorf("grpclb: failed to recv init response: %v", err) + } + initResp := reply.GetInitialResponse() + if initResp == nil { + return true, fmt.Errorf("grpclb: reply from remote balancer did not include initial response") + } + + ccw.wg.Add(1) + go func() { + defer ccw.wg.Done() + if d := convertDuration(initResp.ClientStatsReportInterval); d > 0 { + ccw.sendLoadReport(stream, d) + } + }() + // No backoff if init req/resp handshake was successful. + return false, ccw.readServerList(stream) +} + +// cancelRemoteBalancerCall cancels the context used by the stream to the remote +// balancer. watchRemoteBalancer() takes care of restarting this call after the +// stream fails. +func (ccw *remoteBalancerCCWrapper) cancelRemoteBalancerCall() { + ccw.streamMu.Lock() + if ccw.streamCancel != nil { + ccw.streamCancel() + ccw.streamCancel = nil + } + ccw.streamMu.Unlock() +} + +func (ccw *remoteBalancerCCWrapper) watchRemoteBalancer() { + defer func() { + ccw.wg.Done() + ccw.streamMu.Lock() + if ccw.streamCancel != nil { + // This is to make sure that we don't leak the context when we are + // directly returning from inside of the below `for` loop. + ccw.streamCancel() + ccw.streamCancel = nil + } + ccw.streamMu.Unlock() + }() + + var retryCount int + var ctx context.Context + for { + ccw.streamMu.Lock() + if ccw.streamCancel != nil { + ccw.streamCancel() + ccw.streamCancel = nil + } + ctx, ccw.streamCancel = context.WithCancel(context.Background()) + ccw.streamMu.Unlock() + + doBackoff, err := ccw.callRemoteBalancer(ctx) + select { + case <-ccw.done: + return + default: + if err != nil { + if err == errServerTerminatedConnection { + logger.Info(err) + } else { + logger.Warning(err) + } + } + } + // Trigger a re-resolve when the stream errors. + ccw.lb.cc.cc.ResolveNow(resolver.ResolveNowOptions{}) + + ccw.lb.mu.Lock() + ccw.lb.remoteBalancerConnected = false + ccw.lb.fullServerList = nil + // Enter fallback when connection to remote balancer is lost, and the + // aggregated state is not Ready. + if !ccw.lb.inFallback && ccw.lb.state != connectivity.Ready { + // Entering fallback. + ccw.lb.refreshSubConns(ccw.lb.resolvedBackendAddrs, true, ccw.lb.usePickFirst) + } + ccw.lb.mu.Unlock() + + if !doBackoff { + retryCount = 0 + continue + } + + timer := time.NewTimer(ccw.backoff.Backoff(retryCount)) // Copy backoff + select { + case <-timer.C: + case <-ccw.done: + timer.Stop() + return + } + retryCount++ + } +} diff --git a/vendor/google.golang.org/grpc/balancer/grpclb/grpclb_util.go b/vendor/google.golang.org/grpc/balancer/grpclb/grpclb_util.go new file mode 100644 index 00000000000..373f04b98d3 --- /dev/null +++ b/vendor/google.golang.org/grpc/balancer/grpclb/grpclb_util.go @@ -0,0 +1,208 @@ +/* + * + * Copyright 2016 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package grpclb + +import ( + "fmt" + "sync" + "time" + + "google.golang.org/grpc/balancer" + "google.golang.org/grpc/resolver" +) + +// The parent ClientConn should re-resolve when grpclb loses connection to the +// remote balancer. When the ClientConn inside grpclb gets a TransientFailure, +// it calls lbManualResolver.ResolveNow(), which calls parent ClientConn's +// ResolveNow, and eventually results in re-resolve happening in parent +// ClientConn's resolver (DNS for example). +// +// parent +// ClientConn +// +-----------------------------------------------------------------+ +// | parent +---------------------------------+ | +// | DNS ClientConn | grpclb | | +// | resolver balancerWrapper | | | +// | + + | grpclb grpclb | | +// | | | | ManualResolver ClientConn | | +// | | | | + + | | +// | | | | | | Transient | | +// | | | | | | Failure | | +// | | | | | <--------- | | | +// | | | <--------------- | ResolveNow | | | +// | | <--------- | ResolveNow | | | | | +// | | ResolveNow | | | | | | +// | | | | | | | | +// | + + | + + | | +// | +---------------------------------+ | +// +-----------------------------------------------------------------+ + +// lbManualResolver is used by the ClientConn inside grpclb. It's a manual +// resolver with a special ResolveNow() function. +// +// When ResolveNow() is called, it calls ResolveNow() on the parent ClientConn, +// so when grpclb client lose contact with remote balancers, the parent +// ClientConn's resolver will re-resolve. +type lbManualResolver struct { + scheme string + ccr resolver.ClientConn + + ccb balancer.ClientConn +} + +func (r *lbManualResolver) Build(_ resolver.Target, cc resolver.ClientConn, _ resolver.BuildOptions) (resolver.Resolver, error) { + r.ccr = cc + return r, nil +} + +func (r *lbManualResolver) Scheme() string { + return r.scheme +} + +// ResolveNow calls resolveNow on the parent ClientConn. +func (r *lbManualResolver) ResolveNow(o resolver.ResolveNowOptions) { + r.ccb.ResolveNow(o) +} + +// Close is a noop for Resolver. +func (*lbManualResolver) Close() {} + +// UpdateState calls cc.UpdateState. +func (r *lbManualResolver) UpdateState(s resolver.State) { + r.ccr.UpdateState(s) +} + +const subConnCacheTime = time.Second * 10 + +// lbCacheClientConn is a wrapper balancer.ClientConn with a SubConn cache. +// SubConns will be kept in cache for subConnCacheTime before being removed. +// +// Its new and remove methods are updated to do cache first. +type lbCacheClientConn struct { + cc balancer.ClientConn + timeout time.Duration + + mu sync.Mutex + // subConnCache only keeps subConns that are being deleted. + subConnCache map[resolver.Address]*subConnCacheEntry + subConnToAddr map[balancer.SubConn]resolver.Address +} + +type subConnCacheEntry struct { + sc balancer.SubConn + + cancel func() + abortDeleting bool +} + +func newLBCacheClientConn(cc balancer.ClientConn) *lbCacheClientConn { + return &lbCacheClientConn{ + cc: cc, + timeout: subConnCacheTime, + subConnCache: make(map[resolver.Address]*subConnCacheEntry), + subConnToAddr: make(map[balancer.SubConn]resolver.Address), + } +} + +func (ccc *lbCacheClientConn) NewSubConn(addrs []resolver.Address, opts balancer.NewSubConnOptions) (balancer.SubConn, error) { + if len(addrs) != 1 { + return nil, fmt.Errorf("grpclb calling NewSubConn with addrs of length %v", len(addrs)) + } + addrWithoutAttrs := addrs[0] + addrWithoutAttrs.Attributes = nil + + ccc.mu.Lock() + defer ccc.mu.Unlock() + if entry, ok := ccc.subConnCache[addrWithoutAttrs]; ok { + // If entry is in subConnCache, the SubConn was being deleted. + // cancel function will never be nil. + entry.cancel() + delete(ccc.subConnCache, addrWithoutAttrs) + return entry.sc, nil + } + + scNew, err := ccc.cc.NewSubConn(addrs, opts) + if err != nil { + return nil, err + } + + ccc.subConnToAddr[scNew] = addrWithoutAttrs + return scNew, nil +} + +func (ccc *lbCacheClientConn) RemoveSubConn(sc balancer.SubConn) { + ccc.mu.Lock() + defer ccc.mu.Unlock() + addr, ok := ccc.subConnToAddr[sc] + if !ok { + return + } + + if entry, ok := ccc.subConnCache[addr]; ok { + if entry.sc != sc { + // This could happen if NewSubConn was called multiple times for the + // same address, and those SubConns are all removed. We remove sc + // immediately here. + delete(ccc.subConnToAddr, sc) + ccc.cc.RemoveSubConn(sc) + } + return + } + + entry := &subConnCacheEntry{ + sc: sc, + } + ccc.subConnCache[addr] = entry + + timer := time.AfterFunc(ccc.timeout, func() { + ccc.mu.Lock() + defer ccc.mu.Unlock() + if entry.abortDeleting { + return + } + ccc.cc.RemoveSubConn(sc) + delete(ccc.subConnToAddr, sc) + delete(ccc.subConnCache, addr) + }) + entry.cancel = func() { + if !timer.Stop() { + // If stop was not successful, the timer has fired (this can only + // happen in a race). But the deleting function is blocked on ccc.mu + // because the mutex was held by the caller of this function. + // + // Set abortDeleting to true to abort the deleting function. When + // the lock is released, the deleting function will acquire the + // lock, check the value of abortDeleting and return. + entry.abortDeleting = true + } + } +} + +func (ccc *lbCacheClientConn) UpdateState(s balancer.State) { + ccc.cc.UpdateState(s) +} + +func (ccc *lbCacheClientConn) close() { + ccc.mu.Lock() + // Only cancel all existing timers. There's no need to remove SubConns. + for _, entry := range ccc.subConnCache { + entry.cancel() + } + ccc.mu.Unlock() +} diff --git a/vendor/google.golang.org/grpc/balancer/grpclb/state/state.go b/vendor/google.golang.org/grpc/balancer/grpclb/state/state.go index a24264a34f5..4ecfa1c2151 100644 --- a/vendor/google.golang.org/grpc/balancer/grpclb/state/state.go +++ b/vendor/google.golang.org/grpc/balancer/grpclb/state/state.go @@ -39,7 +39,7 @@ type State struct { // Set returns a copy of the provided state with attributes containing s. s's // data should not be mutated after calling Set. func Set(state resolver.State, s *State) resolver.State { - state.Attributes = state.Attributes.WithValues(key, s) + state.Attributes = state.Attributes.WithValue(key, s) return state } diff --git a/vendor/google.golang.org/grpc/balancer/roundrobin/roundrobin.go b/vendor/google.golang.org/grpc/balancer/roundrobin/roundrobin.go index 43c2a15373a..f7031ad2251 100644 --- a/vendor/google.golang.org/grpc/balancer/roundrobin/roundrobin.go +++ b/vendor/google.golang.org/grpc/balancer/roundrobin/roundrobin.go @@ -22,7 +22,7 @@ package roundrobin import ( - "sync" + "sync/atomic" "google.golang.org/grpc/balancer" "google.golang.org/grpc/balancer/base" @@ -47,11 +47,11 @@ func init() { type rrPickerBuilder struct{} func (*rrPickerBuilder) Build(info base.PickerBuildInfo) balancer.Picker { - logger.Infof("roundrobinPicker: newPicker called with info: %v", info) + logger.Infof("roundrobinPicker: Build called with info: %v", info) if len(info.ReadySCs) == 0 { return base.NewErrPicker(balancer.ErrNoSubConnAvailable) } - var scs []balancer.SubConn + scs := make([]balancer.SubConn, 0, len(info.ReadySCs)) for sc := range info.ReadySCs { scs = append(scs, sc) } @@ -60,7 +60,7 @@ func (*rrPickerBuilder) Build(info base.PickerBuildInfo) balancer.Picker { // Start at a random index, as the same RR balancer rebuilds a new // picker when SubConn states change, and we don't want to apply excess // load to the first server in the list. - next: grpcrand.Intn(len(scs)), + next: uint32(grpcrand.Intn(len(scs))), } } @@ -69,15 +69,13 @@ type rrPicker struct { // created. The slice is immutable. Each Get() will do a round robin // selection from it and return the selected SubConn. subConns []balancer.SubConn - - mu sync.Mutex - next int + next uint32 } func (p *rrPicker) Pick(balancer.PickInfo) (balancer.PickResult, error) { - p.mu.Lock() - sc := p.subConns[p.next] - p.next = (p.next + 1) % len(p.subConns) - p.mu.Unlock() + subConnsLen := uint32(len(p.subConns)) + nextIndex := atomic.AddUint32(&p.next, 1) + + sc := p.subConns[nextIndex%subConnsLen] return balancer.PickResult{SubConn: sc}, nil } diff --git a/vendor/google.golang.org/grpc/balancer_conn_wrappers.go b/vendor/google.golang.org/grpc/balancer_conn_wrappers.go index 11e592aabb0..04b9ad41169 100644 --- a/vendor/google.golang.org/grpc/balancer_conn_wrappers.go +++ b/vendor/google.golang.org/grpc/balancer_conn_wrappers.go @@ -19,156 +19,343 @@ package grpc import ( + "context" "fmt" + "strings" "sync" "google.golang.org/grpc/balancer" "google.golang.org/grpc/connectivity" - "google.golang.org/grpc/internal/buffer" + "google.golang.org/grpc/internal/balancer/gracefulswitch" "google.golang.org/grpc/internal/channelz" "google.golang.org/grpc/internal/grpcsync" "google.golang.org/grpc/resolver" ) -// scStateUpdate contains the subConn and the new state it changed to. -type scStateUpdate struct { - sc balancer.SubConn - state connectivity.State - err error -} +type ccbMode int + +const ( + ccbModeActive = iota + ccbModeIdle + ccbModeClosed + ccbModeExitingIdle +) -// ccBalancerWrapper is a wrapper on top of cc for balancers. -// It implements balancer.ClientConn interface. +// ccBalancerWrapper sits between the ClientConn and the Balancer. +// +// ccBalancerWrapper implements methods corresponding to the ones on the +// balancer.Balancer interface. The ClientConn is free to call these methods +// concurrently and the ccBalancerWrapper ensures that calls from the ClientConn +// to the Balancer happen synchronously and in order. +// +// ccBalancerWrapper also implements the balancer.ClientConn interface and is +// passed to the Balancer implementations. It invokes unexported methods on the +// ClientConn to handle these calls from the Balancer. +// +// It uses the gracefulswitch.Balancer internally to ensure that balancer +// switches happen in a graceful manner. type ccBalancerWrapper struct { - cc *ClientConn - balancerMu sync.Mutex // synchronizes calls to the balancer - balancer balancer.Balancer - scBuffer *buffer.Unbounded - done *grpcsync.Event + // The following fields are initialized when the wrapper is created and are + // read-only afterwards, and therefore can be accessed without a mutex. + cc *ClientConn + opts balancer.BuildOptions + + // Outgoing (gRPC --> balancer) calls are guaranteed to execute in a + // mutually exclusive manner as they are scheduled in the serializer. Fields + // accessed *only* in these serializer callbacks, can therefore be accessed + // without a mutex. + balancer *gracefulswitch.Balancer + curBalancerName string - mu sync.Mutex - subConns map[*acBalancerWrapper]struct{} + // mu guards access to the below fields. Access to the serializer and its + // cancel function needs to be mutex protected because they are overwritten + // when the wrapper exits idle mode. + mu sync.Mutex + serializer *grpcsync.CallbackSerializer // To serialize all outoing calls. + serializerCancel context.CancelFunc // To close the seralizer at close/enterIdle time. + mode ccbMode // Tracks the current mode of the wrapper. } -func newCCBalancerWrapper(cc *ClientConn, b balancer.Builder, bopts balancer.BuildOptions) *ccBalancerWrapper { +// newCCBalancerWrapper creates a new balancer wrapper. The underlying balancer +// is not created until the switchTo() method is invoked. +func newCCBalancerWrapper(cc *ClientConn, bopts balancer.BuildOptions) *ccBalancerWrapper { + ctx, cancel := context.WithCancel(context.Background()) ccb := &ccBalancerWrapper{ - cc: cc, - scBuffer: buffer.NewUnbounded(), - done: grpcsync.NewEvent(), - subConns: make(map[*acBalancerWrapper]struct{}), + cc: cc, + opts: bopts, + serializer: grpcsync.NewCallbackSerializer(ctx), + serializerCancel: cancel, } - go ccb.watcher() - ccb.balancer = b.Build(ccb, bopts) + ccb.balancer = gracefulswitch.NewBalancer(ccb, bopts) return ccb } -// watcher balancer functions sequentially, so the balancer can be implemented -// lock-free. -func (ccb *ccBalancerWrapper) watcher() { - for { - select { - case t := <-ccb.scBuffer.Get(): - ccb.scBuffer.Load() - if ccb.done.HasFired() { - break +// updateClientConnState is invoked by grpc to push a ClientConnState update to +// the underlying balancer. +func (ccb *ccBalancerWrapper) updateClientConnState(ccs *balancer.ClientConnState) error { + ccb.mu.Lock() + errCh := make(chan error, 1) + // Here and everywhere else where Schedule() is called, it is done with the + // lock held. But the lock guards only the scheduling part. The actual + // callback is called asynchronously without the lock being held. + ok := ccb.serializer.Schedule(func(_ context.Context) { + // If the addresses specified in the update contain addresses of type + // "grpclb" and the selected LB policy is not "grpclb", these addresses + // will be filtered out and ccs will be modified with the updated + // address list. + if ccb.curBalancerName != grpclbName { + var addrs []resolver.Address + for _, addr := range ccs.ResolverState.Addresses { + if addr.Type == resolver.GRPCLB { + continue + } + addrs = append(addrs, addr) } - ccb.balancerMu.Lock() - su := t.(*scStateUpdate) - ccb.balancer.UpdateSubConnState(su.sc, balancer.SubConnState{ConnectivityState: su.state, ConnectionError: su.err}) - ccb.balancerMu.Unlock() - case <-ccb.done.Done(): + ccs.ResolverState.Addresses = addrs } + errCh <- ccb.balancer.UpdateClientConnState(*ccs) + }) + if !ok { + // If we are unable to schedule a function with the serializer, it + // indicates that it has been closed. A serializer is only closed when + // the wrapper is closed or is in idle. + ccb.mu.Unlock() + return fmt.Errorf("grpc: cannot send state update to a closed or idle balancer") + } + ccb.mu.Unlock() - if ccb.done.HasFired() { - ccb.balancer.Close() - ccb.mu.Lock() - scs := ccb.subConns - ccb.subConns = nil - ccb.mu.Unlock() - for acbw := range scs { - ccb.cc.removeAddrConn(acbw.getAddrConn(), errConnDrain) - } - ccb.UpdateState(balancer.State{ConnectivityState: connectivity.Connecting, Picker: nil}) + // We get here only if the above call to Schedule succeeds, in which case it + // is guaranteed that the scheduled function will run. Therefore it is safe + // to block on this channel. + err := <-errCh + if logger.V(2) && err != nil { + logger.Infof("error from balancer.UpdateClientConnState: %v", err) + } + return err +} + +// updateSubConnState is invoked by grpc to push a subConn state update to the +// underlying balancer. +func (ccb *ccBalancerWrapper) updateSubConnState(sc balancer.SubConn, s connectivity.State, err error) { + ccb.mu.Lock() + ccb.serializer.Schedule(func(_ context.Context) { + ccb.balancer.UpdateSubConnState(sc, balancer.SubConnState{ConnectivityState: s, ConnectionError: err}) + }) + ccb.mu.Unlock() +} + +func (ccb *ccBalancerWrapper) resolverError(err error) { + ccb.mu.Lock() + ccb.serializer.Schedule(func(_ context.Context) { + ccb.balancer.ResolverError(err) + }) + ccb.mu.Unlock() +} + +// switchTo is invoked by grpc to instruct the balancer wrapper to switch to the +// LB policy identified by name. +// +// ClientConn calls newCCBalancerWrapper() at creation time. Upon receipt of the +// first good update from the name resolver, it determines the LB policy to use +// and invokes the switchTo() method. Upon receipt of every subsequent update +// from the name resolver, it invokes this method. +// +// the ccBalancerWrapper keeps track of the current LB policy name, and skips +// the graceful balancer switching process if the name does not change. +func (ccb *ccBalancerWrapper) switchTo(name string) { + ccb.mu.Lock() + ccb.serializer.Schedule(func(_ context.Context) { + // TODO: Other languages use case-sensitive balancer registries. We should + // switch as well. See: https://github.com/grpc/grpc-go/issues/5288. + if strings.EqualFold(ccb.curBalancerName, name) { return } + ccb.buildLoadBalancingPolicy(name) + }) + ccb.mu.Unlock() +} + +// buildLoadBalancingPolicy performs the following: +// - retrieve a balancer builder for the given name. Use the default LB +// policy, pick_first, if no LB policy with name is found in the registry. +// - instruct the gracefulswitch balancer to switch to the above builder. This +// will actually build the new balancer. +// - update the `curBalancerName` field +// +// Must be called from a serializer callback. +func (ccb *ccBalancerWrapper) buildLoadBalancingPolicy(name string) { + builder := balancer.Get(name) + if builder == nil { + channelz.Warningf(logger, ccb.cc.channelzID, "Channel switches to new LB policy %q, since the specified LB policy %q was not registered", PickFirstBalancerName, name) + builder = newPickfirstBuilder() + } else { + channelz.Infof(logger, ccb.cc.channelzID, "Channel switches to new LB policy %q", name) + } + + if err := ccb.balancer.SwitchTo(builder); err != nil { + channelz.Errorf(logger, ccb.cc.channelzID, "Channel failed to build new LB policy %q: %v", name, err) + return } + ccb.curBalancerName = builder.Name() } func (ccb *ccBalancerWrapper) close() { - ccb.done.Fire() -} - -func (ccb *ccBalancerWrapper) handleSubConnStateChange(sc balancer.SubConn, s connectivity.State, err error) { - // When updating addresses for a SubConn, if the address in use is not in - // the new addresses, the old ac will be tearDown() and a new ac will be - // created. tearDown() generates a state change with Shutdown state, we - // don't want the balancer to receive this state change. So before - // tearDown() on the old ac, ac.acbw (acWrapper) will be set to nil, and - // this function will be called with (nil, Shutdown). We don't need to call - // balancer method in this case. - if sc == nil { + channelz.Info(logger, ccb.cc.channelzID, "ccBalancerWrapper: closing") + ccb.closeBalancer(ccbModeClosed) +} + +// enterIdleMode is invoked by grpc when the channel enters idle mode upon +// expiry of idle_timeout. This call blocks until the balancer is closed. +func (ccb *ccBalancerWrapper) enterIdleMode() { + channelz.Info(logger, ccb.cc.channelzID, "ccBalancerWrapper: entering idle mode") + ccb.closeBalancer(ccbModeIdle) +} + +// closeBalancer is invoked when the channel is being closed or when it enters +// idle mode upon expiry of idle_timeout. +func (ccb *ccBalancerWrapper) closeBalancer(m ccbMode) { + ccb.mu.Lock() + if ccb.mode == ccbModeClosed || ccb.mode == ccbModeIdle { + ccb.mu.Unlock() return } - ccb.scBuffer.Put(&scStateUpdate{ - sc: sc, - state: s, - err: err, + + ccb.mode = m + done := ccb.serializer.Done + b := ccb.balancer + ok := ccb.serializer.Schedule(func(_ context.Context) { + // Close the serializer to ensure that no more calls from gRPC are sent + // to the balancer. + ccb.serializerCancel() + // Empty the current balancer name because we don't have a balancer + // anymore and also so that we act on the next call to switchTo by + // creating a new balancer specified by the new resolver. + ccb.curBalancerName = "" }) + if !ok { + ccb.mu.Unlock() + return + } + ccb.mu.Unlock() + + // Give enqueued callbacks a chance to finish. + <-done + // Spawn a goroutine to close the balancer (since it may block trying to + // cleanup all allocated resources) and return early. + go b.Close() } -func (ccb *ccBalancerWrapper) updateClientConnState(ccs *balancer.ClientConnState) error { - ccb.balancerMu.Lock() - defer ccb.balancerMu.Unlock() - return ccb.balancer.UpdateClientConnState(*ccs) +// exitIdleMode is invoked by grpc when the channel exits idle mode either +// because of an RPC or because of an invocation of the Connect() API. This +// recreates the balancer that was closed previously when entering idle mode. +// +// If the channel is not in idle mode, we know for a fact that we are here as a +// result of the user calling the Connect() method on the ClientConn. In this +// case, we can simply forward the call to the underlying balancer, instructing +// it to reconnect to the backends. +func (ccb *ccBalancerWrapper) exitIdleMode() { + ccb.mu.Lock() + if ccb.mode == ccbModeClosed { + // Request to exit idle is a no-op when wrapper is already closed. + ccb.mu.Unlock() + return + } + + if ccb.mode == ccbModeIdle { + // Recreate the serializer which was closed when we entered idle. + ctx, cancel := context.WithCancel(context.Background()) + ccb.serializer = grpcsync.NewCallbackSerializer(ctx) + ccb.serializerCancel = cancel + } + + // The ClientConn guarantees that mutual exclusion between close() and + // exitIdleMode(), and since we just created a new serializer, we can be + // sure that the below function will be scheduled. + done := make(chan struct{}) + ccb.serializer.Schedule(func(_ context.Context) { + defer close(done) + + ccb.mu.Lock() + defer ccb.mu.Unlock() + + if ccb.mode != ccbModeIdle { + ccb.balancer.ExitIdle() + return + } + + // Gracefulswitch balancer does not support a switchTo operation after + // being closed. Hence we need to create a new one here. + ccb.balancer = gracefulswitch.NewBalancer(ccb, ccb.opts) + ccb.mode = ccbModeActive + channelz.Info(logger, ccb.cc.channelzID, "ccBalancerWrapper: exiting idle mode") + + }) + ccb.mu.Unlock() + + <-done } -func (ccb *ccBalancerWrapper) resolverError(err error) { - ccb.balancerMu.Lock() - ccb.balancer.ResolverError(err) - ccb.balancerMu.Unlock() +func (ccb *ccBalancerWrapper) isIdleOrClosed() bool { + ccb.mu.Lock() + defer ccb.mu.Unlock() + return ccb.mode == ccbModeIdle || ccb.mode == ccbModeClosed } func (ccb *ccBalancerWrapper) NewSubConn(addrs []resolver.Address, opts balancer.NewSubConnOptions) (balancer.SubConn, error) { - if len(addrs) <= 0 { - return nil, fmt.Errorf("grpc: cannot create SubConn with empty address list") + if ccb.isIdleOrClosed() { + return nil, fmt.Errorf("grpc: cannot create SubConn when balancer is closed or idle") } - ccb.mu.Lock() - defer ccb.mu.Unlock() - if ccb.subConns == nil { - return nil, fmt.Errorf("grpc: ClientConn balancer wrapper was closed") + + if len(addrs) == 0 { + return nil, fmt.Errorf("grpc: cannot create SubConn with empty address list") } ac, err := ccb.cc.newAddrConn(addrs, opts) if err != nil { + channelz.Warningf(logger, ccb.cc.channelzID, "acBalancerWrapper: NewSubConn: failed to newAddrConn: %v", err) return nil, err } - acbw := &acBalancerWrapper{ac: ac} - acbw.ac.mu.Lock() + acbw := &acBalancerWrapper{ac: ac, producers: make(map[balancer.ProducerBuilder]*refCountedProducer)} ac.acbw = acbw - acbw.ac.mu.Unlock() - ccb.subConns[acbw] = struct{}{} return acbw, nil } func (ccb *ccBalancerWrapper) RemoveSubConn(sc balancer.SubConn) { + if ccb.isIdleOrClosed() { + // It it safe to ignore this call when the balancer is closed or in idle + // because the ClientConn takes care of closing the connections. + // + // Not returning early from here when the balancer is closed or in idle + // leads to a deadlock though, because of the following sequence of + // calls when holding cc.mu: + // cc.exitIdleMode --> ccb.enterIdleMode --> gsw.Close --> + // ccb.RemoveAddrConn --> cc.removeAddrConn + return + } + acbw, ok := sc.(*acBalancerWrapper) if !ok { return } - ccb.mu.Lock() - defer ccb.mu.Unlock() - if ccb.subConns == nil { + ccb.cc.removeAddrConn(acbw.ac, errConnDrain) +} + +func (ccb *ccBalancerWrapper) UpdateAddresses(sc balancer.SubConn, addrs []resolver.Address) { + if ccb.isIdleOrClosed() { return } - delete(ccb.subConns, acbw) - ccb.cc.removeAddrConn(acbw.getAddrConn(), errConnDrain) + + acbw, ok := sc.(*acBalancerWrapper) + if !ok { + return + } + acbw.UpdateAddresses(addrs) } func (ccb *ccBalancerWrapper) UpdateState(s balancer.State) { - ccb.mu.Lock() - defer ccb.mu.Unlock() - if ccb.subConns == nil { + if ccb.isIdleOrClosed() { return } + // Update picker before updating state. Even though the ordering here does // not matter, it can lead to multiple calls of Pick in the common start-up // case where we wait for ready and then perform an RPC. If the picker is @@ -179,6 +366,10 @@ func (ccb *ccBalancerWrapper) UpdateState(s balancer.State) { } func (ccb *ccBalancerWrapper) ResolveNow(o resolver.ResolveNowOptions) { + if ccb.isIdleOrClosed() { + return + } + ccb.cc.resolveNow(o) } @@ -189,58 +380,80 @@ func (ccb *ccBalancerWrapper) Target() string { // acBalancerWrapper is a wrapper on top of ac for balancers. // It implements balancer.SubConn interface. type acBalancerWrapper struct { - mu sync.Mutex - ac *addrConn + ac *addrConn // read-only + + mu sync.Mutex + producers map[balancer.ProducerBuilder]*refCountedProducer +} + +func (acbw *acBalancerWrapper) String() string { + return fmt.Sprintf("SubConn(id:%d)", acbw.ac.channelzID.Int()) } func (acbw *acBalancerWrapper) UpdateAddresses(addrs []resolver.Address) { - acbw.mu.Lock() - defer acbw.mu.Unlock() - if len(addrs) <= 0 { - acbw.ac.tearDown(errConnDrain) - return + acbw.ac.updateAddrs(addrs) +} + +func (acbw *acBalancerWrapper) Connect() { + go acbw.ac.connect() +} + +// NewStream begins a streaming RPC on the addrConn. If the addrConn is not +// ready, blocks until it is or ctx expires. Returns an error when the context +// expires or the addrConn is shut down. +func (acbw *acBalancerWrapper) NewStream(ctx context.Context, desc *StreamDesc, method string, opts ...CallOption) (ClientStream, error) { + transport, err := acbw.ac.getTransport(ctx) + if err != nil { + return nil, err } - if !acbw.ac.tryUpdateAddrs(addrs) { - cc := acbw.ac.cc - opts := acbw.ac.scopts - acbw.ac.mu.Lock() - // Set old ac.acbw to nil so the Shutdown state update will be ignored - // by balancer. - // - // TODO(bar) the state transition could be wrong when tearDown() old ac - // and creating new ac, fix the transition. - acbw.ac.acbw = nil - acbw.ac.mu.Unlock() - acState := acbw.ac.getState() - acbw.ac.tearDown(errConnDrain) - - if acState == connectivity.Shutdown { - return - } + return newNonRetryClientStream(ctx, desc, method, transport, acbw.ac, opts...) +} - ac, err := cc.newAddrConn(addrs, opts) - if err != nil { - channelz.Warningf(logger, acbw.ac.channelzID, "acBalancerWrapper: UpdateAddresses: failed to newAddrConn: %v", err) - return - } - acbw.ac = ac - ac.mu.Lock() - ac.acbw = acbw - ac.mu.Unlock() - if acState != connectivity.Idle { - ac.connect() - } +// Invoke performs a unary RPC. If the addrConn is not ready, returns +// errSubConnNotReady. +func (acbw *acBalancerWrapper) Invoke(ctx context.Context, method string, args interface{}, reply interface{}, opts ...CallOption) error { + cs, err := acbw.NewStream(ctx, unaryStreamDesc, method, opts...) + if err != nil { + return err } + if err := cs.SendMsg(args); err != nil { + return err + } + return cs.RecvMsg(reply) } -func (acbw *acBalancerWrapper) Connect() { - acbw.mu.Lock() - defer acbw.mu.Unlock() - acbw.ac.connect() +type refCountedProducer struct { + producer balancer.Producer + refs int // number of current refs to the producer + close func() // underlying producer's close function } -func (acbw *acBalancerWrapper) getAddrConn() *addrConn { +func (acbw *acBalancerWrapper) GetOrBuildProducer(pb balancer.ProducerBuilder) (balancer.Producer, func()) { acbw.mu.Lock() defer acbw.mu.Unlock() - return acbw.ac + + // Look up existing producer from this builder. + pData := acbw.producers[pb] + if pData == nil { + // Not found; create a new one and add it to the producers map. + p, close := pb.Build(acbw) + pData = &refCountedProducer{producer: p, close: close} + acbw.producers[pb] = pData + } + // Account for this new reference. + pData.refs++ + + // Return a cleanup function wrapped in a OnceFunc to remove this reference + // and delete the refCountedProducer from the map if the total reference + // count goes to zero. + unref := func() { + acbw.mu.Lock() + pData.refs-- + if pData.refs == 0 { + defer pData.close() // Run outside the acbw mutex + delete(acbw.producers, pb) + } + acbw.mu.Unlock() + } + return pData.producer, grpcsync.OnceFunc(unref) } diff --git a/vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go b/vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go index ed75290cdf3..ec2c2fa14dd 100644 --- a/vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go +++ b/vendor/google.golang.org/grpc/binarylog/grpc_binarylog_v1/binarylog.pb.go @@ -18,14 +18,13 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.25.0 -// protoc v3.14.0 +// protoc-gen-go v1.30.0 +// protoc v4.22.0 // source: grpc/binlog/v1/binarylog.proto package grpc_binarylog_v1 import ( - proto "github.com/golang/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" durationpb "google.golang.org/protobuf/types/known/durationpb" @@ -41,10 +40,6 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - // Enumerates the type of event // Note the terminology is different from the RPC semantics // definition, but the same meaning is expressed here. @@ -261,6 +256,7 @@ type GrpcLogEntry struct { // according to the type of the log entry. // // Types that are assignable to Payload: + // // *GrpcLogEntry_ClientHeader // *GrpcLogEntry_ServerHeader // *GrpcLogEntry_Message @@ -694,12 +690,12 @@ func (x *Message) GetData() []byte { // Header keys added by gRPC are omitted. To be more specific, // implementations will not log the following entries, and this is // not to be treated as a truncation: -// - entries handled by grpc that are not user visible, such as those -// that begin with 'grpc-' (with exception of grpc-trace-bin) -// or keys like 'lb-token' -// - transport specific entries, including but not limited to: -// ':path', ':authority', 'content-encoding', 'user-agent', 'te', etc -// - entries added for call credentials +// - entries handled by grpc that are not user visible, such as those +// that begin with 'grpc-' (with exception of grpc-trace-bin) +// or keys like 'lb-token' +// - transport specific entries, including but not limited to: +// ':path', ':authority', 'content-encoding', 'user-agent', 'te', etc +// - entries added for call credentials // // Implementations must always log grpc-trace-bin if it is present. // Practically speaking it will only be visible on server side because diff --git a/vendor/google.golang.org/grpc/call.go b/vendor/google.golang.org/grpc/call.go index 9e20e4d385f..e6a1dc5d75e 100644 --- a/vendor/google.golang.org/grpc/call.go +++ b/vendor/google.golang.org/grpc/call.go @@ -27,6 +27,11 @@ import ( // // All errors returned by Invoke are compatible with the status package. func (cc *ClientConn) Invoke(ctx context.Context, method string, args, reply interface{}, opts ...CallOption) error { + if err := cc.idlenessMgr.onCallBegin(); err != nil { + return err + } + defer cc.idlenessMgr.onCallEnd() + // allow interceptor to see all applicable call options, which means those // configured as defaults from dial option as well as per-call options opts = combine(cc.dopts.callOptions, opts) diff --git a/vendor/google.golang.org/grpc/channelz/channelz.go b/vendor/google.golang.org/grpc/channelz/channelz.go new file mode 100644 index 00000000000..32b7fa5794e --- /dev/null +++ b/vendor/google.golang.org/grpc/channelz/channelz.go @@ -0,0 +1,36 @@ +/* + * + * Copyright 2020 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Package channelz exports internals of the channelz implementation as required +// by other gRPC packages. +// +// The implementation of the channelz spec as defined in +// https://github.com/grpc/proposal/blob/master/A14-channelz.md, is provided by +// the `internal/channelz` package. +// +// # Experimental +// +// Notice: All APIs in this package are experimental and may be removed in a +// later release. +package channelz + +import "google.golang.org/grpc/internal/channelz" + +// Identifier is an opaque identifier which uniquely identifies an entity in the +// channelz database. +type Identifier = channelz.Identifier diff --git a/vendor/google.golang.org/grpc/clientconn.go b/vendor/google.golang.org/grpc/clientconn.go index 77a08fd33bf..95a7459b02f 100644 --- a/vendor/google.golang.org/grpc/clientconn.go +++ b/vendor/google.golang.org/grpc/clientconn.go @@ -23,7 +23,7 @@ import ( "errors" "fmt" "math" - "reflect" + "net/url" "strings" "sync" "sync/atomic" @@ -37,7 +37,6 @@ import ( "google.golang.org/grpc/internal/backoff" "google.golang.org/grpc/internal/channelz" "google.golang.org/grpc/internal/grpcsync" - "google.golang.org/grpc/internal/grpcutil" iresolver "google.golang.org/grpc/internal/resolver" "google.golang.org/grpc/internal/transport" "google.golang.org/grpc/keepalive" @@ -69,6 +68,9 @@ var ( errConnDrain = errors.New("grpc: the connection is drained") // errConnClosing indicates that the connection is closing. errConnClosing = errors.New("grpc: the connection is closing") + // errConnIdling indicates the the connection is being closed as the channel + // is moving to an idle mode due to inactivity. + errConnIdling = errors.New("grpc: the connection is closing due to channel idleness") // invalidDefaultServiceConfigErrPrefix is used to prefix the json parsing error for the default // service config. invalidDefaultServiceConfigErrPrefix = "grpc: the provided default service config is invalid" @@ -79,17 +81,17 @@ var ( // errNoTransportSecurity indicates that there is no transport security // being set for ClientConn. Users should either set one or explicitly // call WithInsecure DialOption to disable security. - errNoTransportSecurity = errors.New("grpc: no transport security set (use grpc.WithInsecure() explicitly or set credentials)") + errNoTransportSecurity = errors.New("grpc: no transport security set (use grpc.WithTransportCredentials(insecure.NewCredentials()) explicitly or set credentials)") // errTransportCredsAndBundle indicates that creds bundle is used together // with other individual Transport Credentials. errTransportCredsAndBundle = errors.New("grpc: credentials.Bundle may not be used with individual TransportCredentials") - // errTransportCredentialsMissing indicates that users want to transmit security - // information (e.g., OAuth2 token) which requires secure connection on an insecure - // connection. + // errNoTransportCredsInBundle indicated that the configured creds bundle + // returned a transport credentials which was nil. + errNoTransportCredsInBundle = errors.New("grpc: credentials.Bundle must return non-nil transport credentials") + // errTransportCredentialsMissing indicates that users want to transmit + // security information (e.g., OAuth2 token) which requires secure + // connection on an insecure connection. errTransportCredentialsMissing = errors.New("grpc: the credentials require transport level security (use grpc.WithTransportCredentials() to set)") - // errCredentialsConflict indicates that grpc.WithTransportCredentials() - // and grpc.WithInsecure() are both called for a connection. - errCredentialsConflict = errors.New("grpc: transport credentials are set for an insecure connection (grpc.WithTransportCredentials() and grpc.WithInsecure() are both called)") ) const ( @@ -134,16 +136,43 @@ func (dcs *defaultConfigSelector) SelectConfig(rpcInfo iresolver.RPCInfo) (*ires // e.g. to use dns resolver, a "dns:///" prefix should be applied to the target. func DialContext(ctx context.Context, target string, opts ...DialOption) (conn *ClientConn, err error) { cc := &ClientConn{ - target: target, - csMgr: &connectivityStateManager{}, - conns: make(map[*addrConn]struct{}), - dopts: defaultDialOptions(), - blockingpicker: newPickerWrapper(), - czData: new(channelzData), - firstResolveEvent: grpcsync.NewEvent(), - } + target: target, + csMgr: &connectivityStateManager{}, + conns: make(map[*addrConn]struct{}), + dopts: defaultDialOptions(), + czData: new(channelzData), + } + + // We start the channel off in idle mode, but kick it out of idle at the end + // of this method, instead of waiting for the first RPC. Other gRPC + // implementations do wait for the first RPC to kick the channel out of + // idle. But doing so would be a major behavior change for our users who are + // used to seeing the channel active after Dial. + // + // Taking this approach of kicking it out of idle at the end of this method + // allows us to share the code between channel creation and exiting idle + // mode. This will also make it easy for us to switch to starting the + // channel off in idle, if at all we ever get to do that. + cc.idlenessState = ccIdlenessStateIdle + cc.retryThrottler.Store((*retryThrottler)(nil)) + cc.safeConfigSelector.UpdateConfigSelector(&defaultConfigSelector{nil}) cc.ctx, cc.cancel = context.WithCancel(context.Background()) + cc.exitIdleCond = sync.NewCond(&cc.mu) + + disableGlobalOpts := false + for _, opt := range opts { + if _, ok := opt.(*disableGlobalDialOptions); ok { + disableGlobalOpts = true + break + } + } + + if !disableGlobalOpts { + for _, opt := range globalDialOptions { + opt.apply(&cc.dopts) + } + } for _, opt := range opts { opt.apply(&cc.dopts) @@ -158,40 +187,11 @@ func DialContext(ctx context.Context, target string, opts ...DialOption) (conn * } }() - if channelz.IsOn() { - if cc.dopts.channelzParentID != 0 { - cc.channelzID = channelz.RegisterChannel(&channelzChannel{cc}, cc.dopts.channelzParentID, target) - channelz.AddTraceEvent(logger, cc.channelzID, 0, &channelz.TraceEventDesc{ - Desc: "Channel Created", - Severity: channelz.CtInfo, - Parent: &channelz.TraceEventDesc{ - Desc: fmt.Sprintf("Nested Channel(id:%d) created", cc.channelzID), - Severity: channelz.CtInfo, - }, - }) - } else { - cc.channelzID = channelz.RegisterChannel(&channelzChannel{cc}, 0, target) - channelz.Info(logger, cc.channelzID, "Channel Created") - } - cc.csMgr.channelzID = cc.channelzID - } + // Register ClientConn with channelz. + cc.channelzRegistration(target) - if !cc.dopts.insecure { - if cc.dopts.copts.TransportCredentials == nil && cc.dopts.copts.CredsBundle == nil { - return nil, errNoTransportSecurity - } - if cc.dopts.copts.TransportCredentials != nil && cc.dopts.copts.CredsBundle != nil { - return nil, errTransportCredsAndBundle - } - } else { - if cc.dopts.copts.TransportCredentials != nil || cc.dopts.copts.CredsBundle != nil { - return nil, errCredentialsConflict - } - for _, cd := range cc.dopts.copts.PerRPCCredentials { - if cd.RequireTransportSecurity() { - return nil, errTransportCredentialsMissing - } - } + if err := cc.validateTransportCredentials(); err != nil { + return nil, err } if cc.dopts.defaultServiceConfigRawJSON != nil { @@ -229,58 +229,19 @@ func DialContext(ctx context.Context, target string, opts ...DialOption) (conn * } }() - scSet := false - if cc.dopts.scChan != nil { - // Try to get an initial service config. - select { - case sc, ok := <-cc.dopts.scChan: - if ok { - cc.sc = &sc - cc.safeConfigSelector.UpdateConfigSelector(&defaultConfigSelector{&sc}) - scSet = true - } - default: - } - } if cc.dopts.bs == nil { cc.dopts.bs = backoff.DefaultExponential } // Determine the resolver to use. - cc.parsedTarget = grpcutil.ParseTarget(cc.target, cc.dopts.copts.Dialer != nil) - channelz.Infof(logger, cc.channelzID, "parsed scheme: %q", cc.parsedTarget.Scheme) - resolverBuilder := cc.getResolver(cc.parsedTarget.Scheme) - if resolverBuilder == nil { - // If resolver builder is still nil, the parsed target's scheme is - // not registered. Fallback to default resolver and set Endpoint to - // the original target. - channelz.Infof(logger, cc.channelzID, "scheme %q not registered, fallback to default scheme", cc.parsedTarget.Scheme) - cc.parsedTarget = resolver.Target{ - Scheme: resolver.GetDefaultScheme(), - Endpoint: target, - } - resolverBuilder = cc.getResolver(cc.parsedTarget.Scheme) - if resolverBuilder == nil { - return nil, fmt.Errorf("could not get resolver for default scheme: %q", cc.parsedTarget.Scheme) - } + if err := cc.parseTargetAndFindResolver(); err != nil { + return nil, err } - - creds := cc.dopts.copts.TransportCredentials - if creds != nil && creds.Info().ServerName != "" { - cc.authority = creds.Info().ServerName - } else if cc.dopts.insecure && cc.dopts.authority != "" { - cc.authority = cc.dopts.authority - } else if strings.HasPrefix(cc.target, "unix:") || strings.HasPrefix(cc.target, "unix-abstract:") { - cc.authority = "localhost" - } else if strings.HasPrefix(cc.parsedTarget.Endpoint, ":") { - cc.authority = "localhost" + cc.parsedTarget.Endpoint - } else { - // Use endpoint from "scheme://authority/endpoint" as the default - // authority for ClientConn. - cc.authority = cc.parsedTarget.Endpoint + if err = cc.determineAuthority(); err != nil { + return nil, err } - if cc.dopts.scChan != nil && !scSet { + if cc.dopts.scChan != nil { // Blocking wait for the initial service config. select { case sc, ok := <-cc.dopts.scChan: @@ -296,55 +257,224 @@ func DialContext(ctx context.Context, target string, opts ...DialOption) (conn * go cc.scWatcher() } + // This creates the name resolver, load balancer, blocking picker etc. + if err := cc.exitIdleMode(); err != nil { + return nil, err + } + + // Configure idleness support with configured idle timeout or default idle + // timeout duration. Idleness can be explicitly disabled by the user, by + // setting the dial option to 0. + cc.idlenessMgr = newIdlenessManager(cc, cc.dopts.idleTimeout) + + // Return early for non-blocking dials. + if !cc.dopts.block { + return cc, nil + } + + // A blocking dial blocks until the clientConn is ready. + for { + s := cc.GetState() + if s == connectivity.Idle { + cc.Connect() + } + if s == connectivity.Ready { + return cc, nil + } else if cc.dopts.copts.FailOnNonTempDialError && s == connectivity.TransientFailure { + if err = cc.connectionError(); err != nil { + terr, ok := err.(interface { + Temporary() bool + }) + if ok && !terr.Temporary() { + return nil, err + } + } + } + if !cc.WaitForStateChange(ctx, s) { + // ctx got timeout or canceled. + if err = cc.connectionError(); err != nil && cc.dopts.returnLastError { + return nil, err + } + return nil, ctx.Err() + } + } +} + +// addTraceEvent is a helper method to add a trace event on the channel. If the +// channel is a nested one, the same event is also added on the parent channel. +func (cc *ClientConn) addTraceEvent(msg string) { + ted := &channelz.TraceEventDesc{ + Desc: fmt.Sprintf("Channel %s", msg), + Severity: channelz.CtInfo, + } + if cc.dopts.channelzParentID != nil { + ted.Parent = &channelz.TraceEventDesc{ + Desc: fmt.Sprintf("Nested channel(id:%d) %s", cc.channelzID.Int(), msg), + Severity: channelz.CtInfo, + } + } + channelz.AddTraceEvent(logger, cc.channelzID, 0, ted) +} + +// exitIdleMode moves the channel out of idle mode by recreating the name +// resolver and load balancer. +func (cc *ClientConn) exitIdleMode() error { + cc.mu.Lock() + if cc.conns == nil { + cc.mu.Unlock() + return errConnClosing + } + if cc.idlenessState != ccIdlenessStateIdle { + cc.mu.Unlock() + logger.Info("ClientConn asked to exit idle mode when not in idle mode") + return nil + } + + defer func() { + // When Close() and exitIdleMode() race against each other, one of the + // following two can happen: + // - Close() wins the race and runs first. exitIdleMode() runs after, and + // sees that the ClientConn is already closed and hence returns early. + // - exitIdleMode() wins the race and runs first and recreates the balancer + // and releases the lock before recreating the resolver. If Close() runs + // in this window, it will wait for exitIdleMode to complete. + // + // We achieve this synchronization using the below condition variable. + cc.mu.Lock() + cc.idlenessState = ccIdlenessStateActive + cc.exitIdleCond.Signal() + cc.mu.Unlock() + }() + + cc.idlenessState = ccIdlenessStateExitingIdle + exitedIdle := false + if cc.blockingpicker == nil { + cc.blockingpicker = newPickerWrapper() + } else { + cc.blockingpicker.exitIdleMode() + exitedIdle = true + } + var credsClone credentials.TransportCredentials if creds := cc.dopts.copts.TransportCredentials; creds != nil { credsClone = creds.Clone() } - cc.balancerBuildOpts = balancer.BuildOptions{ - DialCreds: credsClone, - CredsBundle: cc.dopts.copts.CredsBundle, - Dialer: cc.dopts.copts.Dialer, - CustomUserAgent: cc.dopts.copts.UserAgent, - ChannelzParentID: cc.channelzID, - Target: cc.parsedTarget, + if cc.balancerWrapper == nil { + cc.balancerWrapper = newCCBalancerWrapper(cc, balancer.BuildOptions{ + DialCreds: credsClone, + CredsBundle: cc.dopts.copts.CredsBundle, + Dialer: cc.dopts.copts.Dialer, + Authority: cc.authority, + CustomUserAgent: cc.dopts.copts.UserAgent, + ChannelzParentID: cc.channelzID, + Target: cc.parsedTarget, + }) + } else { + cc.balancerWrapper.exitIdleMode() } + cc.firstResolveEvent = grpcsync.NewEvent() + cc.mu.Unlock() - // Build the resolver. - rWrapper, err := newCCResolverWrapper(cc, resolverBuilder) - if err != nil { - return nil, fmt.Errorf("failed to build resolver: %v", err) + // This needs to be called without cc.mu because this builds a new resolver + // which might update state or report error inline which needs to be handled + // by cc.updateResolverState() which also grabs cc.mu. + if err := cc.initResolverWrapper(credsClone); err != nil { + return err } + + if exitedIdle { + cc.addTraceEvent("exiting idle mode") + } + return nil +} + +// enterIdleMode puts the channel in idle mode, and as part of it shuts down the +// name resolver, load balancer and any subchannels. +func (cc *ClientConn) enterIdleMode() error { cc.mu.Lock() - cc.resolverWrapper = rWrapper + if cc.conns == nil { + cc.mu.Unlock() + return ErrClientConnClosing + } + if cc.idlenessState != ccIdlenessStateActive { + logger.Error("ClientConn asked to enter idle mode when not active") + return nil + } + + // cc.conns == nil is a proxy for the ClientConn being closed. So, instead + // of setting it to nil here, we recreate the map. This also means that we + // don't have to do this when exiting idle mode. + conns := cc.conns + cc.conns = make(map[*addrConn]struct{}) + + // TODO: Currently, we close the resolver wrapper upon entering idle mode + // and create a new one upon exiting idle mode. This means that the + // `cc.resolverWrapper` field would be overwritten everytime we exit idle + // mode. While this means that we need to hold `cc.mu` when accessing + // `cc.resolverWrapper`, it makes the code simpler in the wrapper. We should + // try to do the same for the balancer and picker wrappers too. + cc.resolverWrapper.close() + cc.blockingpicker.enterIdleMode() + cc.balancerWrapper.enterIdleMode() + cc.csMgr.updateState(connectivity.Idle) + cc.idlenessState = ccIdlenessStateIdle cc.mu.Unlock() - // A blocking dial blocks until the clientConn is ready. - if cc.dopts.block { - for { - s := cc.GetState() - if s == connectivity.Ready { - break - } else if cc.dopts.copts.FailOnNonTempDialError && s == connectivity.TransientFailure { - if err = cc.connectionError(); err != nil { - terr, ok := err.(interface { - Temporary() bool - }) - if ok && !terr.Temporary() { - return nil, err - } - } - } - if !cc.WaitForStateChange(ctx, s) { - // ctx got timeout or canceled. - if err = cc.connectionError(); err != nil && cc.dopts.returnLastError { - return nil, err - } - return nil, ctx.Err() + go func() { + cc.addTraceEvent("entering idle mode") + for ac := range conns { + ac.tearDown(errConnIdling) + } + }() + return nil +} + +// validateTransportCredentials performs a series of checks on the configured +// transport credentials. It returns a non-nil error if any of these conditions +// are met: +// - no transport creds and no creds bundle is configured +// - both transport creds and creds bundle are configured +// - creds bundle is configured, but it lacks a transport credentials +// - insecure transport creds configured alongside call creds that require +// transport level security +// +// If none of the above conditions are met, the configured credentials are +// deemed valid and a nil error is returned. +func (cc *ClientConn) validateTransportCredentials() error { + if cc.dopts.copts.TransportCredentials == nil && cc.dopts.copts.CredsBundle == nil { + return errNoTransportSecurity + } + if cc.dopts.copts.TransportCredentials != nil && cc.dopts.copts.CredsBundle != nil { + return errTransportCredsAndBundle + } + if cc.dopts.copts.CredsBundle != nil && cc.dopts.copts.CredsBundle.TransportCredentials() == nil { + return errNoTransportCredsInBundle + } + transportCreds := cc.dopts.copts.TransportCredentials + if transportCreds == nil { + transportCreds = cc.dopts.copts.CredsBundle.TransportCredentials() + } + if transportCreds.Info().SecurityProtocol == "insecure" { + for _, cd := range cc.dopts.copts.PerRPCCredentials { + if cd.RequireTransportSecurity() { + return errTransportCredentialsMissing } } } + return nil +} - return cc, nil +// channelzRegistration registers the newly created ClientConn with channelz and +// stores the returned identifier in `cc.channelzID` and `cc.csMgr.channelzID`. +// A channelz trace event is emitted for ClientConn creation. If the newly +// created ClientConn is a nested one, i.e a valid parent ClientConn ID is +// specified via a dial option, the trace event is also added to the parent. +// +// Doesn't grab cc.mu as this method is expected to be called only at Dial time. +func (cc *ClientConn) channelzRegistration(target string) { + cc.channelzID = channelz.RegisterChannel(&channelzChannel{cc}, cc.dopts.channelzParentID, target) + cc.addTraceEvent("created") + cc.csMgr.channelzID = cc.channelzID } // chainUnaryClientInterceptors chains all unary client interceptors into one. @@ -415,7 +545,7 @@ type connectivityStateManager struct { mu sync.Mutex state connectivity.State notifyChan chan struct{} - channelzID int64 + channelzID *channelz.Identifier } // updateState updates the connectivity.State of ClientConn. @@ -481,43 +611,67 @@ var _ ClientConnInterface = (*ClientConn)(nil) // handshakes. It also handles errors on established connections by // re-resolving the name and reconnecting. type ClientConn struct { - ctx context.Context - cancel context.CancelFunc - - target string - parsedTarget resolver.Target - authority string - dopts dialOptions - csMgr *connectivityStateManager - - balancerBuildOpts balancer.BuildOptions - blockingpicker *pickerWrapper - + ctx context.Context // Initialized using the background context at dial time. + cancel context.CancelFunc // Cancelled on close. + + // The following are initialized at dial time, and are read-only after that. + target string // User's dial target. + parsedTarget resolver.Target // See parseTargetAndFindResolver(). + authority string // See determineAuthority(). + dopts dialOptions // Default and user specified dial options. + channelzID *channelz.Identifier // Channelz identifier for the channel. + resolverBuilder resolver.Builder // See parseTargetAndFindResolver(). + balancerWrapper *ccBalancerWrapper // Uses gracefulswitch.balancer underneath. + idlenessMgr idlenessManager + + // The following provide their own synchronization, and therefore don't + // require cc.mu to be held to access them. + csMgr *connectivityStateManager + blockingpicker *pickerWrapper safeConfigSelector iresolver.SafeConfigSelector + czData *channelzData + retryThrottler atomic.Value // Updated from service config. - mu sync.RWMutex - resolverWrapper *ccResolverWrapper - sc *ServiceConfig - conns map[*addrConn]struct{} - // Keepalive parameter can be updated if a GoAway is received. - mkp keepalive.ClientParameters - curBalancerName string - balancerWrapper *ccBalancerWrapper - retryThrottler atomic.Value - + // firstResolveEvent is used to track whether the name resolver sent us at + // least one update. RPCs block on this event. firstResolveEvent *grpcsync.Event - channelzID int64 // channelz unique identification number - czData *channelzData + // mu protects the following fields. + // TODO: split mu so the same mutex isn't used for everything. + mu sync.RWMutex + resolverWrapper *ccResolverWrapper // Initialized in Dial; cleared in Close. + sc *ServiceConfig // Latest service config received from the resolver. + conns map[*addrConn]struct{} // Set to nil on close. + mkp keepalive.ClientParameters // May be updated upon receipt of a GoAway. + idlenessState ccIdlenessState // Tracks idleness state of the channel. + exitIdleCond *sync.Cond // Signalled when channel exits idle. lceMu sync.Mutex // protects lastConnectionError lastConnectionError error } +// ccIdlenessState tracks the idleness state of the channel. +// +// Channels start off in `active` and move to `idle` after a period of +// inactivity. When moving back to `active` upon an incoming RPC, they +// transition through `exiting_idle`. This state is useful for synchronization +// with Close(). +// +// This state tracking is mostly for self-protection. The idlenessManager is +// expected to keep track of the state as well, and is expected not to call into +// the ClientConn unnecessarily. +type ccIdlenessState int8 + +const ( + ccIdlenessStateActive ccIdlenessState = iota + ccIdlenessStateIdle + ccIdlenessStateExitingIdle +) + // WaitForStateChange waits until the connectivity.State of ClientConn changes from sourceState or // ctx expires. A true value is returned in former case and false in latter. // -// Experimental +// # Experimental // // Notice: This API is EXPERIMENTAL and may be changed or removed in a // later release. @@ -536,14 +690,29 @@ func (cc *ClientConn) WaitForStateChange(ctx context.Context, sourceState connec // GetState returns the connectivity.State of ClientConn. // -// Experimental +// # Experimental // -// Notice: This API is EXPERIMENTAL and may be changed or removed in a -// later release. +// Notice: This API is EXPERIMENTAL and may be changed or removed in a later +// release. func (cc *ClientConn) GetState() connectivity.State { return cc.csMgr.getState() } +// Connect causes all subchannels in the ClientConn to attempt to connect if +// the channel is idle. Does not wait for the connection attempts to begin +// before returning. +// +// # Experimental +// +// Notice: This API is EXPERIMENTAL and may be changed or removed in a later +// release. +func (cc *ClientConn) Connect() { + cc.exitIdleMode() + // If the ClientConn was not in idle mode, we need to call ExitIdle on the + // LB policy so that connections can be created. + cc.balancerWrapper.exitIdleMode() +} + func (cc *ClientConn) scWatcher() { for { select { @@ -621,9 +790,7 @@ func (cc *ClientConn) updateResolverState(s resolver.State, err error) error { // with the new addresses. cc.maybeApplyDefaultServiceConfig(nil) - if cc.balancerWrapper != nil { - cc.balancerWrapper.resolverError(err) - } + cc.balancerWrapper.resolverError(err) // No addresses are valid with err set; return early. cc.mu.Unlock() @@ -631,7 +798,10 @@ func (cc *ClientConn) updateResolverState(s resolver.State, err error) error { } var ret error - if cc.dopts.disableServiceConfig || s.ServiceConfig == nil { + if cc.dopts.disableServiceConfig { + channelz.Infof(logger, cc.channelzID, "ignoring service config from resolver (%v) and applying the default because service config is disabled", s.ServiceConfig) + cc.maybeApplyDefaultServiceConfig(s.Addresses) + } else if s.ServiceConfig == nil { cc.maybeApplyDefaultServiceConfig(s.Addresses) // TODO: do we need to apply a failing LB policy if there is no // default, per the error handling design? @@ -648,16 +818,10 @@ func (cc *ClientConn) updateResolverState(s resolver.State, err error) error { cc.applyServiceConfigAndBalancer(sc, configSelector, s.Addresses) } else { ret = balancer.ErrBadResolverState - if cc.balancerWrapper == nil { - var err error - if s.ServiceConfig.Err != nil { - err = status.Errorf(codes.Unavailable, "error parsing service config: %v", s.ServiceConfig.Err) - } else { - err = status.Errorf(codes.Unavailable, "illegal service config type: %T", s.ServiceConfig.Config) - } - cc.safeConfigSelector.UpdateConfigSelector(&defaultConfigSelector{cc.sc}) - cc.blockingpicker.updatePicker(base.NewErrPicker(err)) - cc.csMgr.updateState(connectivity.TransientFailure) + if cc.sc == nil { + // Apply the failing LB only if we haven't received valid service config + // from the name resolver in the past. + cc.applyFailingLB(s.ServiceConfig) cc.mu.Unlock() return ret } @@ -665,24 +829,12 @@ func (cc *ClientConn) updateResolverState(s resolver.State, err error) error { } var balCfg serviceconfig.LoadBalancingConfig - if cc.dopts.balancerBuilder == nil && cc.sc != nil && cc.sc.lbConfig != nil { + if cc.sc != nil && cc.sc.lbConfig != nil { balCfg = cc.sc.lbConfig.cfg } - - cbn := cc.curBalancerName bw := cc.balancerWrapper cc.mu.Unlock() - if cbn != grpclbName { - // Filter any grpclb addresses since we don't have the grpclb balancer. - for i := 0; i < len(s.Addresses); { - if s.Addresses[i].Type == resolver.GRPCLB { - copy(s.Addresses[i:], s.Addresses[i+1:]) - s.Addresses = s.Addresses[:len(s.Addresses)-1] - continue - } - i++ - } - } + uccsErr := bw.updateClientConnState(&balancer.ClientConnState{ResolverState: s, BalancerConfig: balCfg}) if ret == nil { ret = uccsErr // prefer ErrBadResolver state since any other error is @@ -691,51 +843,28 @@ func (cc *ClientConn) updateResolverState(s resolver.State, err error) error { return ret } -// switchBalancer starts the switching from current balancer to the balancer -// with the given name. -// -// It will NOT send the current address list to the new balancer. If needed, -// caller of this function should send address list to the new balancer after -// this function returns. +// applyFailingLB is akin to configuring an LB policy on the channel which +// always fails RPCs. Here, an actual LB policy is not configured, but an always +// erroring picker is configured, which returns errors with information about +// what was invalid in the received service config. A config selector with no +// service config is configured, and the connectivity state of the channel is +// set to TransientFailure. // // Caller must hold cc.mu. -func (cc *ClientConn) switchBalancer(name string) { - if strings.EqualFold(cc.curBalancerName, name) { - return - } - - channelz.Infof(logger, cc.channelzID, "ClientConn switching balancer to %q", name) - if cc.dopts.balancerBuilder != nil { - channelz.Info(logger, cc.channelzID, "ignoring balancer switching: Balancer DialOption used instead") - return - } - if cc.balancerWrapper != nil { - cc.balancerWrapper.close() - } - - builder := balancer.Get(name) - if builder == nil { - channelz.Warningf(logger, cc.channelzID, "Channel switches to new LB policy %q due to fallback from invalid balancer name", PickFirstBalancerName) - channelz.Infof(logger, cc.channelzID, "failed to get balancer builder for: %v, using pick_first instead", name) - builder = newPickfirstBuilder() +func (cc *ClientConn) applyFailingLB(sc *serviceconfig.ParseResult) { + var err error + if sc.Err != nil { + err = status.Errorf(codes.Unavailable, "error parsing service config: %v", sc.Err) } else { - channelz.Infof(logger, cc.channelzID, "Channel switches to new LB policy %q", name) + err = status.Errorf(codes.Unavailable, "illegal service config type: %T", sc.Config) } - - cc.curBalancerName = builder.Name() - cc.balancerWrapper = newCCBalancerWrapper(cc, builder, cc.balancerBuildOpts) + cc.safeConfigSelector.UpdateConfigSelector(&defaultConfigSelector{nil}) + cc.blockingpicker.updatePicker(base.NewErrPicker(err)) + cc.csMgr.updateState(connectivity.TransientFailure) } func (cc *ClientConn) handleSubConnStateChange(sc balancer.SubConn, s connectivity.State, err error) { - cc.mu.Lock() - if cc.conns == nil { - cc.mu.Unlock() - return - } - // TODO(bar switching) send updates to all balancer wrappers when balancer - // gracefully switching is supported. - cc.balancerWrapper.handleSubConnStateChange(sc, s, err) - cc.mu.Unlock() + cc.balancerWrapper.updateSubConnState(sc, s, err) } // newAddrConn creates an addrConn for addrs and adds it to cc.conns. @@ -750,27 +879,31 @@ func (cc *ClientConn) newAddrConn(addrs []resolver.Address, opts balancer.NewSub dopts: cc.dopts, czData: new(channelzData), resetBackoff: make(chan struct{}), + stateChan: make(chan struct{}), } ac.ctx, ac.cancel = context.WithCancel(cc.ctx) // Track ac in cc. This needs to be done before any getTransport(...) is called. cc.mu.Lock() + defer cc.mu.Unlock() if cc.conns == nil { - cc.mu.Unlock() return nil, ErrClientConnClosing } - if channelz.IsOn() { - ac.channelzID = channelz.RegisterSubChannel(ac, cc.channelzID, "") - channelz.AddTraceEvent(logger, ac.channelzID, 0, &channelz.TraceEventDesc{ - Desc: "Subchannel Created", - Severity: channelz.CtInfo, - Parent: &channelz.TraceEventDesc{ - Desc: fmt.Sprintf("Subchannel(id:%d) created", ac.channelzID), - Severity: channelz.CtInfo, - }, - }) + + var err error + ac.channelzID, err = channelz.RegisterSubChannel(ac, cc.channelzID, "") + if err != nil { + return nil, err } + channelz.AddTraceEvent(logger, ac.channelzID, 0, &channelz.TraceEventDesc{ + Desc: "Subchannel created", + Severity: channelz.CtInfo, + Parent: &channelz.TraceEventDesc{ + Desc: fmt.Sprintf("Subchannel(id:%d) created", ac.channelzID.Int()), + Severity: channelz.CtInfo, + }, + }) + cc.conns[ac] = struct{}{} - cc.mu.Unlock() return ac, nil } @@ -800,7 +933,7 @@ func (cc *ClientConn) channelzMetric() *channelz.ChannelInternalMetric { // Target returns the target string of the ClientConn. // -// Experimental +// # Experimental // // Notice: This API is EXPERIMENTAL and may be changed or removed in a // later release. @@ -827,67 +960,113 @@ func (cc *ClientConn) incrCallsFailed() { func (ac *addrConn) connect() error { ac.mu.Lock() if ac.state == connectivity.Shutdown { + if logger.V(2) { + logger.Infof("connect called on shutdown addrConn; ignoring.") + } ac.mu.Unlock() return errConnClosing } if ac.state != connectivity.Idle { + if logger.V(2) { + logger.Infof("connect called on addrConn in non-idle state (%v); ignoring.", ac.state) + } ac.mu.Unlock() return nil } - // Update connectivity state within the lock to prevent subsequent or - // concurrent calls from resetting the transport more than once. - ac.updateConnectivityState(connectivity.Connecting, nil) ac.mu.Unlock() - // Start a goroutine connecting to the server asynchronously. - go ac.resetTransport() + ac.resetTransport() return nil } -// tryUpdateAddrs tries to update ac.addrs with the new addresses list. -// -// If ac is Connecting, it returns false. The caller should tear down the ac and -// create a new one. Note that the backoff will be reset when this happens. -// -// If ac is TransientFailure, it updates ac.addrs and returns true. The updated -// addresses will be picked up by retry in the next iteration after backoff. -// -// If ac is Shutdown or Idle, it updates ac.addrs and returns true. -// -// If ac is Ready, it checks whether current connected address of ac is in the -// new addrs list. -// - If true, it updates ac.addrs and returns true. The ac will keep using -// the existing connection. -// - If false, it does nothing and returns false. -func (ac *addrConn) tryUpdateAddrs(addrs []resolver.Address) bool { +func equalAddresses(a, b []resolver.Address) bool { + if len(a) != len(b) { + return false + } + for i, v := range a { + if !v.Equal(b[i]) { + return false + } + } + return true +} + +// updateAddrs updates ac.addrs with the new addresses list and handles active +// connections or connection attempts. +func (ac *addrConn) updateAddrs(addrs []resolver.Address) { ac.mu.Lock() - defer ac.mu.Unlock() - channelz.Infof(logger, ac.channelzID, "addrConn: tryUpdateAddrs curAddr: %v, addrs: %v", ac.curAddr, addrs) + channelz.Infof(logger, ac.channelzID, "addrConn: updateAddrs curAddr: %v, addrs: %v", ac.curAddr, addrs) + + if equalAddresses(ac.addrs, addrs) { + ac.mu.Unlock() + return + } + + ac.addrs = addrs + if ac.state == connectivity.Shutdown || ac.state == connectivity.TransientFailure || ac.state == connectivity.Idle { - ac.addrs = addrs - return true + // We were not connecting, so do nothing but update the addresses. + ac.mu.Unlock() + return } - if ac.state == connectivity.Connecting { - return false + if ac.state == connectivity.Ready { + // Try to find the connected address. + for _, a := range addrs { + a.ServerName = ac.cc.getServerName(a) + if a.Equal(ac.curAddr) { + // We are connected to a valid address, so do nothing but + // update the addresses. + ac.mu.Unlock() + return + } + } } - // ac.state is Ready, try to find the connected address. - var curAddrFound bool - for _, a := range addrs { - if reflect.DeepEqual(ac.curAddr, a) { - curAddrFound = true - break - } + // We are either connected to the wrong address or currently connecting. + // Stop the current iteration and restart. + + ac.cancel() + ac.ctx, ac.cancel = context.WithCancel(ac.cc.ctx) + + // We have to defer here because GracefulClose => Close => onClose, which + // requires locking ac.mu. + if ac.transport != nil { + defer ac.transport.GracefulClose() + ac.transport = nil } - channelz.Infof(logger, ac.channelzID, "addrConn: tryUpdateAddrs curAddrFound: %v", curAddrFound) - if curAddrFound { - ac.addrs = addrs + + if len(addrs) == 0 { + ac.updateConnectivityState(connectivity.Idle, nil) } - return curAddrFound + ac.mu.Unlock() + + // Since we were connecting/connected, we should start a new connection + // attempt. + go ac.resetTransport() +} + +// getServerName determines the serverName to be used in the connection +// handshake. The default value for the serverName is the authority on the +// ClientConn, which either comes from the user's dial target or through an +// authority override specified using the WithAuthority dial option. Name +// resolvers can specify a per-address override for the serverName through the +// resolver.Address.ServerName field which is used only if the WithAuthority +// dial option was not used. The rationale is that per-address authority +// overrides specified by the name resolver can represent a security risk, while +// an override specified by the user is more dependable since they probably know +// what they are doing. +func (cc *ClientConn) getServerName(addr resolver.Address) string { + if cc.dopts.authority != "" { + return cc.dopts.authority + } + if addr.ServerName != "" { + return addr.ServerName + } + return cc.authority } func getMethodConfig(sc *ServiceConfig, method string) MethodConfig { @@ -928,15 +1107,11 @@ func (cc *ClientConn) healthCheckConfig() *healthCheckConfig { return cc.sc.healthCheckConfig } -func (cc *ClientConn) getTransport(ctx context.Context, failfast bool, method string) (transport.ClientTransport, func(balancer.DoneInfo), error) { - t, done, err := cc.blockingpicker.pick(ctx, failfast, balancer.PickInfo{ +func (cc *ClientConn) getTransport(ctx context.Context, failfast bool, method string) (transport.ClientTransport, balancer.PickResult, error) { + return cc.blockingpicker.pick(ctx, failfast, balancer.PickInfo{ Ctx: ctx, FullMethodName: method, }) - if err != nil { - return nil, nil, toRPCErr(err) - } - return t, done, nil } func (cc *ClientConn) applyServiceConfigAndBalancer(sc *ServiceConfig, configSelector iresolver.ConfigSelector, addrs []resolver.Address) { @@ -961,35 +1136,26 @@ func (cc *ClientConn) applyServiceConfigAndBalancer(sc *ServiceConfig, configSel cc.retryThrottler.Store((*retryThrottler)(nil)) } - if cc.dopts.balancerBuilder == nil { - // Only look at balancer types and switch balancer if balancer dial - // option is not set. - var newBalancerName string - if cc.sc != nil && cc.sc.lbConfig != nil { - newBalancerName = cc.sc.lbConfig.name - } else { - var isGRPCLB bool - for _, a := range addrs { - if a.Type == resolver.GRPCLB { - isGRPCLB = true - break - } - } - if isGRPCLB { - newBalancerName = grpclbName - } else if cc.sc != nil && cc.sc.LB != nil { - newBalancerName = *cc.sc.LB - } else { - newBalancerName = PickFirstBalancerName + var newBalancerName string + if cc.sc != nil && cc.sc.lbConfig != nil { + newBalancerName = cc.sc.lbConfig.name + } else { + var isGRPCLB bool + for _, a := range addrs { + if a.Type == resolver.GRPCLB { + isGRPCLB = true + break } } - cc.switchBalancer(newBalancerName) - } else if cc.balancerWrapper == nil { - // Balancer dial option was set, and this is the first time handling - // resolved addresses. Build a balancer with dopts.balancerBuilder. - cc.curBalancerName = cc.dopts.balancerBuilder.Name() - cc.balancerWrapper = newCCBalancerWrapper(cc, cc.dopts.balancerBuilder, cc.balancerBuildOpts) + if isGRPCLB { + newBalancerName = grpclbName + } else if cc.sc != nil && cc.sc.LB != nil { + newBalancerName = *cc.sc.LB + } else { + newBalancerName = PickFirstBalancerName + } } + cc.balancerWrapper.switchTo(newBalancerName) } func (cc *ClientConn) resolveNow(o resolver.ResolveNowOptions) { @@ -1011,7 +1177,7 @@ func (cc *ClientConn) resolveNow(o resolver.ResolveNowOptions) { // However, if a previously unavailable network becomes available, this may be // used to trigger an immediate reconnect. // -// Experimental +// # Experimental // // Notice: This API is EXPERIMENTAL and may be changed or removed in a // later release. @@ -1033,44 +1199,45 @@ func (cc *ClientConn) Close() error { cc.mu.Unlock() return ErrClientConnClosing } + + for cc.idlenessState == ccIdlenessStateExitingIdle { + cc.exitIdleCond.Wait() + } + conns := cc.conns cc.conns = nil cc.csMgr.updateState(connectivity.Shutdown) + pWrapper := cc.blockingpicker rWrapper := cc.resolverWrapper - cc.resolverWrapper = nil bWrapper := cc.balancerWrapper - cc.balancerWrapper = nil + idlenessMgr := cc.idlenessMgr cc.mu.Unlock() - cc.blockingpicker.close() - - if rWrapper != nil { - rWrapper.close() + // The order of closing matters here since the balancer wrapper assumes the + // picker is closed before it is closed. + if pWrapper != nil { + pWrapper.close() } if bWrapper != nil { bWrapper.close() } + if rWrapper != nil { + rWrapper.close() + } + if idlenessMgr != nil { + idlenessMgr.close() + } for ac := range conns { ac.tearDown(ErrClientConnClosing) } - if channelz.IsOn() { - ted := &channelz.TraceEventDesc{ - Desc: "Channel Deleted", - Severity: channelz.CtInfo, - } - if cc.dopts.channelzParentID != 0 { - ted.Parent = &channelz.TraceEventDesc{ - Desc: fmt.Sprintf("Nested channel(id:%d) deleted", cc.channelzID), - Severity: channelz.CtInfo, - } - } - channelz.AddTraceEvent(logger, cc.channelzID, 0, ted) - // TraceEvent needs to be called before RemoveEntry, as TraceEvent may add trace reference to - // the entity being deleted, and thus prevent it from being deleted right away. - channelz.RemoveEntry(cc.channelzID) - } + cc.addTraceEvent("deleted") + // TraceEvent needs to be called before RemoveEntry, as TraceEvent may add + // trace reference to the entity being deleted, and thus prevent it from being + // deleted right away. + channelz.RemoveEntry(cc.channelzID) + return nil } @@ -1095,12 +1262,13 @@ type addrConn struct { addrs []resolver.Address // All addresses that the resolver resolved to. // Use updateConnectivityState for updating addrConn's connectivity state. - state connectivity.State + state connectivity.State + stateChan chan struct{} // closed and recreated on every state change. backoffIdx int // Needs to be stateful for resetConnectBackoff. resetBackoff chan struct{} - channelzID int64 // channelz unique identification number. + channelzID *channelz.Identifier czData *channelzData } @@ -1109,8 +1277,15 @@ func (ac *addrConn) updateConnectivityState(s connectivity.State, lastErr error) if ac.state == s { return } + // When changing states, reset the state change channel. + close(ac.stateChan) + ac.stateChan = make(chan struct{}) ac.state = s - channelz.Infof(logger, ac.channelzID, "Subchannel Connectivity change to %v", s) + if lastErr == nil { + channelz.Infof(logger, ac.channelzID, "Subchannel Connectivity change to %v", s) + } else { + channelz.Infof(logger, ac.channelzID, "Subchannel Connectivity change to %v, last error: %s", s, lastErr) + } ac.cc.handleSubConnStateChange(ac.acbw, s, lastErr) } @@ -1129,113 +1304,86 @@ func (ac *addrConn) adjustParams(r transport.GoAwayReason) { } func (ac *addrConn) resetTransport() { - for i := 0; ; i++ { - if i > 0 { - ac.cc.resolveNow(resolver.ResolveNowOptions{}) - } + ac.mu.Lock() + acCtx := ac.ctx + if acCtx.Err() != nil { + ac.mu.Unlock() + return + } - ac.mu.Lock() - if ac.state == connectivity.Shutdown { - ac.mu.Unlock() - return - } + addrs := ac.addrs + backoffFor := ac.dopts.bs.Backoff(ac.backoffIdx) + // This will be the duration that dial gets to finish. + dialDuration := minConnectTimeout + if ac.dopts.minConnectTimeout != nil { + dialDuration = ac.dopts.minConnectTimeout() + } - addrs := ac.addrs - backoffFor := ac.dopts.bs.Backoff(ac.backoffIdx) - // This will be the duration that dial gets to finish. - dialDuration := minConnectTimeout - if ac.dopts.minConnectTimeout != nil { - dialDuration = ac.dopts.minConnectTimeout() - } + if dialDuration < backoffFor { + // Give dial more time as we keep failing to connect. + dialDuration = backoffFor + } + // We can potentially spend all the time trying the first address, and + // if the server accepts the connection and then hangs, the following + // addresses will never be tried. + // + // The spec doesn't mention what should be done for multiple addresses. + // https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md#proposed-backoff-algorithm + connectDeadline := time.Now().Add(dialDuration) - if dialDuration < backoffFor { - // Give dial more time as we keep failing to connect. - dialDuration = backoffFor + ac.updateConnectivityState(connectivity.Connecting, nil) + ac.mu.Unlock() + + if err := ac.tryAllAddrs(acCtx, addrs, connectDeadline); err != nil { + ac.cc.resolveNow(resolver.ResolveNowOptions{}) + // After exhausting all addresses, the addrConn enters + // TRANSIENT_FAILURE. + if acCtx.Err() != nil { + return } - // We can potentially spend all the time trying the first address, and - // if the server accepts the connection and then hangs, the following - // addresses will never be tried. - // - // The spec doesn't mention what should be done for multiple addresses. - // https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md#proposed-backoff-algorithm - connectDeadline := time.Now().Add(dialDuration) + ac.mu.Lock() + ac.updateConnectivityState(connectivity.TransientFailure, err) - ac.updateConnectivityState(connectivity.Connecting, nil) - ac.transport = nil + // Backoff. + b := ac.resetBackoff ac.mu.Unlock() - newTr, addr, reconnect, err := ac.tryAllAddrs(addrs, connectDeadline) - if err != nil { - // After exhausting all addresses, the addrConn enters - // TRANSIENT_FAILURE. + timer := time.NewTimer(backoffFor) + select { + case <-timer.C: ac.mu.Lock() - if ac.state == connectivity.Shutdown { - ac.mu.Unlock() - return - } - ac.updateConnectivityState(connectivity.TransientFailure, err) - - // Backoff. - b := ac.resetBackoff + ac.backoffIdx++ ac.mu.Unlock() - - timer := time.NewTimer(backoffFor) - select { - case <-timer.C: - ac.mu.Lock() - ac.backoffIdx++ - ac.mu.Unlock() - case <-b: - timer.Stop() - case <-ac.ctx.Done(): - timer.Stop() - return - } - continue + case <-b: + timer.Stop() + case <-acCtx.Done(): + timer.Stop() + return } ac.mu.Lock() - if ac.state == connectivity.Shutdown { - ac.mu.Unlock() - newTr.Close() - return + if acCtx.Err() == nil { + ac.updateConnectivityState(connectivity.Idle, err) } - ac.curAddr = addr - ac.transport = newTr - ac.backoffIdx = 0 - - hctx, hcancel := context.WithCancel(ac.ctx) - ac.startHealthCheck(hctx) ac.mu.Unlock() - - // Block until the created transport is down. And when this happens, - // we restart from the top of the addr list. - <-reconnect.Done() - hcancel() - // restart connecting - the top of the loop will set state to - // CONNECTING. This is against the current connectivity semantics doc, - // however it allows for graceful behavior for RPCs not yet dispatched - // - unfortunate timing would otherwise lead to the RPC failing even - // though the TRANSIENT_FAILURE state (called for by the doc) would be - // instantaneous. - // - // Ideally we should transition to Idle here and block until there is - // RPC activity that leads to the balancer requesting a reconnect of - // the associated SubConn. + return } + // Success; reset backoff. + ac.mu.Lock() + ac.backoffIdx = 0 + ac.mu.Unlock() } -// tryAllAddrs tries to creates a connection to the addresses, and stop when at the -// first successful one. It returns the transport, the address and a Event in -// the successful case. The Event fires when the returned transport disconnects. -func (ac *addrConn) tryAllAddrs(addrs []resolver.Address, connectDeadline time.Time) (transport.ClientTransport, resolver.Address, *grpcsync.Event, error) { +// tryAllAddrs tries to creates a connection to the addresses, and stop when at +// the first successful one. It returns an error if no address was successfully +// connected, or updates ac appropriately with the new transport. +func (ac *addrConn) tryAllAddrs(ctx context.Context, addrs []resolver.Address, connectDeadline time.Time) error { var firstConnErr error for _, addr := range addrs { - ac.mu.Lock() - if ac.state == connectivity.Shutdown { - ac.mu.Unlock() - return nil, resolver.Address{}, nil, errConnClosing + if ctx.Err() != nil { + return errConnClosing } + ac.mu.Lock() ac.cc.mu.RLock() ac.dopts.copts.KeepaliveParams = ac.cc.mkp @@ -1249,9 +1397,9 @@ func (ac *addrConn) tryAllAddrs(addrs []resolver.Address, connectDeadline time.T channelz.Infof(logger, ac.channelzID, "Subchannel picks a new address %q to connect", addr.Addr) - newTr, reconnect, err := ac.createTransport(addr, copts, connectDeadline) + err := ac.createTransport(ctx, addr, copts, connectDeadline) if err == nil { - return newTr, addr, reconnect, nil + return nil } if firstConnErr == nil { firstConnErr = err @@ -1260,86 +1408,90 @@ func (ac *addrConn) tryAllAddrs(addrs []resolver.Address, connectDeadline time.T } // Couldn't connect to any address. - return nil, resolver.Address{}, nil, firstConnErr + return firstConnErr } -// createTransport creates a connection to addr. It returns the transport and a -// Event in the successful case. The Event fires when the returned transport -// disconnects. -func (ac *addrConn) createTransport(addr resolver.Address, copts transport.ConnectOptions, connectDeadline time.Time) (transport.ClientTransport, *grpcsync.Event, error) { - prefaceReceived := make(chan struct{}) - onCloseCalled := make(chan struct{}) - reconnect := grpcsync.NewEvent() - - // addr.ServerName takes precedent over ClientConn authority, if present. - if addr.ServerName == "" { - addr.ServerName = ac.cc.authority - } +// createTransport creates a connection to addr. It returns an error if the +// address was not successfully connected, or updates ac appropriately with the +// new transport. +func (ac *addrConn) createTransport(ctx context.Context, addr resolver.Address, copts transport.ConnectOptions, connectDeadline time.Time) error { + addr.ServerName = ac.cc.getServerName(addr) + hctx, hcancel := context.WithCancel(ctx) - once := sync.Once{} - onGoAway := func(r transport.GoAwayReason) { + onClose := func(r transport.GoAwayReason) { ac.mu.Lock() + defer ac.mu.Unlock() + // adjust params based on GoAwayReason ac.adjustParams(r) - once.Do(func() { - if ac.state == connectivity.Ready { - // Prevent this SubConn from being used for new RPCs by setting its - // state to Connecting. - // - // TODO: this should be Idle when grpc-go properly supports it. - ac.updateConnectivityState(connectivity.Connecting, nil) - } - }) - ac.mu.Unlock() - reconnect.Fire() - } - - onClose := func() { - ac.mu.Lock() - once.Do(func() { - if ac.state == connectivity.Ready { - // Prevent this SubConn from being used for new RPCs by setting its - // state to Connecting. - // - // TODO: this should be Idle when grpc-go properly supports it. - ac.updateConnectivityState(connectivity.Connecting, nil) - } - }) - ac.mu.Unlock() - close(onCloseCalled) - reconnect.Fire() - } - - onPrefaceReceipt := func() { - close(prefaceReceived) + if ctx.Err() != nil { + // Already shut down or connection attempt canceled. tearDown() or + // updateAddrs() already cleared the transport and canceled hctx + // via ac.ctx, and we expected this connection to be closed, so do + // nothing here. + return + } + hcancel() + if ac.transport == nil { + // We're still connecting to this address, which could error. Do + // not update the connectivity state or resolve; these will happen + // at the end of the tryAllAddrs connection loop in the event of an + // error. + return + } + ac.transport = nil + // Refresh the name resolver on any connection loss. + ac.cc.resolveNow(resolver.ResolveNowOptions{}) + // Always go idle and wait for the LB policy to initiate a new + // connection attempt. + ac.updateConnectivityState(connectivity.Idle, nil) } - connectCtx, cancel := context.WithDeadline(ac.ctx, connectDeadline) + connectCtx, cancel := context.WithDeadline(ctx, connectDeadline) defer cancel() - if channelz.IsOn() { - copts.ChannelzParentID = ac.channelzID - } + copts.ChannelzParentID = ac.channelzID - newTr, err := transport.NewClientTransport(connectCtx, ac.cc.ctx, addr, copts, onPrefaceReceipt, onGoAway, onClose) + newTr, err := transport.NewClientTransport(connectCtx, ac.cc.ctx, addr, copts, onClose) if err != nil { + if logger.V(2) { + logger.Infof("Creating new client transport to %q: %v", addr, err) + } // newTr is either nil, or closed. - channelz.Warningf(logger, ac.channelzID, "grpc: addrConn.createTransport failed to connect to %v. Err: %v. Reconnecting...", addr, err) - return nil, nil, err + hcancel() + channelz.Warningf(logger, ac.channelzID, "grpc: addrConn.createTransport failed to connect to %s. Err: %v", addr, err) + return err } - select { - case <-time.After(time.Until(connectDeadline)): - // We didn't get the preface in time. - newTr.Close() - channelz.Warningf(logger, ac.channelzID, "grpc: addrConn.createTransport failed to connect to %v: didn't receive server preface in time. Reconnecting...", addr) - return nil, nil, errors.New("timed out waiting for server handshake") - case <-prefaceReceived: - // We got the preface - huzzah! things are good. - case <-onCloseCalled: - // The transport has already closed - noop. - return nil, nil, errors.New("connection closed") - // TODO(deklerk) this should bail on ac.ctx.Done(). Add a test and fix. + ac.mu.Lock() + defer ac.mu.Unlock() + if ctx.Err() != nil { + // This can happen if the subConn was removed while in `Connecting` + // state. tearDown() would have set the state to `Shutdown`, but + // would not have closed the transport since ac.transport would not + // have been set at that point. + // + // We run this in a goroutine because newTr.Close() calls onClose() + // inline, which requires locking ac.mu. + // + // The error we pass to Close() is immaterial since there are no open + // streams at this point, so no trailers with error details will be sent + // out. We just need to pass a non-nil error. + // + // This can also happen when updateAddrs is called during a connection + // attempt. + go newTr.Close(transport.ErrConnClosing) + return nil + } + if hctx.Err() != nil { + // onClose was already called for this connection, but the connection + // was successfully established first. Consider it a success and set + // the new state to Idle. + ac.updateConnectivityState(connectivity.Idle, nil) + return nil } - return newTr, reconnect, nil + ac.curAddr = addr + ac.transport = newTr + ac.startHealthCheck(hctx) // Will set state to READY if appropriate. + return nil } // startHealthCheck starts the health checking stream (RPC) to watch the health @@ -1409,7 +1561,7 @@ func (ac *addrConn) startHealthCheck(ctx context.Context) { if status.Code(err) == codes.Unimplemented { channelz.Error(logger, ac.channelzID, "Subchannel health check is unimplemented at server side, thus health check is disabled") } else { - channelz.Errorf(logger, ac.channelzID, "HealthCheckFunc exits with unexpected error %v", err) + channelz.Errorf(logger, ac.channelzID, "Health checking failed: %v", err) } } }() @@ -1423,33 +1575,43 @@ func (ac *addrConn) resetConnectBackoff() { ac.mu.Unlock() } -// getReadyTransport returns the transport if ac's state is READY. -// Otherwise it returns nil, false. -// If ac's state is IDLE, it will trigger ac to connect. -func (ac *addrConn) getReadyTransport() (transport.ClientTransport, bool) { +// getReadyTransport returns the transport if ac's state is READY or nil if not. +func (ac *addrConn) getReadyTransport() transport.ClientTransport { ac.mu.Lock() - if ac.state == connectivity.Ready && ac.transport != nil { - t := ac.transport - ac.mu.Unlock() - return t, true - } - var idle bool - if ac.state == connectivity.Idle { - idle = true + defer ac.mu.Unlock() + if ac.state == connectivity.Ready { + return ac.transport } - ac.mu.Unlock() - // Trigger idle ac to connect. - if idle { - ac.connect() + return nil +} + +// getTransport waits until the addrconn is ready and returns the transport. +// If the context expires first, returns an appropriate status. If the +// addrConn is stopped first, returns an Unavailable status error. +func (ac *addrConn) getTransport(ctx context.Context) (transport.ClientTransport, error) { + for ctx.Err() == nil { + ac.mu.Lock() + t, state, sc := ac.transport, ac.state, ac.stateChan + ac.mu.Unlock() + if state == connectivity.Ready { + return t, nil + } + if state == connectivity.Shutdown { + return nil, status.Errorf(codes.Unavailable, "SubConn shutting down") + } + + select { + case <-ctx.Done(): + case <-sc: + } } - return nil, false + return nil, status.FromContextError(ctx.Err()).Err() } // tearDown starts to tear down the addrConn. -// TODO(zhaoq): Make this synchronous to avoid unbounded memory consumption in -// some edge cases (e.g., the caller opens and closes many addrConn's in a -// tight loop. -// tearDown doesn't remove ac from ac.cc.conns. +// +// Note that tearDown doesn't remove ac from ac.cc.conns, so the addrConn struct +// will leak. In most cases, call cc.removeAddrConn() instead. func (ac *addrConn) tearDown(err error) { ac.mu.Lock() if ac.state == connectivity.Shutdown { @@ -1473,19 +1635,18 @@ func (ac *addrConn) tearDown(err error) { curTr.GracefulClose() ac.mu.Lock() } - if channelz.IsOn() { - channelz.AddTraceEvent(logger, ac.channelzID, 0, &channelz.TraceEventDesc{ - Desc: "Subchannel Deleted", + channelz.AddTraceEvent(logger, ac.channelzID, 0, &channelz.TraceEventDesc{ + Desc: "Subchannel deleted", + Severity: channelz.CtInfo, + Parent: &channelz.TraceEventDesc{ + Desc: fmt.Sprintf("Subchannel(id:%d) deleted", ac.channelzID.Int()), Severity: channelz.CtInfo, - Parent: &channelz.TraceEventDesc{ - Desc: fmt.Sprintf("Subchanel(id:%d) deleted", ac.channelzID), - Severity: channelz.CtInfo, - }, - }) - // TraceEvent needs to be called before RemoveEntry, as TraceEvent may add trace reference to - // the entity being deleted, and thus prevent it from being deleted right away. - channelz.RemoveEntry(ac.channelzID) - } + }, + }) + // TraceEvent needs to be called before RemoveEntry, as TraceEvent may add + // trace reference to the entity being deleted, and thus prevent it from + // being deleted right away. + channelz.RemoveEntry(ac.channelzID) ac.mu.Unlock() } @@ -1574,6 +1735,9 @@ func (c *channelzChannel) ChannelzMetric() *channelz.ChannelInternalMetric { // referenced by users. var ErrClientConnTimeout = errors.New("grpc: timed out when dialing") +// getResolver finds the scheme in the cc's resolvers or the global registry. +// scheme should always be lowercase (typically by virtue of url.Parse() +// performing proper RFC3986 behavior). func (cc *ClientConn) getResolver(scheme string) resolver.Builder { for _, rb := range cc.dopts.resolvers { if scheme == rb.Scheme() { @@ -1594,3 +1758,151 @@ func (cc *ClientConn) connectionError() error { defer cc.lceMu.Unlock() return cc.lastConnectionError } + +// parseTargetAndFindResolver parses the user's dial target and stores the +// parsed target in `cc.parsedTarget`. +// +// The resolver to use is determined based on the scheme in the parsed target +// and the same is stored in `cc.resolverBuilder`. +// +// Doesn't grab cc.mu as this method is expected to be called only at Dial time. +func (cc *ClientConn) parseTargetAndFindResolver() error { + channelz.Infof(logger, cc.channelzID, "original dial target is: %q", cc.target) + + var rb resolver.Builder + parsedTarget, err := parseTarget(cc.target) + if err != nil { + channelz.Infof(logger, cc.channelzID, "dial target %q parse failed: %v", cc.target, err) + } else { + channelz.Infof(logger, cc.channelzID, "parsed dial target is: %+v", parsedTarget) + rb = cc.getResolver(parsedTarget.URL.Scheme) + if rb != nil { + cc.parsedTarget = parsedTarget + cc.resolverBuilder = rb + return nil + } + } + + // We are here because the user's dial target did not contain a scheme or + // specified an unregistered scheme. We should fallback to the default + // scheme, except when a custom dialer is specified in which case, we should + // always use passthrough scheme. + defScheme := resolver.GetDefaultScheme() + channelz.Infof(logger, cc.channelzID, "fallback to scheme %q", defScheme) + canonicalTarget := defScheme + ":///" + cc.target + + parsedTarget, err = parseTarget(canonicalTarget) + if err != nil { + channelz.Infof(logger, cc.channelzID, "dial target %q parse failed: %v", canonicalTarget, err) + return err + } + channelz.Infof(logger, cc.channelzID, "parsed dial target is: %+v", parsedTarget) + rb = cc.getResolver(parsedTarget.URL.Scheme) + if rb == nil { + return fmt.Errorf("could not get resolver for default scheme: %q", parsedTarget.URL.Scheme) + } + cc.parsedTarget = parsedTarget + cc.resolverBuilder = rb + return nil +} + +// parseTarget uses RFC 3986 semantics to parse the given target into a +// resolver.Target struct containing scheme, authority and url. Query +// params are stripped from the endpoint. +func parseTarget(target string) (resolver.Target, error) { + u, err := url.Parse(target) + if err != nil { + return resolver.Target{}, err + } + + return resolver.Target{ + Scheme: u.Scheme, + Authority: u.Host, + URL: *u, + }, nil +} + +// Determine channel authority. The order of precedence is as follows: +// - user specified authority override using `WithAuthority` dial option +// - creds' notion of server name for the authentication handshake +// - endpoint from dial target of the form "scheme://[authority]/endpoint" +// +// Stores the determined authority in `cc.authority`. +// +// Returns a non-nil error if the authority returned by the transport +// credentials do not match the authority configured through the dial option. +// +// Doesn't grab cc.mu as this method is expected to be called only at Dial time. +func (cc *ClientConn) determineAuthority() error { + dopts := cc.dopts + // Historically, we had two options for users to specify the serverName or + // authority for a channel. One was through the transport credentials + // (either in its constructor, or through the OverrideServerName() method). + // The other option (for cases where WithInsecure() dial option was used) + // was to use the WithAuthority() dial option. + // + // A few things have changed since: + // - `insecure` package with an implementation of the `TransportCredentials` + // interface for the insecure case + // - WithAuthority() dial option support for secure credentials + authorityFromCreds := "" + if creds := dopts.copts.TransportCredentials; creds != nil && creds.Info().ServerName != "" { + authorityFromCreds = creds.Info().ServerName + } + authorityFromDialOption := dopts.authority + if (authorityFromCreds != "" && authorityFromDialOption != "") && authorityFromCreds != authorityFromDialOption { + return fmt.Errorf("ClientConn's authority from transport creds %q and dial option %q don't match", authorityFromCreds, authorityFromDialOption) + } + + endpoint := cc.parsedTarget.Endpoint() + target := cc.target + switch { + case authorityFromDialOption != "": + cc.authority = authorityFromDialOption + case authorityFromCreds != "": + cc.authority = authorityFromCreds + case strings.HasPrefix(target, "unix:") || strings.HasPrefix(target, "unix-abstract:"): + // TODO: remove when the unix resolver implements optional interface to + // return channel authority. + cc.authority = "localhost" + case strings.HasPrefix(endpoint, ":"): + cc.authority = "localhost" + endpoint + default: + // TODO: Define an optional interface on the resolver builder to return + // the channel authority given the user's dial target. For resolvers + // which don't implement this interface, we will use the endpoint from + // "scheme://authority/endpoint" as the default authority. + cc.authority = endpoint + } + channelz.Infof(logger, cc.channelzID, "Channel authority set to %q", cc.authority) + return nil +} + +// initResolverWrapper creates a ccResolverWrapper, which builds the name +// resolver. This method grabs the lock to assign the newly built resolver +// wrapper to the cc.resolverWrapper field. +func (cc *ClientConn) initResolverWrapper(creds credentials.TransportCredentials) error { + rw, err := newCCResolverWrapper(cc, ccResolverWrapperOpts{ + target: cc.parsedTarget, + builder: cc.resolverBuilder, + bOpts: resolver.BuildOptions{ + DisableServiceConfig: cc.dopts.disableServiceConfig, + DialCreds: creds, + CredsBundle: cc.dopts.copts.CredsBundle, + Dialer: cc.dopts.copts.Dialer, + }, + channelzID: cc.channelzID, + }) + if err != nil { + return fmt.Errorf("failed to build resolver: %v", err) + } + // Resolver implementations may report state update or error inline when + // built (or right after), and this is handled in cc.updateResolverState. + // Also, an error from the resolver might lead to a re-resolution request + // from the balancer, which is handled in resolveNow() where + // `cc.resolverWrapper` is accessed. Hence, we need to hold the lock here. + cc.mu.Lock() + cc.resolverWrapper = rw + cc.mu.Unlock() + return nil +} diff --git a/vendor/google.golang.org/grpc/codes/code_string.go b/vendor/google.golang.org/grpc/codes/code_string.go index 0b206a57822..934fac2b090 100644 --- a/vendor/google.golang.org/grpc/codes/code_string.go +++ b/vendor/google.golang.org/grpc/codes/code_string.go @@ -18,7 +18,15 @@ package codes -import "strconv" +import ( + "strconv" + + "google.golang.org/grpc/internal" +) + +func init() { + internal.CanonicalString = canonicalString +} func (c Code) String() string { switch c { @@ -60,3 +68,44 @@ func (c Code) String() string { return "Code(" + strconv.FormatInt(int64(c), 10) + ")" } } + +func canonicalString(c Code) string { + switch c { + case OK: + return "OK" + case Canceled: + return "CANCELLED" + case Unknown: + return "UNKNOWN" + case InvalidArgument: + return "INVALID_ARGUMENT" + case DeadlineExceeded: + return "DEADLINE_EXCEEDED" + case NotFound: + return "NOT_FOUND" + case AlreadyExists: + return "ALREADY_EXISTS" + case PermissionDenied: + return "PERMISSION_DENIED" + case ResourceExhausted: + return "RESOURCE_EXHAUSTED" + case FailedPrecondition: + return "FAILED_PRECONDITION" + case Aborted: + return "ABORTED" + case OutOfRange: + return "OUT_OF_RANGE" + case Unimplemented: + return "UNIMPLEMENTED" + case Internal: + return "INTERNAL" + case Unavailable: + return "UNAVAILABLE" + case DataLoss: + return "DATA_LOSS" + case Unauthenticated: + return "UNAUTHENTICATED" + default: + return "CODE(" + strconv.FormatInt(int64(c), 10) + ")" + } +} diff --git a/vendor/google.golang.org/grpc/connectivity/connectivity.go b/vendor/google.golang.org/grpc/connectivity/connectivity.go index 01015626150..4a89926422b 100644 --- a/vendor/google.golang.org/grpc/connectivity/connectivity.go +++ b/vendor/google.golang.org/grpc/connectivity/connectivity.go @@ -18,7 +18,6 @@ // Package connectivity defines connectivity semantics. // For details, see https://github.com/grpc/grpc/blob/master/doc/connectivity-semantics-and-api.md. -// All APIs in this package are experimental. package connectivity import ( @@ -45,7 +44,7 @@ func (s State) String() string { return "SHUTDOWN" default: logger.Errorf("unknown connectivity state: %d", s) - return "Invalid-State" + return "INVALID_STATE" } } @@ -61,3 +60,35 @@ const ( // Shutdown indicates the ClientConn has started shutting down. Shutdown ) + +// ServingMode indicates the current mode of operation of the server. +// +// Only xDS enabled gRPC servers currently report their serving mode. +type ServingMode int + +const ( + // ServingModeStarting indicates that the server is starting up. + ServingModeStarting ServingMode = iota + // ServingModeServing indicates that the server contains all required + // configuration and is serving RPCs. + ServingModeServing + // ServingModeNotServing indicates that the server is not accepting new + // connections. Existing connections will be closed gracefully, allowing + // in-progress RPCs to complete. A server enters this mode when it does not + // contain the required configuration to serve RPCs. + ServingModeNotServing +) + +func (s ServingMode) String() string { + switch s { + case ServingModeStarting: + return "STARTING" + case ServingModeServing: + return "SERVING" + case ServingModeNotServing: + return "NOT_SERVING" + default: + logger.Errorf("unknown serving mode: %d", s) + return "INVALID_MODE" + } +} diff --git a/vendor/google.golang.org/grpc/credentials/alts/alts.go b/vendor/google.golang.org/grpc/credentials/alts/alts.go new file mode 100644 index 00000000000..579adf210c4 --- /dev/null +++ b/vendor/google.golang.org/grpc/credentials/alts/alts.go @@ -0,0 +1,332 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Package alts implements the ALTS credential support by gRPC library, which +// encapsulates all the state needed by a client to authenticate with a server +// using ALTS and make various assertions, e.g., about the client's identity, +// role, or whether it is authorized to make a particular call. +// This package is experimental. +package alts + +import ( + "context" + "errors" + "fmt" + "net" + "sync" + "time" + + "google.golang.org/grpc/credentials" + core "google.golang.org/grpc/credentials/alts/internal" + "google.golang.org/grpc/credentials/alts/internal/handshaker" + "google.golang.org/grpc/credentials/alts/internal/handshaker/service" + altspb "google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/internal/googlecloud" +) + +const ( + // hypervisorHandshakerServiceAddress represents the default ALTS gRPC + // handshaker service address in the hypervisor. + hypervisorHandshakerServiceAddress = "metadata.google.internal.:8080" + // defaultTimeout specifies the server handshake timeout. + defaultTimeout = 30.0 * time.Second + // The following constants specify the minimum and maximum acceptable + // protocol versions. + protocolVersionMaxMajor = 2 + protocolVersionMaxMinor = 1 + protocolVersionMinMajor = 2 + protocolVersionMinMinor = 1 +) + +var ( + vmOnGCP bool + once sync.Once + maxRPCVersion = &altspb.RpcProtocolVersions_Version{ + Major: protocolVersionMaxMajor, + Minor: protocolVersionMaxMinor, + } + minRPCVersion = &altspb.RpcProtocolVersions_Version{ + Major: protocolVersionMinMajor, + Minor: protocolVersionMinMinor, + } + // ErrUntrustedPlatform is returned from ClientHandshake and + // ServerHandshake is running on a platform where the trustworthiness of + // the handshaker service is not guaranteed. + ErrUntrustedPlatform = errors.New("ALTS: untrusted platform. ALTS is only supported on GCP") + logger = grpclog.Component("alts") +) + +// AuthInfo exposes security information from the ALTS handshake to the +// application. This interface is to be implemented by ALTS. Users should not +// need a brand new implementation of this interface. For situations like +// testing, any new implementation should embed this interface. This allows +// ALTS to add new methods to this interface. +type AuthInfo interface { + // ApplicationProtocol returns application protocol negotiated for the + // ALTS connection. + ApplicationProtocol() string + // RecordProtocol returns the record protocol negotiated for the ALTS + // connection. + RecordProtocol() string + // SecurityLevel returns the security level of the created ALTS secure + // channel. + SecurityLevel() altspb.SecurityLevel + // PeerServiceAccount returns the peer service account. + PeerServiceAccount() string + // LocalServiceAccount returns the local service account. + LocalServiceAccount() string + // PeerRPCVersions returns the RPC version supported by the peer. + PeerRPCVersions() *altspb.RpcProtocolVersions +} + +// ClientOptions contains the client-side options of an ALTS channel. These +// options will be passed to the underlying ALTS handshaker. +type ClientOptions struct { + // TargetServiceAccounts contains a list of expected target service + // accounts. + TargetServiceAccounts []string + // HandshakerServiceAddress represents the ALTS handshaker gRPC service + // address to connect to. + HandshakerServiceAddress string +} + +// DefaultClientOptions creates a new ClientOptions object with the default +// values. +func DefaultClientOptions() *ClientOptions { + return &ClientOptions{ + HandshakerServiceAddress: hypervisorHandshakerServiceAddress, + } +} + +// ServerOptions contains the server-side options of an ALTS channel. These +// options will be passed to the underlying ALTS handshaker. +type ServerOptions struct { + // HandshakerServiceAddress represents the ALTS handshaker gRPC service + // address to connect to. + HandshakerServiceAddress string +} + +// DefaultServerOptions creates a new ServerOptions object with the default +// values. +func DefaultServerOptions() *ServerOptions { + return &ServerOptions{ + HandshakerServiceAddress: hypervisorHandshakerServiceAddress, + } +} + +// altsTC is the credentials required for authenticating a connection using ALTS. +// It implements credentials.TransportCredentials interface. +type altsTC struct { + info *credentials.ProtocolInfo + side core.Side + accounts []string + hsAddress string +} + +// NewClientCreds constructs a client-side ALTS TransportCredentials object. +func NewClientCreds(opts *ClientOptions) credentials.TransportCredentials { + return newALTS(core.ClientSide, opts.TargetServiceAccounts, opts.HandshakerServiceAddress) +} + +// NewServerCreds constructs a server-side ALTS TransportCredentials object. +func NewServerCreds(opts *ServerOptions) credentials.TransportCredentials { + return newALTS(core.ServerSide, nil, opts.HandshakerServiceAddress) +} + +func newALTS(side core.Side, accounts []string, hsAddress string) credentials.TransportCredentials { + once.Do(func() { + vmOnGCP = googlecloud.OnGCE() + }) + if hsAddress == "" { + hsAddress = hypervisorHandshakerServiceAddress + } + return &altsTC{ + info: &credentials.ProtocolInfo{ + SecurityProtocol: "alts", + SecurityVersion: "1.0", + }, + side: side, + accounts: accounts, + hsAddress: hsAddress, + } +} + +// ClientHandshake implements the client side handshake protocol. +func (g *altsTC) ClientHandshake(ctx context.Context, addr string, rawConn net.Conn) (_ net.Conn, _ credentials.AuthInfo, err error) { + if !vmOnGCP { + return nil, nil, ErrUntrustedPlatform + } + + // Connecting to ALTS handshaker service. + hsConn, err := service.Dial(g.hsAddress) + if err != nil { + return nil, nil, err + } + // Do not close hsConn since it is shared with other handshakes. + + // Possible context leak: + // The cancel function for the child context we create will only be + // called a non-nil error is returned. + var cancel context.CancelFunc + ctx, cancel = context.WithCancel(ctx) + defer func() { + if err != nil { + cancel() + } + }() + + opts := handshaker.DefaultClientHandshakerOptions() + opts.TargetName = addr + opts.TargetServiceAccounts = g.accounts + opts.RPCVersions = &altspb.RpcProtocolVersions{ + MaxRpcVersion: maxRPCVersion, + MinRpcVersion: minRPCVersion, + } + chs, err := handshaker.NewClientHandshaker(ctx, hsConn, rawConn, opts) + if err != nil { + return nil, nil, err + } + defer func() { + if err != nil { + chs.Close() + } + }() + secConn, authInfo, err := chs.ClientHandshake(ctx) + if err != nil { + return nil, nil, err + } + altsAuthInfo, ok := authInfo.(AuthInfo) + if !ok { + return nil, nil, errors.New("client-side auth info is not of type alts.AuthInfo") + } + match, _ := checkRPCVersions(opts.RPCVersions, altsAuthInfo.PeerRPCVersions()) + if !match { + return nil, nil, fmt.Errorf("server-side RPC versions are not compatible with this client, local versions: %v, peer versions: %v", opts.RPCVersions, altsAuthInfo.PeerRPCVersions()) + } + return secConn, authInfo, nil +} + +// ServerHandshake implements the server side ALTS handshaker. +func (g *altsTC) ServerHandshake(rawConn net.Conn) (_ net.Conn, _ credentials.AuthInfo, err error) { + if !vmOnGCP { + return nil, nil, ErrUntrustedPlatform + } + // Connecting to ALTS handshaker service. + hsConn, err := service.Dial(g.hsAddress) + if err != nil { + return nil, nil, err + } + // Do not close hsConn since it's shared with other handshakes. + + ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout) + defer cancel() + opts := handshaker.DefaultServerHandshakerOptions() + opts.RPCVersions = &altspb.RpcProtocolVersions{ + MaxRpcVersion: maxRPCVersion, + MinRpcVersion: minRPCVersion, + } + shs, err := handshaker.NewServerHandshaker(ctx, hsConn, rawConn, opts) + if err != nil { + return nil, nil, err + } + defer func() { + if err != nil { + shs.Close() + } + }() + secConn, authInfo, err := shs.ServerHandshake(ctx) + if err != nil { + return nil, nil, err + } + altsAuthInfo, ok := authInfo.(AuthInfo) + if !ok { + return nil, nil, errors.New("server-side auth info is not of type alts.AuthInfo") + } + match, _ := checkRPCVersions(opts.RPCVersions, altsAuthInfo.PeerRPCVersions()) + if !match { + return nil, nil, fmt.Errorf("client-side RPC versions is not compatible with this server, local versions: %v, peer versions: %v", opts.RPCVersions, altsAuthInfo.PeerRPCVersions()) + } + return secConn, authInfo, nil +} + +func (g *altsTC) Info() credentials.ProtocolInfo { + return *g.info +} + +func (g *altsTC) Clone() credentials.TransportCredentials { + info := *g.info + var accounts []string + if g.accounts != nil { + accounts = make([]string, len(g.accounts)) + copy(accounts, g.accounts) + } + return &altsTC{ + info: &info, + side: g.side, + hsAddress: g.hsAddress, + accounts: accounts, + } +} + +func (g *altsTC) OverrideServerName(serverNameOverride string) error { + g.info.ServerName = serverNameOverride + return nil +} + +// compareRPCVersion returns 0 if v1 == v2, 1 if v1 > v2 and -1 if v1 < v2. +func compareRPCVersions(v1, v2 *altspb.RpcProtocolVersions_Version) int { + switch { + case v1.GetMajor() > v2.GetMajor(), + v1.GetMajor() == v2.GetMajor() && v1.GetMinor() > v2.GetMinor(): + return 1 + case v1.GetMajor() < v2.GetMajor(), + v1.GetMajor() == v2.GetMajor() && v1.GetMinor() < v2.GetMinor(): + return -1 + } + return 0 +} + +// checkRPCVersions performs a version check between local and peer rpc protocol +// versions. This function returns true if the check passes which means both +// parties agreed on a common rpc protocol to use, and false otherwise. The +// function also returns the highest common RPC protocol version both parties +// agreed on. +func checkRPCVersions(local, peer *altspb.RpcProtocolVersions) (bool, *altspb.RpcProtocolVersions_Version) { + if local == nil || peer == nil { + logger.Error("invalid checkRPCVersions argument, either local or peer is nil.") + return false, nil + } + + // maxCommonVersion is MIN(local.max, peer.max). + maxCommonVersion := local.GetMaxRpcVersion() + if compareRPCVersions(local.GetMaxRpcVersion(), peer.GetMaxRpcVersion()) > 0 { + maxCommonVersion = peer.GetMaxRpcVersion() + } + + // minCommonVersion is MAX(local.min, peer.min). + minCommonVersion := peer.GetMinRpcVersion() + if compareRPCVersions(local.GetMinRpcVersion(), peer.GetMinRpcVersion()) > 0 { + minCommonVersion = local.GetMinRpcVersion() + } + + if compareRPCVersions(maxCommonVersion, minCommonVersion) < 0 { + return false, nil + } + return true, maxCommonVersion +} diff --git a/vendor/google.golang.org/grpc/credentials/alts/internal/authinfo/authinfo.go b/vendor/google.golang.org/grpc/credentials/alts/internal/authinfo/authinfo.go new file mode 100644 index 00000000000..ebea57da1de --- /dev/null +++ b/vendor/google.golang.org/grpc/credentials/alts/internal/authinfo/authinfo.go @@ -0,0 +1,95 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Package authinfo provide authentication information returned by handshakers. +package authinfo + +import ( + "google.golang.org/grpc/credentials" + altspb "google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp" +) + +var _ credentials.AuthInfo = (*altsAuthInfo)(nil) + +// altsAuthInfo exposes security information from the ALTS handshake to the +// application. altsAuthInfo is immutable and implements credentials.AuthInfo. +type altsAuthInfo struct { + p *altspb.AltsContext + credentials.CommonAuthInfo +} + +// New returns a new altsAuthInfo object given handshaker results. +func New(result *altspb.HandshakerResult) credentials.AuthInfo { + return newAuthInfo(result) +} + +func newAuthInfo(result *altspb.HandshakerResult) *altsAuthInfo { + return &altsAuthInfo{ + p: &altspb.AltsContext{ + ApplicationProtocol: result.GetApplicationProtocol(), + RecordProtocol: result.GetRecordProtocol(), + // TODO: assign security level from result. + SecurityLevel: altspb.SecurityLevel_INTEGRITY_AND_PRIVACY, + PeerServiceAccount: result.GetPeerIdentity().GetServiceAccount(), + LocalServiceAccount: result.GetLocalIdentity().GetServiceAccount(), + PeerRpcVersions: result.GetPeerRpcVersions(), + PeerAttributes: result.GetPeerIdentity().GetAttributes(), + }, + CommonAuthInfo: credentials.CommonAuthInfo{SecurityLevel: credentials.PrivacyAndIntegrity}, + } +} + +// AuthType identifies the context as providing ALTS authentication information. +func (s *altsAuthInfo) AuthType() string { + return "alts" +} + +// ApplicationProtocol returns the context's application protocol. +func (s *altsAuthInfo) ApplicationProtocol() string { + return s.p.GetApplicationProtocol() +} + +// RecordProtocol returns the context's record protocol. +func (s *altsAuthInfo) RecordProtocol() string { + return s.p.GetRecordProtocol() +} + +// SecurityLevel returns the context's security level. +func (s *altsAuthInfo) SecurityLevel() altspb.SecurityLevel { + return s.p.GetSecurityLevel() +} + +// PeerServiceAccount returns the context's peer service account. +func (s *altsAuthInfo) PeerServiceAccount() string { + return s.p.GetPeerServiceAccount() +} + +// LocalServiceAccount returns the context's local service account. +func (s *altsAuthInfo) LocalServiceAccount() string { + return s.p.GetLocalServiceAccount() +} + +// PeerRPCVersions returns the context's peer RPC versions. +func (s *altsAuthInfo) PeerRPCVersions() *altspb.RpcProtocolVersions { + return s.p.GetPeerRpcVersions() +} + +// PeerAttributes returns the context's peer attributes. +func (s *altsAuthInfo) PeerAttributes() map[string]string { + return s.p.GetPeerAttributes() +} diff --git a/vendor/google.golang.org/grpc/credentials/alts/internal/common.go b/vendor/google.golang.org/grpc/credentials/alts/internal/common.go new file mode 100644 index 00000000000..3896e8cf2b5 --- /dev/null +++ b/vendor/google.golang.org/grpc/credentials/alts/internal/common.go @@ -0,0 +1,67 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Package internal contains common core functionality for ALTS. +package internal + +import ( + "context" + "net" + + "google.golang.org/grpc/credentials" +) + +const ( + // ClientSide identifies the client in this communication. + ClientSide Side = iota + // ServerSide identifies the server in this communication. + ServerSide +) + +// PeerNotRespondingError is returned when a peer server is not responding +// after a channel has been established. It is treated as a temporary connection +// error and re-connection to the server should be attempted. +var PeerNotRespondingError = &peerNotRespondingError{} + +// Side identifies the party's role: client or server. +type Side int + +type peerNotRespondingError struct{} + +// Return an error message for the purpose of logging. +func (e *peerNotRespondingError) Error() string { + return "peer server is not responding and re-connection should be attempted." +} + +// Temporary indicates if this connection error is temporary or fatal. +func (e *peerNotRespondingError) Temporary() bool { + return true +} + +// Handshaker defines a ALTS handshaker interface. +type Handshaker interface { + // ClientHandshake starts and completes a client-side handshaking and + // returns a secure connection and corresponding auth information. + ClientHandshake(ctx context.Context) (net.Conn, credentials.AuthInfo, error) + // ServerHandshake starts and completes a server-side handshaking and + // returns a secure connection and corresponding auth information. + ServerHandshake(ctx context.Context) (net.Conn, credentials.AuthInfo, error) + // Close terminates the Handshaker. It should be called when the caller + // obtains the secure connection. + Close() +} diff --git a/vendor/google.golang.org/grpc/credentials/alts/internal/conn/aeadrekey.go b/vendor/google.golang.org/grpc/credentials/alts/internal/conn/aeadrekey.go new file mode 100644 index 00000000000..43726e877b8 --- /dev/null +++ b/vendor/google.golang.org/grpc/credentials/alts/internal/conn/aeadrekey.go @@ -0,0 +1,131 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package conn + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "crypto/hmac" + "crypto/sha256" + "encoding/binary" + "fmt" + "strconv" +) + +// rekeyAEAD holds the necessary information for an AEAD based on +// AES-GCM that performs nonce-based key derivation and XORs the +// nonce with a random mask. +type rekeyAEAD struct { + kdfKey []byte + kdfCounter []byte + nonceMask []byte + nonceBuf []byte + gcmAEAD cipher.AEAD +} + +// KeySizeError signals that the given key does not have the correct size. +type KeySizeError int + +func (k KeySizeError) Error() string { + return "alts/conn: invalid key size " + strconv.Itoa(int(k)) +} + +// newRekeyAEAD creates a new instance of aes128gcm with rekeying. +// The key argument should be 44 bytes, the first 32 bytes are used as a key +// for HKDF-expand and the remainining 12 bytes are used as a random mask for +// the counter. +func newRekeyAEAD(key []byte) (*rekeyAEAD, error) { + k := len(key) + if k != kdfKeyLen+nonceLen { + return nil, KeySizeError(k) + } + return &rekeyAEAD{ + kdfKey: key[:kdfKeyLen], + kdfCounter: make([]byte, kdfCounterLen), + nonceMask: key[kdfKeyLen:], + nonceBuf: make([]byte, nonceLen), + gcmAEAD: nil, + }, nil +} + +// Seal rekeys if nonce[2:8] is different than in the last call, masks the nonce, +// and calls Seal for aes128gcm. +func (s *rekeyAEAD) Seal(dst, nonce, plaintext, additionalData []byte) []byte { + if err := s.rekeyIfRequired(nonce); err != nil { + panic(fmt.Sprintf("Rekeying failed with: %s", err.Error())) + } + maskNonce(s.nonceBuf, nonce, s.nonceMask) + return s.gcmAEAD.Seal(dst, s.nonceBuf, plaintext, additionalData) +} + +// Open rekeys if nonce[2:8] is different than in the last call, masks the nonce, +// and calls Open for aes128gcm. +func (s *rekeyAEAD) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) { + if err := s.rekeyIfRequired(nonce); err != nil { + return nil, err + } + maskNonce(s.nonceBuf, nonce, s.nonceMask) + return s.gcmAEAD.Open(dst, s.nonceBuf, ciphertext, additionalData) +} + +// rekeyIfRequired creates a new aes128gcm AEAD if the existing AEAD is nil +// or cannot be used with given nonce. +func (s *rekeyAEAD) rekeyIfRequired(nonce []byte) error { + newKdfCounter := nonce[kdfCounterOffset : kdfCounterOffset+kdfCounterLen] + if s.gcmAEAD != nil && bytes.Equal(newKdfCounter, s.kdfCounter) { + return nil + } + copy(s.kdfCounter, newKdfCounter) + a, err := aes.NewCipher(hkdfExpand(s.kdfKey, s.kdfCounter)) + if err != nil { + return err + } + s.gcmAEAD, err = cipher.NewGCM(a) + return err +} + +// maskNonce XORs the given nonce with the mask and stores the result in dst. +func maskNonce(dst, nonce, mask []byte) { + nonce1 := binary.LittleEndian.Uint64(nonce[:sizeUint64]) + nonce2 := binary.LittleEndian.Uint32(nonce[sizeUint64:]) + mask1 := binary.LittleEndian.Uint64(mask[:sizeUint64]) + mask2 := binary.LittleEndian.Uint32(mask[sizeUint64:]) + binary.LittleEndian.PutUint64(dst[:sizeUint64], nonce1^mask1) + binary.LittleEndian.PutUint32(dst[sizeUint64:], nonce2^mask2) +} + +// NonceSize returns the required nonce size. +func (s *rekeyAEAD) NonceSize() int { + return s.gcmAEAD.NonceSize() +} + +// Overhead returns the ciphertext overhead. +func (s *rekeyAEAD) Overhead() int { + return s.gcmAEAD.Overhead() +} + +// hkdfExpand computes the first 16 bytes of the HKDF-expand function +// defined in RFC5869. +func hkdfExpand(key, info []byte) []byte { + mac := hmac.New(sha256.New, key) + mac.Write(info) + mac.Write([]byte{0x01}[:]) + return mac.Sum(nil)[:aeadKeyLen] +} diff --git a/vendor/google.golang.org/grpc/credentials/alts/internal/conn/aes128gcm.go b/vendor/google.golang.org/grpc/credentials/alts/internal/conn/aes128gcm.go new file mode 100644 index 00000000000..04e0adb6c90 --- /dev/null +++ b/vendor/google.golang.org/grpc/credentials/alts/internal/conn/aes128gcm.go @@ -0,0 +1,105 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package conn + +import ( + "crypto/aes" + "crypto/cipher" + + core "google.golang.org/grpc/credentials/alts/internal" +) + +const ( + // Overflow length n in bytes, never encrypt more than 2^(n*8) frames (in + // each direction). + overflowLenAES128GCM = 5 +) + +// aes128gcm is the struct that holds necessary information for ALTS record. +// The counter value is NOT included in the payload during the encryption and +// decryption operations. +type aes128gcm struct { + // inCounter is used in ALTS record to check that incoming counters are + // as expected, since ALTS record guarantees that messages are unwrapped + // in the same order that the peer wrapped them. + inCounter Counter + outCounter Counter + aead cipher.AEAD +} + +// NewAES128GCM creates an instance that uses aes128gcm for ALTS record. +func NewAES128GCM(side core.Side, key []byte) (ALTSRecordCrypto, error) { + c, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + a, err := cipher.NewGCM(c) + if err != nil { + return nil, err + } + return &aes128gcm{ + inCounter: NewInCounter(side, overflowLenAES128GCM), + outCounter: NewOutCounter(side, overflowLenAES128GCM), + aead: a, + }, nil +} + +// Encrypt is the encryption function. dst can contain bytes at the beginning of +// the ciphertext that will not be encrypted but will be authenticated. If dst +// has enough capacity to hold these bytes, the ciphertext and the tag, no +// allocation and copy operations will be performed. dst and plaintext do not +// overlap. +func (s *aes128gcm) Encrypt(dst, plaintext []byte) ([]byte, error) { + // If we need to allocate an output buffer, we want to include space for + // GCM tag to avoid forcing ALTS record to reallocate as well. + dlen := len(dst) + dst, out := SliceForAppend(dst, len(plaintext)+GcmTagSize) + seq, err := s.outCounter.Value() + if err != nil { + return nil, err + } + data := out[:len(plaintext)] + copy(data, plaintext) // data may alias plaintext + + // Seal appends the ciphertext and the tag to its first argument and + // returns the updated slice. However, SliceForAppend above ensures that + // dst has enough capacity to avoid a reallocation and copy due to the + // append. + dst = s.aead.Seal(dst[:dlen], seq, data, nil) + s.outCounter.Inc() + return dst, nil +} + +func (s *aes128gcm) EncryptionOverhead() int { + return GcmTagSize +} + +func (s *aes128gcm) Decrypt(dst, ciphertext []byte) ([]byte, error) { + seq, err := s.inCounter.Value() + if err != nil { + return nil, err + } + // If dst is equal to ciphertext[:0], ciphertext storage is reused. + plaintext, err := s.aead.Open(dst, seq, ciphertext, nil) + if err != nil { + return nil, ErrAuth + } + s.inCounter.Inc() + return plaintext, nil +} diff --git a/vendor/google.golang.org/grpc/credentials/alts/internal/conn/aes128gcmrekey.go b/vendor/google.golang.org/grpc/credentials/alts/internal/conn/aes128gcmrekey.go new file mode 100644 index 00000000000..6a9035ea254 --- /dev/null +++ b/vendor/google.golang.org/grpc/credentials/alts/internal/conn/aes128gcmrekey.go @@ -0,0 +1,116 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package conn + +import ( + "crypto/cipher" + + core "google.golang.org/grpc/credentials/alts/internal" +) + +const ( + // Overflow length n in bytes, never encrypt more than 2^(n*8) frames (in + // each direction). + overflowLenAES128GCMRekey = 8 + nonceLen = 12 + aeadKeyLen = 16 + kdfKeyLen = 32 + kdfCounterOffset = 2 + kdfCounterLen = 6 + sizeUint64 = 8 +) + +// aes128gcmRekey is the struct that holds necessary information for ALTS record. +// The counter value is NOT included in the payload during the encryption and +// decryption operations. +type aes128gcmRekey struct { + // inCounter is used in ALTS record to check that incoming counters are + // as expected, since ALTS record guarantees that messages are unwrapped + // in the same order that the peer wrapped them. + inCounter Counter + outCounter Counter + inAEAD cipher.AEAD + outAEAD cipher.AEAD +} + +// NewAES128GCMRekey creates an instance that uses aes128gcm with rekeying +// for ALTS record. The key argument should be 44 bytes, the first 32 bytes +// are used as a key for HKDF-expand and the remainining 12 bytes are used +// as a random mask for the counter. +func NewAES128GCMRekey(side core.Side, key []byte) (ALTSRecordCrypto, error) { + inCounter := NewInCounter(side, overflowLenAES128GCMRekey) + outCounter := NewOutCounter(side, overflowLenAES128GCMRekey) + inAEAD, err := newRekeyAEAD(key) + if err != nil { + return nil, err + } + outAEAD, err := newRekeyAEAD(key) + if err != nil { + return nil, err + } + return &aes128gcmRekey{ + inCounter, + outCounter, + inAEAD, + outAEAD, + }, nil +} + +// Encrypt is the encryption function. dst can contain bytes at the beginning of +// the ciphertext that will not be encrypted but will be authenticated. If dst +// has enough capacity to hold these bytes, the ciphertext and the tag, no +// allocation and copy operations will be performed. dst and plaintext do not +// overlap. +func (s *aes128gcmRekey) Encrypt(dst, plaintext []byte) ([]byte, error) { + // If we need to allocate an output buffer, we want to include space for + // GCM tag to avoid forcing ALTS record to reallocate as well. + dlen := len(dst) + dst, out := SliceForAppend(dst, len(plaintext)+GcmTagSize) + seq, err := s.outCounter.Value() + if err != nil { + return nil, err + } + data := out[:len(plaintext)] + copy(data, plaintext) // data may alias plaintext + + // Seal appends the ciphertext and the tag to its first argument and + // returns the updated slice. However, SliceForAppend above ensures that + // dst has enough capacity to avoid a reallocation and copy due to the + // append. + dst = s.outAEAD.Seal(dst[:dlen], seq, data, nil) + s.outCounter.Inc() + return dst, nil +} + +func (s *aes128gcmRekey) EncryptionOverhead() int { + return GcmTagSize +} + +func (s *aes128gcmRekey) Decrypt(dst, ciphertext []byte) ([]byte, error) { + seq, err := s.inCounter.Value() + if err != nil { + return nil, err + } + plaintext, err := s.inAEAD.Open(dst, seq, ciphertext, nil) + if err != nil { + return nil, ErrAuth + } + s.inCounter.Inc() + return plaintext, nil +} diff --git a/vendor/google.golang.org/grpc/credentials/alts/internal/conn/common.go b/vendor/google.golang.org/grpc/credentials/alts/internal/conn/common.go new file mode 100644 index 00000000000..1795d0c9e37 --- /dev/null +++ b/vendor/google.golang.org/grpc/credentials/alts/internal/conn/common.go @@ -0,0 +1,70 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package conn + +import ( + "encoding/binary" + "errors" + "fmt" +) + +const ( + // GcmTagSize is the GCM tag size is the difference in length between + // plaintext and ciphertext. From crypto/cipher/gcm.go in Go crypto + // library. + GcmTagSize = 16 +) + +// ErrAuth occurs on authentication failure. +var ErrAuth = errors.New("message authentication failed") + +// SliceForAppend takes a slice and a requested number of bytes. It returns a +// slice with the contents of the given slice followed by that many bytes and a +// second slice that aliases into it and contains only the extra bytes. If the +// original slice has sufficient capacity then no allocation is performed. +func SliceForAppend(in []byte, n int) (head, tail []byte) { + if total := len(in) + n; cap(in) >= total { + head = in[:total] + } else { + head = make([]byte, total) + copy(head, in) + } + tail = head[len(in):] + return head, tail +} + +// ParseFramedMsg parse the provided buffer and returns a frame of the format +// msgLength+msg and any remaining bytes in that buffer. +func ParseFramedMsg(b []byte, maxLen uint32) ([]byte, []byte, error) { + // If the size field is not complete, return the provided buffer as + // remaining buffer. + if len(b) < MsgLenFieldSize { + return nil, b, nil + } + msgLenField := b[:MsgLenFieldSize] + length := binary.LittleEndian.Uint32(msgLenField) + if length > maxLen { + return nil, nil, fmt.Errorf("received the frame length %d larger than the limit %d", length, maxLen) + } + if len(b) < int(length)+4 { // account for the first 4 msg length bytes. + // Frame is not complete yet. + return nil, b, nil + } + return b[:MsgLenFieldSize+length], b[MsgLenFieldSize+length:], nil +} diff --git a/vendor/google.golang.org/grpc/credentials/alts/internal/conn/counter.go b/vendor/google.golang.org/grpc/credentials/alts/internal/conn/counter.go new file mode 100644 index 00000000000..9f00aca0b61 --- /dev/null +++ b/vendor/google.golang.org/grpc/credentials/alts/internal/conn/counter.go @@ -0,0 +1,62 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package conn + +import ( + "errors" +) + +const counterLen = 12 + +var ( + errInvalidCounter = errors.New("invalid counter") +) + +// Counter is a 96-bit, little-endian counter. +type Counter struct { + value [counterLen]byte + invalid bool + overflowLen int +} + +// Value returns the current value of the counter as a byte slice. +func (c *Counter) Value() ([]byte, error) { + if c.invalid { + return nil, errInvalidCounter + } + return c.value[:], nil +} + +// Inc increments the counter and checks for overflow. +func (c *Counter) Inc() { + // If the counter is already invalid, there is no need to increase it. + if c.invalid { + return + } + i := 0 + for ; i < c.overflowLen; i++ { + c.value[i]++ + if c.value[i] != 0 { + break + } + } + if i == c.overflowLen { + c.invalid = true + } +} diff --git a/vendor/google.golang.org/grpc/credentials/alts/internal/conn/record.go b/vendor/google.golang.org/grpc/credentials/alts/internal/conn/record.go new file mode 100644 index 00000000000..0d64fb37a12 --- /dev/null +++ b/vendor/google.golang.org/grpc/credentials/alts/internal/conn/record.go @@ -0,0 +1,275 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Package conn contains an implementation of a secure channel created by gRPC +// handshakers. +package conn + +import ( + "encoding/binary" + "fmt" + "math" + "net" + + core "google.golang.org/grpc/credentials/alts/internal" +) + +// ALTSRecordCrypto is the interface for gRPC ALTS record protocol. +type ALTSRecordCrypto interface { + // Encrypt encrypts the plaintext and computes the tag (if any) of dst + // and plaintext. dst and plaintext may fully overlap or not at all. + Encrypt(dst, plaintext []byte) ([]byte, error) + // EncryptionOverhead returns the tag size (if any) in bytes. + EncryptionOverhead() int + // Decrypt decrypts ciphertext and verify the tag (if any). dst and + // ciphertext may alias exactly or not at all. To reuse ciphertext's + // storage for the decrypted output, use ciphertext[:0] as dst. + Decrypt(dst, ciphertext []byte) ([]byte, error) +} + +// ALTSRecordFunc is a function type for factory functions that create +// ALTSRecordCrypto instances. +type ALTSRecordFunc func(s core.Side, keyData []byte) (ALTSRecordCrypto, error) + +const ( + // MsgLenFieldSize is the byte size of the frame length field of a + // framed message. + MsgLenFieldSize = 4 + // The byte size of the message type field of a framed message. + msgTypeFieldSize = 4 + // The bytes size limit for a ALTS record message. + altsRecordLengthLimit = 1024 * 1024 // 1 MiB + // The default bytes size of a ALTS record message. + altsRecordDefaultLength = 4 * 1024 // 4KiB + // Message type value included in ALTS record framing. + altsRecordMsgType = uint32(0x06) + // The initial write buffer size. + altsWriteBufferInitialSize = 32 * 1024 // 32KiB + // The maximum write buffer size. This *must* be multiple of + // altsRecordDefaultLength. + altsWriteBufferMaxSize = 512 * 1024 // 512KiB +) + +var ( + protocols = make(map[string]ALTSRecordFunc) +) + +// RegisterProtocol register a ALTS record encryption protocol. +func RegisterProtocol(protocol string, f ALTSRecordFunc) error { + if _, ok := protocols[protocol]; ok { + return fmt.Errorf("protocol %v is already registered", protocol) + } + protocols[protocol] = f + return nil +} + +// conn represents a secured connection. It implements the net.Conn interface. +type conn struct { + net.Conn + crypto ALTSRecordCrypto + // buf holds data that has been read from the connection and decrypted, + // but has not yet been returned by Read. + buf []byte + payloadLengthLimit int + // protected holds data read from the network but have not yet been + // decrypted. This data might not compose a complete frame. + protected []byte + // writeBuf is a buffer used to contain encrypted frames before being + // written to the network. + writeBuf []byte + // nextFrame stores the next frame (in protected buffer) info. + nextFrame []byte + // overhead is the calculated overhead of each frame. + overhead int +} + +// NewConn creates a new secure channel instance given the other party role and +// handshaking result. +func NewConn(c net.Conn, side core.Side, recordProtocol string, key []byte, protected []byte) (net.Conn, error) { + newCrypto := protocols[recordProtocol] + if newCrypto == nil { + return nil, fmt.Errorf("negotiated unknown next_protocol %q", recordProtocol) + } + crypto, err := newCrypto(side, key) + if err != nil { + return nil, fmt.Errorf("protocol %q: %v", recordProtocol, err) + } + overhead := MsgLenFieldSize + msgTypeFieldSize + crypto.EncryptionOverhead() + payloadLengthLimit := altsRecordDefaultLength - overhead + var protectedBuf []byte + if protected == nil { + // We pre-allocate protected to be of size + // 2*altsRecordDefaultLength-1 during initialization. We only + // read from the network into protected when protected does not + // contain a complete frame, which is at most + // altsRecordDefaultLength-1 (bytes). And we read at most + // altsRecordDefaultLength (bytes) data into protected at one + // time. Therefore, 2*altsRecordDefaultLength-1 is large enough + // to buffer data read from the network. + protectedBuf = make([]byte, 0, 2*altsRecordDefaultLength-1) + } else { + protectedBuf = make([]byte, len(protected)) + copy(protectedBuf, protected) + } + + altsConn := &conn{ + Conn: c, + crypto: crypto, + payloadLengthLimit: payloadLengthLimit, + protected: protectedBuf, + writeBuf: make([]byte, altsWriteBufferInitialSize), + nextFrame: protectedBuf, + overhead: overhead, + } + return altsConn, nil +} + +// Read reads and decrypts a frame from the underlying connection, and copies the +// decrypted payload into b. If the size of the payload is greater than len(b), +// Read retains the remaining bytes in an internal buffer, and subsequent calls +// to Read will read from this buffer until it is exhausted. +func (p *conn) Read(b []byte) (n int, err error) { + if len(p.buf) == 0 { + var framedMsg []byte + framedMsg, p.nextFrame, err = ParseFramedMsg(p.nextFrame, altsRecordLengthLimit) + if err != nil { + return n, err + } + // Check whether the next frame to be decrypted has been + // completely received yet. + if len(framedMsg) == 0 { + copy(p.protected, p.nextFrame) + p.protected = p.protected[:len(p.nextFrame)] + // Always copy next incomplete frame to the beginning of + // the protected buffer and reset nextFrame to it. + p.nextFrame = p.protected + } + // Check whether a complete frame has been received yet. + for len(framedMsg) == 0 { + if len(p.protected) == cap(p.protected) { + tmp := make([]byte, len(p.protected), cap(p.protected)+altsRecordDefaultLength) + copy(tmp, p.protected) + p.protected = tmp + } + n, err = p.Conn.Read(p.protected[len(p.protected):min(cap(p.protected), len(p.protected)+altsRecordDefaultLength)]) + if err != nil { + return 0, err + } + p.protected = p.protected[:len(p.protected)+n] + framedMsg, p.nextFrame, err = ParseFramedMsg(p.protected, altsRecordLengthLimit) + if err != nil { + return 0, err + } + } + // Now we have a complete frame, decrypted it. + msg := framedMsg[MsgLenFieldSize:] + msgType := binary.LittleEndian.Uint32(msg[:msgTypeFieldSize]) + if msgType&0xff != altsRecordMsgType { + return 0, fmt.Errorf("received frame with incorrect message type %v, expected lower byte %v", + msgType, altsRecordMsgType) + } + ciphertext := msg[msgTypeFieldSize:] + + // Decrypt requires that if the dst and ciphertext alias, they + // must alias exactly. Code here used to use msg[:0], but msg + // starts MsgLenFieldSize+msgTypeFieldSize bytes earlier than + // ciphertext, so they alias inexactly. Using ciphertext[:0] + // arranges the appropriate aliasing without needing to copy + // ciphertext or use a separate destination buffer. For more info + // check: https://golang.org/pkg/crypto/cipher/#AEAD. + p.buf, err = p.crypto.Decrypt(ciphertext[:0], ciphertext) + if err != nil { + return 0, err + } + } + + n = copy(b, p.buf) + p.buf = p.buf[n:] + return n, nil +} + +// Write encrypts, frames, and writes bytes from b to the underlying connection. +func (p *conn) Write(b []byte) (n int, err error) { + n = len(b) + // Calculate the output buffer size with framing and encryption overhead. + numOfFrames := int(math.Ceil(float64(len(b)) / float64(p.payloadLengthLimit))) + size := len(b) + numOfFrames*p.overhead + // If writeBuf is too small, increase its size up to the maximum size. + partialBSize := len(b) + if size > altsWriteBufferMaxSize { + size = altsWriteBufferMaxSize + const numOfFramesInMaxWriteBuf = altsWriteBufferMaxSize / altsRecordDefaultLength + partialBSize = numOfFramesInMaxWriteBuf * p.payloadLengthLimit + } + if len(p.writeBuf) < size { + p.writeBuf = make([]byte, size) + } + + for partialBStart := 0; partialBStart < len(b); partialBStart += partialBSize { + partialBEnd := partialBStart + partialBSize + if partialBEnd > len(b) { + partialBEnd = len(b) + } + partialB := b[partialBStart:partialBEnd] + writeBufIndex := 0 + for len(partialB) > 0 { + payloadLen := len(partialB) + if payloadLen > p.payloadLengthLimit { + payloadLen = p.payloadLengthLimit + } + buf := partialB[:payloadLen] + partialB = partialB[payloadLen:] + + // Write buffer contains: length, type, payload, and tag + // if any. + + // 1. Fill in type field. + msg := p.writeBuf[writeBufIndex+MsgLenFieldSize:] + binary.LittleEndian.PutUint32(msg, altsRecordMsgType) + + // 2. Encrypt the payload and create a tag if any. + msg, err = p.crypto.Encrypt(msg[:msgTypeFieldSize], buf) + if err != nil { + return n, err + } + + // 3. Fill in the size field. + binary.LittleEndian.PutUint32(p.writeBuf[writeBufIndex:], uint32(len(msg))) + + // 4. Increase writeBufIndex. + writeBufIndex += len(buf) + p.overhead + } + nn, err := p.Conn.Write(p.writeBuf[:writeBufIndex]) + if err != nil { + // We need to calculate the actual data size that was + // written. This means we need to remove header, + // encryption overheads, and any partially-written + // frame data. + numOfWrittenFrames := int(math.Floor(float64(nn) / float64(altsRecordDefaultLength))) + return partialBStart + numOfWrittenFrames*p.payloadLengthLimit, err + } + } + return n, nil +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} diff --git a/vendor/google.golang.org/grpc/credentials/alts/internal/conn/utils.go b/vendor/google.golang.org/grpc/credentials/alts/internal/conn/utils.go new file mode 100644 index 00000000000..84821fa2543 --- /dev/null +++ b/vendor/google.golang.org/grpc/credentials/alts/internal/conn/utils.go @@ -0,0 +1,63 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package conn + +import core "google.golang.org/grpc/credentials/alts/internal" + +// NewOutCounter returns an outgoing counter initialized to the starting sequence +// number for the client/server side of a connection. +func NewOutCounter(s core.Side, overflowLen int) (c Counter) { + c.overflowLen = overflowLen + if s == core.ServerSide { + // Server counters in ALTS record have the little-endian high bit + // set. + c.value[counterLen-1] = 0x80 + } + return +} + +// NewInCounter returns an incoming counter initialized to the starting sequence +// number for the client/server side of a connection. This is used in ALTS record +// to check that incoming counters are as expected, since ALTS record guarantees +// that messages are unwrapped in the same order that the peer wrapped them. +func NewInCounter(s core.Side, overflowLen int) (c Counter) { + c.overflowLen = overflowLen + if s == core.ClientSide { + // Server counters in ALTS record have the little-endian high bit + // set. + c.value[counterLen-1] = 0x80 + } + return +} + +// CounterFromValue creates a new counter given an initial value. +func CounterFromValue(value []byte, overflowLen int) (c Counter) { + c.overflowLen = overflowLen + copy(c.value[:], value) + return +} + +// CounterSide returns the connection side (client/server) a sequence counter is +// associated with. +func CounterSide(c []byte) core.Side { + if c[counterLen-1]&0x80 == 0x80 { + return core.ServerSide + } + return core.ClientSide +} diff --git a/vendor/google.golang.org/grpc/credentials/alts/internal/handshaker/handshaker.go b/vendor/google.golang.org/grpc/credentials/alts/internal/handshaker/handshaker.go new file mode 100644 index 00000000000..150ae557676 --- /dev/null +++ b/vendor/google.golang.org/grpc/credentials/alts/internal/handshaker/handshaker.go @@ -0,0 +1,393 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Package handshaker provides ALTS handshaking functionality for GCP. +package handshaker + +import ( + "context" + "errors" + "fmt" + "io" + "net" + "sync" + + grpc "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/credentials" + core "google.golang.org/grpc/credentials/alts/internal" + "google.golang.org/grpc/credentials/alts/internal/authinfo" + "google.golang.org/grpc/credentials/alts/internal/conn" + altsgrpc "google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp" + altspb "google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp" +) + +const ( + // The maximum byte size of receive frames. + frameLimit = 64 * 1024 // 64 KB + rekeyRecordProtocolName = "ALTSRP_GCM_AES128_REKEY" + // maxPendingHandshakes represents the maximum number of concurrent + // handshakes. + maxPendingHandshakes = 100 +) + +var ( + hsProtocol = altspb.HandshakeProtocol_ALTS + appProtocols = []string{"grpc"} + recordProtocols = []string{rekeyRecordProtocolName} + keyLength = map[string]int{ + rekeyRecordProtocolName: 44, + } + altsRecordFuncs = map[string]conn.ALTSRecordFunc{ + // ALTS handshaker protocols. + rekeyRecordProtocolName: func(s core.Side, keyData []byte) (conn.ALTSRecordCrypto, error) { + return conn.NewAES128GCMRekey(s, keyData) + }, + } + // control number of concurrent created (but not closed) handshakers. + mu sync.Mutex + concurrentHandshakes = int64(0) + // errDropped occurs when maxPendingHandshakes is reached. + errDropped = errors.New("maximum number of concurrent ALTS handshakes is reached") + // errOutOfBound occurs when the handshake service returns a consumed + // bytes value larger than the buffer that was passed to it originally. + errOutOfBound = errors.New("handshaker service consumed bytes value is out-of-bound") +) + +func init() { + for protocol, f := range altsRecordFuncs { + if err := conn.RegisterProtocol(protocol, f); err != nil { + panic(err) + } + } +} + +func acquire() bool { + mu.Lock() + // If we need n to be configurable, we can pass it as an argument. + n := int64(1) + success := maxPendingHandshakes-concurrentHandshakes >= n + if success { + concurrentHandshakes += n + } + mu.Unlock() + return success +} + +func release() { + mu.Lock() + // If we need n to be configurable, we can pass it as an argument. + n := int64(1) + concurrentHandshakes -= n + if concurrentHandshakes < 0 { + mu.Unlock() + panic("bad release") + } + mu.Unlock() +} + +// ClientHandshakerOptions contains the client handshaker options that can +// provided by the caller. +type ClientHandshakerOptions struct { + // ClientIdentity is the handshaker client local identity. + ClientIdentity *altspb.Identity + // TargetName is the server service account name for secure name + // checking. + TargetName string + // TargetServiceAccounts contains a list of expected target service + // accounts. One of these accounts should match one of the accounts in + // the handshaker results. Otherwise, the handshake fails. + TargetServiceAccounts []string + // RPCVersions specifies the gRPC versions accepted by the client. + RPCVersions *altspb.RpcProtocolVersions +} + +// ServerHandshakerOptions contains the server handshaker options that can +// provided by the caller. +type ServerHandshakerOptions struct { + // RPCVersions specifies the gRPC versions accepted by the server. + RPCVersions *altspb.RpcProtocolVersions +} + +// DefaultClientHandshakerOptions returns the default client handshaker options. +func DefaultClientHandshakerOptions() *ClientHandshakerOptions { + return &ClientHandshakerOptions{} +} + +// DefaultServerHandshakerOptions returns the default client handshaker options. +func DefaultServerHandshakerOptions() *ServerHandshakerOptions { + return &ServerHandshakerOptions{} +} + +// TODO: add support for future local and remote endpoint in both client options +// and server options (server options struct does not exist now. When +// caller can provide endpoints, it should be created. + +// altsHandshaker is used to complete an ALTS handshake between client and +// server. This handshaker talks to the ALTS handshaker service in the metadata +// server. +type altsHandshaker struct { + // RPC stream used to access the ALTS Handshaker service. + stream altsgrpc.HandshakerService_DoHandshakeClient + // the connection to the peer. + conn net.Conn + // a virtual connection to the ALTS handshaker service. + clientConn *grpc.ClientConn + // client handshake options. + clientOpts *ClientHandshakerOptions + // server handshake options. + serverOpts *ServerHandshakerOptions + // defines the side doing the handshake, client or server. + side core.Side +} + +// NewClientHandshaker creates a core.Handshaker that performs a client-side +// ALTS handshake by acting as a proxy between the peer and the ALTS handshaker +// service in the metadata server. +func NewClientHandshaker(ctx context.Context, conn *grpc.ClientConn, c net.Conn, opts *ClientHandshakerOptions) (core.Handshaker, error) { + return &altsHandshaker{ + stream: nil, + conn: c, + clientConn: conn, + clientOpts: opts, + side: core.ClientSide, + }, nil +} + +// NewServerHandshaker creates a core.Handshaker that performs a server-side +// ALTS handshake by acting as a proxy between the peer and the ALTS handshaker +// service in the metadata server. +func NewServerHandshaker(ctx context.Context, conn *grpc.ClientConn, c net.Conn, opts *ServerHandshakerOptions) (core.Handshaker, error) { + return &altsHandshaker{ + stream: nil, + conn: c, + clientConn: conn, + serverOpts: opts, + side: core.ServerSide, + }, nil +} + +// ClientHandshake starts and completes a client ALTS handshake for GCP. Once +// done, ClientHandshake returns a secure connection. +func (h *altsHandshaker) ClientHandshake(ctx context.Context) (net.Conn, credentials.AuthInfo, error) { + if !acquire() { + return nil, nil, errDropped + } + defer release() + + if h.side != core.ClientSide { + return nil, nil, errors.New("only handshakers created using NewClientHandshaker can perform a client handshaker") + } + + // TODO(matthewstevenson88): Change unit tests to use public APIs so + // that h.stream can unconditionally be set based on h.clientConn. + if h.stream == nil { + stream, err := altsgrpc.NewHandshakerServiceClient(h.clientConn).DoHandshake(ctx) + if err != nil { + return nil, nil, fmt.Errorf("failed to establish stream to ALTS handshaker service: %v", err) + } + h.stream = stream + } + + // Create target identities from service account list. + targetIdentities := make([]*altspb.Identity, 0, len(h.clientOpts.TargetServiceAccounts)) + for _, account := range h.clientOpts.TargetServiceAccounts { + targetIdentities = append(targetIdentities, &altspb.Identity{ + IdentityOneof: &altspb.Identity_ServiceAccount{ + ServiceAccount: account, + }, + }) + } + req := &altspb.HandshakerReq{ + ReqOneof: &altspb.HandshakerReq_ClientStart{ + ClientStart: &altspb.StartClientHandshakeReq{ + HandshakeSecurityProtocol: hsProtocol, + ApplicationProtocols: appProtocols, + RecordProtocols: recordProtocols, + TargetIdentities: targetIdentities, + LocalIdentity: h.clientOpts.ClientIdentity, + TargetName: h.clientOpts.TargetName, + RpcVersions: h.clientOpts.RPCVersions, + }, + }, + } + + conn, result, err := h.doHandshake(req) + if err != nil { + return nil, nil, err + } + authInfo := authinfo.New(result) + return conn, authInfo, nil +} + +// ServerHandshake starts and completes a server ALTS handshake for GCP. Once +// done, ServerHandshake returns a secure connection. +func (h *altsHandshaker) ServerHandshake(ctx context.Context) (net.Conn, credentials.AuthInfo, error) { + if !acquire() { + return nil, nil, errDropped + } + defer release() + + if h.side != core.ServerSide { + return nil, nil, errors.New("only handshakers created using NewServerHandshaker can perform a server handshaker") + } + + // TODO(matthewstevenson88): Change unit tests to use public APIs so + // that h.stream can unconditionally be set based on h.clientConn. + if h.stream == nil { + stream, err := altsgrpc.NewHandshakerServiceClient(h.clientConn).DoHandshake(ctx) + if err != nil { + return nil, nil, fmt.Errorf("failed to establish stream to ALTS handshaker service: %v", err) + } + h.stream = stream + } + + p := make([]byte, frameLimit) + n, err := h.conn.Read(p) + if err != nil { + return nil, nil, err + } + + // Prepare server parameters. + // TODO: currently only ALTS parameters are provided. Might need to use + // more options in the future. + params := make(map[int32]*altspb.ServerHandshakeParameters) + params[int32(altspb.HandshakeProtocol_ALTS)] = &altspb.ServerHandshakeParameters{ + RecordProtocols: recordProtocols, + } + req := &altspb.HandshakerReq{ + ReqOneof: &altspb.HandshakerReq_ServerStart{ + ServerStart: &altspb.StartServerHandshakeReq{ + ApplicationProtocols: appProtocols, + HandshakeParameters: params, + InBytes: p[:n], + RpcVersions: h.serverOpts.RPCVersions, + }, + }, + } + + conn, result, err := h.doHandshake(req) + if err != nil { + return nil, nil, err + } + authInfo := authinfo.New(result) + return conn, authInfo, nil +} + +func (h *altsHandshaker) doHandshake(req *altspb.HandshakerReq) (net.Conn, *altspb.HandshakerResult, error) { + resp, err := h.accessHandshakerService(req) + if err != nil { + return nil, nil, err + } + // Check of the returned status is an error. + if resp.GetStatus() != nil { + if got, want := resp.GetStatus().Code, uint32(codes.OK); got != want { + return nil, nil, fmt.Errorf("%v", resp.GetStatus().Details) + } + } + + var extra []byte + if req.GetServerStart() != nil { + if resp.GetBytesConsumed() > uint32(len(req.GetServerStart().GetInBytes())) { + return nil, nil, errOutOfBound + } + extra = req.GetServerStart().GetInBytes()[resp.GetBytesConsumed():] + } + result, extra, err := h.processUntilDone(resp, extra) + if err != nil { + return nil, nil, err + } + // The handshaker returns a 128 bytes key. It should be truncated based + // on the returned record protocol. + keyLen, ok := keyLength[result.RecordProtocol] + if !ok { + return nil, nil, fmt.Errorf("unknown resulted record protocol %v", result.RecordProtocol) + } + sc, err := conn.NewConn(h.conn, h.side, result.GetRecordProtocol(), result.KeyData[:keyLen], extra) + if err != nil { + return nil, nil, err + } + return sc, result, nil +} + +func (h *altsHandshaker) accessHandshakerService(req *altspb.HandshakerReq) (*altspb.HandshakerResp, error) { + if err := h.stream.Send(req); err != nil { + return nil, err + } + resp, err := h.stream.Recv() + if err != nil { + return nil, err + } + return resp, nil +} + +// processUntilDone processes the handshake until the handshaker service returns +// the results. Handshaker service takes care of frame parsing, so we read +// whatever received from the network and send it to the handshaker service. +func (h *altsHandshaker) processUntilDone(resp *altspb.HandshakerResp, extra []byte) (*altspb.HandshakerResult, []byte, error) { + for { + if len(resp.OutFrames) > 0 { + if _, err := h.conn.Write(resp.OutFrames); err != nil { + return nil, nil, err + } + } + if resp.Result != nil { + return resp.Result, extra, nil + } + buf := make([]byte, frameLimit) + n, err := h.conn.Read(buf) + if err != nil && err != io.EOF { + return nil, nil, err + } + // If there is nothing to send to the handshaker service, and + // nothing is received from the peer, then we are stuck. + // This covers the case when the peer is not responding. Note + // that handshaker service connection issues are caught in + // accessHandshakerService before we even get here. + if len(resp.OutFrames) == 0 && n == 0 { + return nil, nil, core.PeerNotRespondingError + } + // Append extra bytes from the previous interaction with the + // handshaker service with the current buffer read from conn. + p := append(extra, buf[:n]...) + // From here on, p and extra point to the same slice. + resp, err = h.accessHandshakerService(&altspb.HandshakerReq{ + ReqOneof: &altspb.HandshakerReq_Next{ + Next: &altspb.NextHandshakeMessageReq{ + InBytes: p, + }, + }, + }) + if err != nil { + return nil, nil, err + } + // Set extra based on handshaker service response. + if resp.GetBytesConsumed() > uint32(len(p)) { + return nil, nil, errOutOfBound + } + extra = p[resp.GetBytesConsumed():] + } +} + +// Close terminates the Handshaker. It should be called when the caller obtains +// the secure connection. +func (h *altsHandshaker) Close() { + if h.stream != nil { + h.stream.CloseSend() + } +} diff --git a/vendor/google.golang.org/grpc/credentials/alts/internal/handshaker/service/service.go b/vendor/google.golang.org/grpc/credentials/alts/internal/handshaker/service/service.go new file mode 100644 index 00000000000..e1cdafb980c --- /dev/null +++ b/vendor/google.golang.org/grpc/credentials/alts/internal/handshaker/service/service.go @@ -0,0 +1,78 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Package service manages connections between the VM application and the ALTS +// handshaker service. +package service + +import ( + "sync" + + grpc "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +var ( + // mu guards hsConnMap and hsDialer. + mu sync.Mutex + // hsConn represents a mapping from a hypervisor handshaker service address + // to a corresponding connection to a hypervisor handshaker service + // instance. + hsConnMap = make(map[string]*grpc.ClientConn) + // hsDialer will be reassigned in tests. + hsDialer = grpc.Dial +) + +// Dial dials the handshake service in the hypervisor. If a connection has +// already been established, this function returns it. Otherwise, a new +// connection is created. +func Dial(hsAddress string) (*grpc.ClientConn, error) { + mu.Lock() + defer mu.Unlock() + + hsConn, ok := hsConnMap[hsAddress] + if !ok { + // Create a new connection to the handshaker service. Note that + // this connection stays open until the application is closed. + var err error + hsConn, err = hsDialer(hsAddress, grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + return nil, err + } + hsConnMap[hsAddress] = hsConn + } + return hsConn, nil +} + +// CloseForTesting closes all open connections to the handshaker service. +// +// For testing purposes only. +func CloseForTesting() error { + for _, hsConn := range hsConnMap { + if hsConn == nil { + continue + } + if err := hsConn.Close(); err != nil { + return err + } + } + + // Reset the connection map. + hsConnMap = make(map[string]*grpc.ClientConn) + return nil +} diff --git a/vendor/google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp/altscontext.pb.go b/vendor/google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp/altscontext.pb.go new file mode 100644 index 00000000000..83e3bae37b1 --- /dev/null +++ b/vendor/google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp/altscontext.pb.go @@ -0,0 +1,259 @@ +// Copyright 2018 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// The canonical version of this proto can be found at +// https://github.com/grpc/grpc-proto/blob/master/grpc/gcp/altscontext.proto + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.30.0 +// protoc v4.22.0 +// source: grpc/gcp/altscontext.proto + +package grpc_gcp + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type AltsContext struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The application protocol negotiated for this connection. + ApplicationProtocol string `protobuf:"bytes,1,opt,name=application_protocol,json=applicationProtocol,proto3" json:"application_protocol,omitempty"` + // The record protocol negotiated for this connection. + RecordProtocol string `protobuf:"bytes,2,opt,name=record_protocol,json=recordProtocol,proto3" json:"record_protocol,omitempty"` + // The security level of the created secure channel. + SecurityLevel SecurityLevel `protobuf:"varint,3,opt,name=security_level,json=securityLevel,proto3,enum=grpc.gcp.SecurityLevel" json:"security_level,omitempty"` + // The peer service account. + PeerServiceAccount string `protobuf:"bytes,4,opt,name=peer_service_account,json=peerServiceAccount,proto3" json:"peer_service_account,omitempty"` + // The local service account. + LocalServiceAccount string `protobuf:"bytes,5,opt,name=local_service_account,json=localServiceAccount,proto3" json:"local_service_account,omitempty"` + // The RPC protocol versions supported by the peer. + PeerRpcVersions *RpcProtocolVersions `protobuf:"bytes,6,opt,name=peer_rpc_versions,json=peerRpcVersions,proto3" json:"peer_rpc_versions,omitempty"` + // Additional attributes of the peer. + PeerAttributes map[string]string `protobuf:"bytes,7,rep,name=peer_attributes,json=peerAttributes,proto3" json:"peer_attributes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *AltsContext) Reset() { + *x = AltsContext{} + if protoimpl.UnsafeEnabled { + mi := &file_grpc_gcp_altscontext_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AltsContext) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AltsContext) ProtoMessage() {} + +func (x *AltsContext) ProtoReflect() protoreflect.Message { + mi := &file_grpc_gcp_altscontext_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AltsContext.ProtoReflect.Descriptor instead. +func (*AltsContext) Descriptor() ([]byte, []int) { + return file_grpc_gcp_altscontext_proto_rawDescGZIP(), []int{0} +} + +func (x *AltsContext) GetApplicationProtocol() string { + if x != nil { + return x.ApplicationProtocol + } + return "" +} + +func (x *AltsContext) GetRecordProtocol() string { + if x != nil { + return x.RecordProtocol + } + return "" +} + +func (x *AltsContext) GetSecurityLevel() SecurityLevel { + if x != nil { + return x.SecurityLevel + } + return SecurityLevel_SECURITY_NONE +} + +func (x *AltsContext) GetPeerServiceAccount() string { + if x != nil { + return x.PeerServiceAccount + } + return "" +} + +func (x *AltsContext) GetLocalServiceAccount() string { + if x != nil { + return x.LocalServiceAccount + } + return "" +} + +func (x *AltsContext) GetPeerRpcVersions() *RpcProtocolVersions { + if x != nil { + return x.PeerRpcVersions + } + return nil +} + +func (x *AltsContext) GetPeerAttributes() map[string]string { + if x != nil { + return x.PeerAttributes + } + return nil +} + +var File_grpc_gcp_altscontext_proto protoreflect.FileDescriptor + +var file_grpc_gcp_altscontext_proto_rawDesc = []byte{ + 0x0a, 0x1a, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x67, 0x63, 0x70, 0x2f, 0x61, 0x6c, 0x74, 0x73, 0x63, + 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x67, 0x72, + 0x70, 0x63, 0x2e, 0x67, 0x63, 0x70, 0x1a, 0x28, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x67, 0x63, 0x70, + 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x73, 0x65, 0x63, 0x75, 0x72, + 0x69, 0x74, 0x79, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x22, 0xf1, 0x03, 0x0a, 0x0b, 0x41, 0x6c, 0x74, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, + 0x12, 0x31, 0x0a, 0x14, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, + 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x63, 0x6f, 0x6c, 0x12, 0x27, 0x0a, 0x0f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x5f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x72, 0x65, + 0x63, 0x6f, 0x72, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x3e, 0x0a, 0x0e, + 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x63, 0x70, 0x2e, + 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x0d, 0x73, + 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x30, 0x0a, 0x14, + 0x70, 0x65, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, 0x63, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x70, 0x65, 0x65, 0x72, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x32, + 0x0a, 0x15, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, + 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x6c, + 0x6f, 0x63, 0x61, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x12, 0x49, 0x0a, 0x11, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x72, 0x70, 0x63, 0x5f, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x63, 0x70, 0x2e, 0x52, 0x70, 0x63, 0x50, 0x72, 0x6f, 0x74, + 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x0f, 0x70, 0x65, + 0x65, 0x72, 0x52, 0x70, 0x63, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x52, 0x0a, + 0x0f, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, + 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x63, + 0x70, 0x2e, 0x41, 0x6c, 0x74, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x50, 0x65, + 0x65, 0x72, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x0e, 0x70, 0x65, 0x65, 0x72, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, + 0x73, 0x1a, 0x41, 0x0a, 0x13, 0x50, 0x65, 0x65, 0x72, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, + 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x3a, 0x02, 0x38, 0x01, 0x42, 0x6c, 0x0a, 0x15, 0x69, 0x6f, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, + 0x61, 0x6c, 0x74, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x42, 0x10, 0x41, + 0x6c, 0x74, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, + 0x01, 0x5a, 0x3f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, + 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2f, 0x61, 0x6c, 0x74, 0x73, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x5f, 0x67, + 0x63, 0x70, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_grpc_gcp_altscontext_proto_rawDescOnce sync.Once + file_grpc_gcp_altscontext_proto_rawDescData = file_grpc_gcp_altscontext_proto_rawDesc +) + +func file_grpc_gcp_altscontext_proto_rawDescGZIP() []byte { + file_grpc_gcp_altscontext_proto_rawDescOnce.Do(func() { + file_grpc_gcp_altscontext_proto_rawDescData = protoimpl.X.CompressGZIP(file_grpc_gcp_altscontext_proto_rawDescData) + }) + return file_grpc_gcp_altscontext_proto_rawDescData +} + +var file_grpc_gcp_altscontext_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_grpc_gcp_altscontext_proto_goTypes = []interface{}{ + (*AltsContext)(nil), // 0: grpc.gcp.AltsContext + nil, // 1: grpc.gcp.AltsContext.PeerAttributesEntry + (SecurityLevel)(0), // 2: grpc.gcp.SecurityLevel + (*RpcProtocolVersions)(nil), // 3: grpc.gcp.RpcProtocolVersions +} +var file_grpc_gcp_altscontext_proto_depIdxs = []int32{ + 2, // 0: grpc.gcp.AltsContext.security_level:type_name -> grpc.gcp.SecurityLevel + 3, // 1: grpc.gcp.AltsContext.peer_rpc_versions:type_name -> grpc.gcp.RpcProtocolVersions + 1, // 2: grpc.gcp.AltsContext.peer_attributes:type_name -> grpc.gcp.AltsContext.PeerAttributesEntry + 3, // [3:3] is the sub-list for method output_type + 3, // [3:3] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name +} + +func init() { file_grpc_gcp_altscontext_proto_init() } +func file_grpc_gcp_altscontext_proto_init() { + if File_grpc_gcp_altscontext_proto != nil { + return + } + file_grpc_gcp_transport_security_common_proto_init() + if !protoimpl.UnsafeEnabled { + file_grpc_gcp_altscontext_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AltsContext); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_grpc_gcp_altscontext_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_grpc_gcp_altscontext_proto_goTypes, + DependencyIndexes: file_grpc_gcp_altscontext_proto_depIdxs, + MessageInfos: file_grpc_gcp_altscontext_proto_msgTypes, + }.Build() + File_grpc_gcp_altscontext_proto = out.File + file_grpc_gcp_altscontext_proto_rawDesc = nil + file_grpc_gcp_altscontext_proto_goTypes = nil + file_grpc_gcp_altscontext_proto_depIdxs = nil +} diff --git a/vendor/google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp/handshaker.pb.go b/vendor/google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp/handshaker.pb.go new file mode 100644 index 00000000000..0b0093328bf --- /dev/null +++ b/vendor/google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp/handshaker.pb.go @@ -0,0 +1,1423 @@ +// Copyright 2018 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// The canonical version of this proto can be found at +// https://github.com/grpc/grpc-proto/blob/master/grpc/gcp/handshaker.proto + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.30.0 +// protoc v4.22.0 +// source: grpc/gcp/handshaker.proto + +package grpc_gcp + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type HandshakeProtocol int32 + +const ( + // Default value. + HandshakeProtocol_HANDSHAKE_PROTOCOL_UNSPECIFIED HandshakeProtocol = 0 + // TLS handshake protocol. + HandshakeProtocol_TLS HandshakeProtocol = 1 + // Application Layer Transport Security handshake protocol. + HandshakeProtocol_ALTS HandshakeProtocol = 2 +) + +// Enum value maps for HandshakeProtocol. +var ( + HandshakeProtocol_name = map[int32]string{ + 0: "HANDSHAKE_PROTOCOL_UNSPECIFIED", + 1: "TLS", + 2: "ALTS", + } + HandshakeProtocol_value = map[string]int32{ + "HANDSHAKE_PROTOCOL_UNSPECIFIED": 0, + "TLS": 1, + "ALTS": 2, + } +) + +func (x HandshakeProtocol) Enum() *HandshakeProtocol { + p := new(HandshakeProtocol) + *p = x + return p +} + +func (x HandshakeProtocol) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (HandshakeProtocol) Descriptor() protoreflect.EnumDescriptor { + return file_grpc_gcp_handshaker_proto_enumTypes[0].Descriptor() +} + +func (HandshakeProtocol) Type() protoreflect.EnumType { + return &file_grpc_gcp_handshaker_proto_enumTypes[0] +} + +func (x HandshakeProtocol) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use HandshakeProtocol.Descriptor instead. +func (HandshakeProtocol) EnumDescriptor() ([]byte, []int) { + return file_grpc_gcp_handshaker_proto_rawDescGZIP(), []int{0} +} + +type NetworkProtocol int32 + +const ( + NetworkProtocol_NETWORK_PROTOCOL_UNSPECIFIED NetworkProtocol = 0 + NetworkProtocol_TCP NetworkProtocol = 1 + NetworkProtocol_UDP NetworkProtocol = 2 +) + +// Enum value maps for NetworkProtocol. +var ( + NetworkProtocol_name = map[int32]string{ + 0: "NETWORK_PROTOCOL_UNSPECIFIED", + 1: "TCP", + 2: "UDP", + } + NetworkProtocol_value = map[string]int32{ + "NETWORK_PROTOCOL_UNSPECIFIED": 0, + "TCP": 1, + "UDP": 2, + } +) + +func (x NetworkProtocol) Enum() *NetworkProtocol { + p := new(NetworkProtocol) + *p = x + return p +} + +func (x NetworkProtocol) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (NetworkProtocol) Descriptor() protoreflect.EnumDescriptor { + return file_grpc_gcp_handshaker_proto_enumTypes[1].Descriptor() +} + +func (NetworkProtocol) Type() protoreflect.EnumType { + return &file_grpc_gcp_handshaker_proto_enumTypes[1] +} + +func (x NetworkProtocol) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use NetworkProtocol.Descriptor instead. +func (NetworkProtocol) EnumDescriptor() ([]byte, []int) { + return file_grpc_gcp_handshaker_proto_rawDescGZIP(), []int{1} +} + +type Endpoint struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // IP address. It should contain an IPv4 or IPv6 string literal, e.g. + // "192.168.0.1" or "2001:db8::1". + IpAddress string `protobuf:"bytes,1,opt,name=ip_address,json=ipAddress,proto3" json:"ip_address,omitempty"` + // Port number. + Port int32 `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"` + // Network protocol (e.g., TCP, UDP) associated with this endpoint. + Protocol NetworkProtocol `protobuf:"varint,3,opt,name=protocol,proto3,enum=grpc.gcp.NetworkProtocol" json:"protocol,omitempty"` +} + +func (x *Endpoint) Reset() { + *x = Endpoint{} + if protoimpl.UnsafeEnabled { + mi := &file_grpc_gcp_handshaker_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Endpoint) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Endpoint) ProtoMessage() {} + +func (x *Endpoint) ProtoReflect() protoreflect.Message { + mi := &file_grpc_gcp_handshaker_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Endpoint.ProtoReflect.Descriptor instead. +func (*Endpoint) Descriptor() ([]byte, []int) { + return file_grpc_gcp_handshaker_proto_rawDescGZIP(), []int{0} +} + +func (x *Endpoint) GetIpAddress() string { + if x != nil { + return x.IpAddress + } + return "" +} + +func (x *Endpoint) GetPort() int32 { + if x != nil { + return x.Port + } + return 0 +} + +func (x *Endpoint) GetProtocol() NetworkProtocol { + if x != nil { + return x.Protocol + } + return NetworkProtocol_NETWORK_PROTOCOL_UNSPECIFIED +} + +type Identity struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to IdentityOneof: + // + // *Identity_ServiceAccount + // *Identity_Hostname + IdentityOneof isIdentity_IdentityOneof `protobuf_oneof:"identity_oneof"` + // Additional attributes of the identity. + Attributes map[string]string `protobuf:"bytes,3,rep,name=attributes,proto3" json:"attributes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *Identity) Reset() { + *x = Identity{} + if protoimpl.UnsafeEnabled { + mi := &file_grpc_gcp_handshaker_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Identity) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Identity) ProtoMessage() {} + +func (x *Identity) ProtoReflect() protoreflect.Message { + mi := &file_grpc_gcp_handshaker_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Identity.ProtoReflect.Descriptor instead. +func (*Identity) Descriptor() ([]byte, []int) { + return file_grpc_gcp_handshaker_proto_rawDescGZIP(), []int{1} +} + +func (m *Identity) GetIdentityOneof() isIdentity_IdentityOneof { + if m != nil { + return m.IdentityOneof + } + return nil +} + +func (x *Identity) GetServiceAccount() string { + if x, ok := x.GetIdentityOneof().(*Identity_ServiceAccount); ok { + return x.ServiceAccount + } + return "" +} + +func (x *Identity) GetHostname() string { + if x, ok := x.GetIdentityOneof().(*Identity_Hostname); ok { + return x.Hostname + } + return "" +} + +func (x *Identity) GetAttributes() map[string]string { + if x != nil { + return x.Attributes + } + return nil +} + +type isIdentity_IdentityOneof interface { + isIdentity_IdentityOneof() +} + +type Identity_ServiceAccount struct { + // Service account of a connection endpoint. + ServiceAccount string `protobuf:"bytes,1,opt,name=service_account,json=serviceAccount,proto3,oneof"` +} + +type Identity_Hostname struct { + // Hostname of a connection endpoint. + Hostname string `protobuf:"bytes,2,opt,name=hostname,proto3,oneof"` +} + +func (*Identity_ServiceAccount) isIdentity_IdentityOneof() {} + +func (*Identity_Hostname) isIdentity_IdentityOneof() {} + +type StartClientHandshakeReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Handshake security protocol requested by the client. + HandshakeSecurityProtocol HandshakeProtocol `protobuf:"varint,1,opt,name=handshake_security_protocol,json=handshakeSecurityProtocol,proto3,enum=grpc.gcp.HandshakeProtocol" json:"handshake_security_protocol,omitempty"` + // The application protocols supported by the client, e.g., "h2" (for http2), + // "grpc". + ApplicationProtocols []string `protobuf:"bytes,2,rep,name=application_protocols,json=applicationProtocols,proto3" json:"application_protocols,omitempty"` + // The record protocols supported by the client, e.g., + // "ALTSRP_GCM_AES128". + RecordProtocols []string `protobuf:"bytes,3,rep,name=record_protocols,json=recordProtocols,proto3" json:"record_protocols,omitempty"` + // (Optional) Describes which server identities are acceptable by the client. + // If target identities are provided and none of them matches the peer + // identity of the server, handshake will fail. + TargetIdentities []*Identity `protobuf:"bytes,4,rep,name=target_identities,json=targetIdentities,proto3" json:"target_identities,omitempty"` + // (Optional) Application may specify a local identity. Otherwise, the + // handshaker chooses a default local identity. + LocalIdentity *Identity `protobuf:"bytes,5,opt,name=local_identity,json=localIdentity,proto3" json:"local_identity,omitempty"` + // (Optional) Local endpoint information of the connection to the server, + // such as local IP address, port number, and network protocol. + LocalEndpoint *Endpoint `protobuf:"bytes,6,opt,name=local_endpoint,json=localEndpoint,proto3" json:"local_endpoint,omitempty"` + // (Optional) Endpoint information of the remote server, such as IP address, + // port number, and network protocol. + RemoteEndpoint *Endpoint `protobuf:"bytes,7,opt,name=remote_endpoint,json=remoteEndpoint,proto3" json:"remote_endpoint,omitempty"` + // (Optional) If target name is provided, a secure naming check is performed + // to verify that the peer authenticated identity is indeed authorized to run + // the target name. + TargetName string `protobuf:"bytes,8,opt,name=target_name,json=targetName,proto3" json:"target_name,omitempty"` + // (Optional) RPC protocol versions supported by the client. + RpcVersions *RpcProtocolVersions `protobuf:"bytes,9,opt,name=rpc_versions,json=rpcVersions,proto3" json:"rpc_versions,omitempty"` + // (Optional) Maximum frame size supported by the client. + MaxFrameSize uint32 `protobuf:"varint,10,opt,name=max_frame_size,json=maxFrameSize,proto3" json:"max_frame_size,omitempty"` +} + +func (x *StartClientHandshakeReq) Reset() { + *x = StartClientHandshakeReq{} + if protoimpl.UnsafeEnabled { + mi := &file_grpc_gcp_handshaker_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StartClientHandshakeReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StartClientHandshakeReq) ProtoMessage() {} + +func (x *StartClientHandshakeReq) ProtoReflect() protoreflect.Message { + mi := &file_grpc_gcp_handshaker_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StartClientHandshakeReq.ProtoReflect.Descriptor instead. +func (*StartClientHandshakeReq) Descriptor() ([]byte, []int) { + return file_grpc_gcp_handshaker_proto_rawDescGZIP(), []int{2} +} + +func (x *StartClientHandshakeReq) GetHandshakeSecurityProtocol() HandshakeProtocol { + if x != nil { + return x.HandshakeSecurityProtocol + } + return HandshakeProtocol_HANDSHAKE_PROTOCOL_UNSPECIFIED +} + +func (x *StartClientHandshakeReq) GetApplicationProtocols() []string { + if x != nil { + return x.ApplicationProtocols + } + return nil +} + +func (x *StartClientHandshakeReq) GetRecordProtocols() []string { + if x != nil { + return x.RecordProtocols + } + return nil +} + +func (x *StartClientHandshakeReq) GetTargetIdentities() []*Identity { + if x != nil { + return x.TargetIdentities + } + return nil +} + +func (x *StartClientHandshakeReq) GetLocalIdentity() *Identity { + if x != nil { + return x.LocalIdentity + } + return nil +} + +func (x *StartClientHandshakeReq) GetLocalEndpoint() *Endpoint { + if x != nil { + return x.LocalEndpoint + } + return nil +} + +func (x *StartClientHandshakeReq) GetRemoteEndpoint() *Endpoint { + if x != nil { + return x.RemoteEndpoint + } + return nil +} + +func (x *StartClientHandshakeReq) GetTargetName() string { + if x != nil { + return x.TargetName + } + return "" +} + +func (x *StartClientHandshakeReq) GetRpcVersions() *RpcProtocolVersions { + if x != nil { + return x.RpcVersions + } + return nil +} + +func (x *StartClientHandshakeReq) GetMaxFrameSize() uint32 { + if x != nil { + return x.MaxFrameSize + } + return 0 +} + +type ServerHandshakeParameters struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The record protocols supported by the server, e.g., + // "ALTSRP_GCM_AES128". + RecordProtocols []string `protobuf:"bytes,1,rep,name=record_protocols,json=recordProtocols,proto3" json:"record_protocols,omitempty"` + // (Optional) A list of local identities supported by the server, if + // specified. Otherwise, the handshaker chooses a default local identity. + LocalIdentities []*Identity `protobuf:"bytes,2,rep,name=local_identities,json=localIdentities,proto3" json:"local_identities,omitempty"` +} + +func (x *ServerHandshakeParameters) Reset() { + *x = ServerHandshakeParameters{} + if protoimpl.UnsafeEnabled { + mi := &file_grpc_gcp_handshaker_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ServerHandshakeParameters) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServerHandshakeParameters) ProtoMessage() {} + +func (x *ServerHandshakeParameters) ProtoReflect() protoreflect.Message { + mi := &file_grpc_gcp_handshaker_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServerHandshakeParameters.ProtoReflect.Descriptor instead. +func (*ServerHandshakeParameters) Descriptor() ([]byte, []int) { + return file_grpc_gcp_handshaker_proto_rawDescGZIP(), []int{3} +} + +func (x *ServerHandshakeParameters) GetRecordProtocols() []string { + if x != nil { + return x.RecordProtocols + } + return nil +} + +func (x *ServerHandshakeParameters) GetLocalIdentities() []*Identity { + if x != nil { + return x.LocalIdentities + } + return nil +} + +type StartServerHandshakeReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The application protocols supported by the server, e.g., "h2" (for http2), + // "grpc". + ApplicationProtocols []string `protobuf:"bytes,1,rep,name=application_protocols,json=applicationProtocols,proto3" json:"application_protocols,omitempty"` + // Handshake parameters (record protocols and local identities supported by + // the server) mapped by the handshake protocol. Each handshake security + // protocol (e.g., TLS or ALTS) has its own set of record protocols and local + // identities. Since protobuf does not support enum as key to the map, the key + // to handshake_parameters is the integer value of HandshakeProtocol enum. + HandshakeParameters map[int32]*ServerHandshakeParameters `protobuf:"bytes,2,rep,name=handshake_parameters,json=handshakeParameters,proto3" json:"handshake_parameters,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // Bytes in out_frames returned from the peer's HandshakerResp. It is possible + // that the peer's out_frames are split into multiple HandshakReq messages. + InBytes []byte `protobuf:"bytes,3,opt,name=in_bytes,json=inBytes,proto3" json:"in_bytes,omitempty"` + // (Optional) Local endpoint information of the connection to the client, + // such as local IP address, port number, and network protocol. + LocalEndpoint *Endpoint `protobuf:"bytes,4,opt,name=local_endpoint,json=localEndpoint,proto3" json:"local_endpoint,omitempty"` + // (Optional) Endpoint information of the remote client, such as IP address, + // port number, and network protocol. + RemoteEndpoint *Endpoint `protobuf:"bytes,5,opt,name=remote_endpoint,json=remoteEndpoint,proto3" json:"remote_endpoint,omitempty"` + // (Optional) RPC protocol versions supported by the server. + RpcVersions *RpcProtocolVersions `protobuf:"bytes,6,opt,name=rpc_versions,json=rpcVersions,proto3" json:"rpc_versions,omitempty"` + // (Optional) Maximum frame size supported by the server. + MaxFrameSize uint32 `protobuf:"varint,7,opt,name=max_frame_size,json=maxFrameSize,proto3" json:"max_frame_size,omitempty"` +} + +func (x *StartServerHandshakeReq) Reset() { + *x = StartServerHandshakeReq{} + if protoimpl.UnsafeEnabled { + mi := &file_grpc_gcp_handshaker_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StartServerHandshakeReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StartServerHandshakeReq) ProtoMessage() {} + +func (x *StartServerHandshakeReq) ProtoReflect() protoreflect.Message { + mi := &file_grpc_gcp_handshaker_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StartServerHandshakeReq.ProtoReflect.Descriptor instead. +func (*StartServerHandshakeReq) Descriptor() ([]byte, []int) { + return file_grpc_gcp_handshaker_proto_rawDescGZIP(), []int{4} +} + +func (x *StartServerHandshakeReq) GetApplicationProtocols() []string { + if x != nil { + return x.ApplicationProtocols + } + return nil +} + +func (x *StartServerHandshakeReq) GetHandshakeParameters() map[int32]*ServerHandshakeParameters { + if x != nil { + return x.HandshakeParameters + } + return nil +} + +func (x *StartServerHandshakeReq) GetInBytes() []byte { + if x != nil { + return x.InBytes + } + return nil +} + +func (x *StartServerHandshakeReq) GetLocalEndpoint() *Endpoint { + if x != nil { + return x.LocalEndpoint + } + return nil +} + +func (x *StartServerHandshakeReq) GetRemoteEndpoint() *Endpoint { + if x != nil { + return x.RemoteEndpoint + } + return nil +} + +func (x *StartServerHandshakeReq) GetRpcVersions() *RpcProtocolVersions { + if x != nil { + return x.RpcVersions + } + return nil +} + +func (x *StartServerHandshakeReq) GetMaxFrameSize() uint32 { + if x != nil { + return x.MaxFrameSize + } + return 0 +} + +type NextHandshakeMessageReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Bytes in out_frames returned from the peer's HandshakerResp. It is possible + // that the peer's out_frames are split into multiple NextHandshakerMessageReq + // messages. + InBytes []byte `protobuf:"bytes,1,opt,name=in_bytes,json=inBytes,proto3" json:"in_bytes,omitempty"` +} + +func (x *NextHandshakeMessageReq) Reset() { + *x = NextHandshakeMessageReq{} + if protoimpl.UnsafeEnabled { + mi := &file_grpc_gcp_handshaker_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NextHandshakeMessageReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NextHandshakeMessageReq) ProtoMessage() {} + +func (x *NextHandshakeMessageReq) ProtoReflect() protoreflect.Message { + mi := &file_grpc_gcp_handshaker_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NextHandshakeMessageReq.ProtoReflect.Descriptor instead. +func (*NextHandshakeMessageReq) Descriptor() ([]byte, []int) { + return file_grpc_gcp_handshaker_proto_rawDescGZIP(), []int{5} +} + +func (x *NextHandshakeMessageReq) GetInBytes() []byte { + if x != nil { + return x.InBytes + } + return nil +} + +type HandshakerReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to ReqOneof: + // + // *HandshakerReq_ClientStart + // *HandshakerReq_ServerStart + // *HandshakerReq_Next + ReqOneof isHandshakerReq_ReqOneof `protobuf_oneof:"req_oneof"` +} + +func (x *HandshakerReq) Reset() { + *x = HandshakerReq{} + if protoimpl.UnsafeEnabled { + mi := &file_grpc_gcp_handshaker_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *HandshakerReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HandshakerReq) ProtoMessage() {} + +func (x *HandshakerReq) ProtoReflect() protoreflect.Message { + mi := &file_grpc_gcp_handshaker_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HandshakerReq.ProtoReflect.Descriptor instead. +func (*HandshakerReq) Descriptor() ([]byte, []int) { + return file_grpc_gcp_handshaker_proto_rawDescGZIP(), []int{6} +} + +func (m *HandshakerReq) GetReqOneof() isHandshakerReq_ReqOneof { + if m != nil { + return m.ReqOneof + } + return nil +} + +func (x *HandshakerReq) GetClientStart() *StartClientHandshakeReq { + if x, ok := x.GetReqOneof().(*HandshakerReq_ClientStart); ok { + return x.ClientStart + } + return nil +} + +func (x *HandshakerReq) GetServerStart() *StartServerHandshakeReq { + if x, ok := x.GetReqOneof().(*HandshakerReq_ServerStart); ok { + return x.ServerStart + } + return nil +} + +func (x *HandshakerReq) GetNext() *NextHandshakeMessageReq { + if x, ok := x.GetReqOneof().(*HandshakerReq_Next); ok { + return x.Next + } + return nil +} + +type isHandshakerReq_ReqOneof interface { + isHandshakerReq_ReqOneof() +} + +type HandshakerReq_ClientStart struct { + // The start client handshake request message. + ClientStart *StartClientHandshakeReq `protobuf:"bytes,1,opt,name=client_start,json=clientStart,proto3,oneof"` +} + +type HandshakerReq_ServerStart struct { + // The start server handshake request message. + ServerStart *StartServerHandshakeReq `protobuf:"bytes,2,opt,name=server_start,json=serverStart,proto3,oneof"` +} + +type HandshakerReq_Next struct { + // The next handshake request message. + Next *NextHandshakeMessageReq `protobuf:"bytes,3,opt,name=next,proto3,oneof"` +} + +func (*HandshakerReq_ClientStart) isHandshakerReq_ReqOneof() {} + +func (*HandshakerReq_ServerStart) isHandshakerReq_ReqOneof() {} + +func (*HandshakerReq_Next) isHandshakerReq_ReqOneof() {} + +type HandshakerResult struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The application protocol negotiated for this connection. + ApplicationProtocol string `protobuf:"bytes,1,opt,name=application_protocol,json=applicationProtocol,proto3" json:"application_protocol,omitempty"` + // The record protocol negotiated for this connection. + RecordProtocol string `protobuf:"bytes,2,opt,name=record_protocol,json=recordProtocol,proto3" json:"record_protocol,omitempty"` + // Cryptographic key data. The key data may be more than the key length + // required for the record protocol, thus the client of the handshaker + // service needs to truncate the key data into the right key length. + KeyData []byte `protobuf:"bytes,3,opt,name=key_data,json=keyData,proto3" json:"key_data,omitempty"` + // The authenticated identity of the peer. + PeerIdentity *Identity `protobuf:"bytes,4,opt,name=peer_identity,json=peerIdentity,proto3" json:"peer_identity,omitempty"` + // The local identity used in the handshake. + LocalIdentity *Identity `protobuf:"bytes,5,opt,name=local_identity,json=localIdentity,proto3" json:"local_identity,omitempty"` + // Indicate whether the handshaker service client should keep the channel + // between the handshaker service open, e.g., in order to handle + // post-handshake messages in the future. + KeepChannelOpen bool `protobuf:"varint,6,opt,name=keep_channel_open,json=keepChannelOpen,proto3" json:"keep_channel_open,omitempty"` + // The RPC protocol versions supported by the peer. + PeerRpcVersions *RpcProtocolVersions `protobuf:"bytes,7,opt,name=peer_rpc_versions,json=peerRpcVersions,proto3" json:"peer_rpc_versions,omitempty"` + // The maximum frame size of the peer. + MaxFrameSize uint32 `protobuf:"varint,8,opt,name=max_frame_size,json=maxFrameSize,proto3" json:"max_frame_size,omitempty"` +} + +func (x *HandshakerResult) Reset() { + *x = HandshakerResult{} + if protoimpl.UnsafeEnabled { + mi := &file_grpc_gcp_handshaker_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *HandshakerResult) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HandshakerResult) ProtoMessage() {} + +func (x *HandshakerResult) ProtoReflect() protoreflect.Message { + mi := &file_grpc_gcp_handshaker_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HandshakerResult.ProtoReflect.Descriptor instead. +func (*HandshakerResult) Descriptor() ([]byte, []int) { + return file_grpc_gcp_handshaker_proto_rawDescGZIP(), []int{7} +} + +func (x *HandshakerResult) GetApplicationProtocol() string { + if x != nil { + return x.ApplicationProtocol + } + return "" +} + +func (x *HandshakerResult) GetRecordProtocol() string { + if x != nil { + return x.RecordProtocol + } + return "" +} + +func (x *HandshakerResult) GetKeyData() []byte { + if x != nil { + return x.KeyData + } + return nil +} + +func (x *HandshakerResult) GetPeerIdentity() *Identity { + if x != nil { + return x.PeerIdentity + } + return nil +} + +func (x *HandshakerResult) GetLocalIdentity() *Identity { + if x != nil { + return x.LocalIdentity + } + return nil +} + +func (x *HandshakerResult) GetKeepChannelOpen() bool { + if x != nil { + return x.KeepChannelOpen + } + return false +} + +func (x *HandshakerResult) GetPeerRpcVersions() *RpcProtocolVersions { + if x != nil { + return x.PeerRpcVersions + } + return nil +} + +func (x *HandshakerResult) GetMaxFrameSize() uint32 { + if x != nil { + return x.MaxFrameSize + } + return 0 +} + +type HandshakerStatus struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The status code. This could be the gRPC status code. + Code uint32 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"` + // The status details. + Details string `protobuf:"bytes,2,opt,name=details,proto3" json:"details,omitempty"` +} + +func (x *HandshakerStatus) Reset() { + *x = HandshakerStatus{} + if protoimpl.UnsafeEnabled { + mi := &file_grpc_gcp_handshaker_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *HandshakerStatus) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HandshakerStatus) ProtoMessage() {} + +func (x *HandshakerStatus) ProtoReflect() protoreflect.Message { + mi := &file_grpc_gcp_handshaker_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HandshakerStatus.ProtoReflect.Descriptor instead. +func (*HandshakerStatus) Descriptor() ([]byte, []int) { + return file_grpc_gcp_handshaker_proto_rawDescGZIP(), []int{8} +} + +func (x *HandshakerStatus) GetCode() uint32 { + if x != nil { + return x.Code + } + return 0 +} + +func (x *HandshakerStatus) GetDetails() string { + if x != nil { + return x.Details + } + return "" +} + +type HandshakerResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Frames to be given to the peer for the NextHandshakeMessageReq. May be + // empty if no out_frames have to be sent to the peer or if in_bytes in the + // HandshakerReq are incomplete. All the non-empty out frames must be sent to + // the peer even if the handshaker status is not OK as these frames may + // contain the alert frames. + OutFrames []byte `protobuf:"bytes,1,opt,name=out_frames,json=outFrames,proto3" json:"out_frames,omitempty"` + // Number of bytes in the in_bytes consumed by the handshaker. It is possible + // that part of in_bytes in HandshakerReq was unrelated to the handshake + // process. + BytesConsumed uint32 `protobuf:"varint,2,opt,name=bytes_consumed,json=bytesConsumed,proto3" json:"bytes_consumed,omitempty"` + // This is set iff the handshake was successful. out_frames may still be set + // to frames that needs to be forwarded to the peer. + Result *HandshakerResult `protobuf:"bytes,3,opt,name=result,proto3" json:"result,omitempty"` + // Status of the handshaker. + Status *HandshakerStatus `protobuf:"bytes,4,opt,name=status,proto3" json:"status,omitempty"` +} + +func (x *HandshakerResp) Reset() { + *x = HandshakerResp{} + if protoimpl.UnsafeEnabled { + mi := &file_grpc_gcp_handshaker_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *HandshakerResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HandshakerResp) ProtoMessage() {} + +func (x *HandshakerResp) ProtoReflect() protoreflect.Message { + mi := &file_grpc_gcp_handshaker_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HandshakerResp.ProtoReflect.Descriptor instead. +func (*HandshakerResp) Descriptor() ([]byte, []int) { + return file_grpc_gcp_handshaker_proto_rawDescGZIP(), []int{9} +} + +func (x *HandshakerResp) GetOutFrames() []byte { + if x != nil { + return x.OutFrames + } + return nil +} + +func (x *HandshakerResp) GetBytesConsumed() uint32 { + if x != nil { + return x.BytesConsumed + } + return 0 +} + +func (x *HandshakerResp) GetResult() *HandshakerResult { + if x != nil { + return x.Result + } + return nil +} + +func (x *HandshakerResp) GetStatus() *HandshakerStatus { + if x != nil { + return x.Status + } + return nil +} + +var File_grpc_gcp_handshaker_proto protoreflect.FileDescriptor + +var file_grpc_gcp_handshaker_proto_rawDesc = []byte{ + 0x0a, 0x19, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x67, 0x63, 0x70, 0x2f, 0x68, 0x61, 0x6e, 0x64, 0x73, + 0x68, 0x61, 0x6b, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x67, 0x72, 0x70, + 0x63, 0x2e, 0x67, 0x63, 0x70, 0x1a, 0x28, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x67, 0x63, 0x70, 0x2f, + 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, + 0x74, 0x79, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, + 0x74, 0x0a, 0x08, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x69, + 0x70, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x69, 0x70, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, + 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x35, + 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x19, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x63, 0x70, 0x2e, 0x4e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x52, 0x08, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x22, 0xe8, 0x01, 0x0a, 0x08, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x74, 0x79, 0x12, 0x29, 0x0a, 0x0f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0e, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1c, 0x0a, + 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, + 0x00, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x42, 0x0a, 0x0a, 0x61, + 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x22, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x63, 0x70, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x74, 0x79, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x1a, + 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x10, + 0x0a, 0x0e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x6f, 0x6e, 0x65, 0x6f, 0x66, + 0x22, 0xd3, 0x04, 0x0a, 0x17, 0x53, 0x74, 0x61, 0x72, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x48, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x52, 0x65, 0x71, 0x12, 0x5b, 0x0a, 0x1b, + 0x68, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x5f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, + 0x74, 0x79, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x1b, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x63, 0x70, 0x2e, 0x48, 0x61, 0x6e, + 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x52, 0x19, + 0x68, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, + 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x33, 0x0a, 0x15, 0x61, 0x70, 0x70, + 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, + 0x6c, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x14, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x12, 0x29, + 0x0a, 0x10, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, + 0x6c, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x12, 0x3f, 0x0a, 0x11, 0x74, 0x61, 0x72, + 0x67, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, 0x04, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x63, 0x70, 0x2e, + 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x10, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, + 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x69, 0x65, 0x73, 0x12, 0x39, 0x0a, 0x0e, 0x6c, 0x6f, + 0x63, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x63, 0x70, 0x2e, 0x49, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x0d, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x39, 0x0a, 0x0e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x65, + 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x63, 0x70, 0x2e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, + 0x74, 0x52, 0x0d, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, + 0x12, 0x3b, 0x0a, 0x0f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, + 0x69, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, + 0x2e, 0x67, 0x63, 0x70, 0x2e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x0e, 0x72, + 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x1f, 0x0a, + 0x0b, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x40, + 0x0a, 0x0c, 0x72, 0x70, 0x63, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x63, 0x70, 0x2e, + 0x52, 0x70, 0x63, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x52, 0x0b, 0x72, 0x70, 0x63, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, + 0x12, 0x24, 0x0a, 0x0e, 0x6d, 0x61, 0x78, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x73, 0x69, + 0x7a, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x6d, 0x61, 0x78, 0x46, 0x72, 0x61, + 0x6d, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x22, 0x85, 0x01, 0x0a, 0x19, 0x53, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x48, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, + 0x74, 0x65, 0x72, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x5f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, + 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x12, + 0x3d, 0x0a, 0x10, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, + 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, + 0x2e, 0x67, 0x63, 0x70, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x0f, 0x6c, + 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x69, 0x65, 0x73, 0x22, 0xa5, + 0x04, 0x0a, 0x17, 0x53, 0x74, 0x61, 0x72, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x48, 0x61, + 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x52, 0x65, 0x71, 0x12, 0x33, 0x0a, 0x15, 0x61, 0x70, + 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, + 0x6f, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x14, 0x61, 0x70, 0x70, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x12, + 0x6d, 0x0a, 0x14, 0x68, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x5f, 0x70, 0x61, 0x72, + 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3a, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x63, 0x70, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x53, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x48, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x52, 0x65, 0x71, + 0x2e, 0x48, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, + 0x74, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x13, 0x68, 0x61, 0x6e, 0x64, 0x73, + 0x68, 0x61, 0x6b, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x19, + 0x0a, 0x08, 0x69, 0x6e, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x07, 0x69, 0x6e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x39, 0x0a, 0x0e, 0x6c, 0x6f, 0x63, + 0x61, 0x6c, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x63, 0x70, 0x2e, 0x45, 0x6e, 0x64, + 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x0d, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x45, 0x6e, 0x64, 0x70, + 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x3b, 0x0a, 0x0f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x65, + 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x63, 0x70, 0x2e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, + 0x74, 0x52, 0x0e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, + 0x74, 0x12, 0x40, 0x0a, 0x0c, 0x72, 0x70, 0x63, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, + 0x63, 0x70, 0x2e, 0x52, 0x70, 0x63, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x0b, 0x72, 0x70, 0x63, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x12, 0x24, 0x0a, 0x0e, 0x6d, 0x61, 0x78, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, + 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x6d, 0x61, 0x78, + 0x46, 0x72, 0x61, 0x6d, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x1a, 0x6b, 0x0a, 0x18, 0x48, 0x61, 0x6e, + 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x39, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x63, + 0x70, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x48, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, + 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x34, 0x0a, 0x17, 0x4e, 0x65, 0x78, 0x74, 0x48, 0x61, + 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, + 0x71, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x6e, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x07, 0x69, 0x6e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x22, 0xe5, 0x01, 0x0a, + 0x0d, 0x48, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x72, 0x52, 0x65, 0x71, 0x12, 0x46, + 0x0a, 0x0c, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x63, 0x70, 0x2e, + 0x53, 0x74, 0x61, 0x72, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x6e, 0x64, 0x73, + 0x68, 0x61, 0x6b, 0x65, 0x52, 0x65, 0x71, 0x48, 0x00, 0x52, 0x0b, 0x63, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x46, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x67, + 0x72, 0x70, 0x63, 0x2e, 0x67, 0x63, 0x70, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x48, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x52, 0x65, 0x71, 0x48, + 0x00, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x37, + 0x0a, 0x04, 0x6e, 0x65, 0x78, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x67, + 0x72, 0x70, 0x63, 0x2e, 0x67, 0x63, 0x70, 0x2e, 0x4e, 0x65, 0x78, 0x74, 0x48, 0x61, 0x6e, 0x64, + 0x73, 0x68, 0x61, 0x6b, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x48, + 0x00, 0x52, 0x04, 0x6e, 0x65, 0x78, 0x74, 0x42, 0x0b, 0x0a, 0x09, 0x72, 0x65, 0x71, 0x5f, 0x6f, + 0x6e, 0x65, 0x6f, 0x66, 0x22, 0x9a, 0x03, 0x0a, 0x10, 0x48, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, + 0x6b, 0x65, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x31, 0x0a, 0x14, 0x61, 0x70, 0x70, + 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, + 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x27, 0x0a, 0x0f, + 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x19, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x64, 0x61, 0x74, + 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x44, 0x61, 0x74, 0x61, + 0x12, 0x37, 0x0a, 0x0d, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, + 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, + 0x63, 0x70, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x0c, 0x70, 0x65, 0x65, + 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x39, 0x0a, 0x0e, 0x6c, 0x6f, 0x63, + 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x63, 0x70, 0x2e, 0x49, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x0d, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x12, 0x2a, 0x0a, 0x11, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x63, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0f, 0x6b, 0x65, 0x65, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4f, 0x70, 0x65, 0x6e, + 0x12, 0x49, 0x0a, 0x11, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x72, 0x70, 0x63, 0x5f, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x67, 0x72, + 0x70, 0x63, 0x2e, 0x67, 0x63, 0x70, 0x2e, 0x52, 0x70, 0x63, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, + 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x0f, 0x70, 0x65, 0x65, 0x72, + 0x52, 0x70, 0x63, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x24, 0x0a, 0x0e, 0x6d, + 0x61, 0x78, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x08, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x6d, 0x61, 0x78, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x53, 0x69, 0x7a, + 0x65, 0x22, 0x40, 0x0a, 0x10, 0x48, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x72, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x74, + 0x61, 0x69, 0x6c, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x64, 0x65, 0x74, 0x61, + 0x69, 0x6c, 0x73, 0x22, 0xbe, 0x01, 0x0a, 0x0e, 0x48, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, + 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x12, 0x1d, 0x0a, 0x0a, 0x6f, 0x75, 0x74, 0x5f, 0x66, 0x72, + 0x61, 0x6d, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x6f, 0x75, 0x74, 0x46, + 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x63, + 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x62, + 0x79, 0x74, 0x65, 0x73, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x64, 0x12, 0x32, 0x0a, 0x06, + 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, + 0x72, 0x70, 0x63, 0x2e, 0x67, 0x63, 0x70, 0x2e, 0x48, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, + 0x65, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x12, 0x32, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x63, 0x70, 0x2e, 0x48, 0x61, 0x6e, 0x64, + 0x73, 0x68, 0x61, 0x6b, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x2a, 0x4a, 0x0a, 0x11, 0x48, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, + 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x22, 0x0a, 0x1e, 0x48, 0x41, 0x4e, + 0x44, 0x53, 0x48, 0x41, 0x4b, 0x45, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, + 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x07, 0x0a, + 0x03, 0x54, 0x4c, 0x53, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x41, 0x4c, 0x54, 0x53, 0x10, 0x02, + 0x2a, 0x45, 0x0a, 0x0f, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x63, 0x6f, 0x6c, 0x12, 0x20, 0x0a, 0x1c, 0x4e, 0x45, 0x54, 0x57, 0x4f, 0x52, 0x4b, 0x5f, 0x50, + 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, + 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x54, 0x43, 0x50, 0x10, 0x01, 0x12, 0x07, + 0x0a, 0x03, 0x55, 0x44, 0x50, 0x10, 0x02, 0x32, 0x5b, 0x0a, 0x11, 0x48, 0x61, 0x6e, 0x64, 0x73, + 0x68, 0x61, 0x6b, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x46, 0x0a, 0x0b, + 0x44, 0x6f, 0x48, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x12, 0x17, 0x2e, 0x67, 0x72, + 0x70, 0x63, 0x2e, 0x67, 0x63, 0x70, 0x2e, 0x48, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, + 0x72, 0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x63, 0x70, 0x2e, + 0x48, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, + 0x28, 0x01, 0x30, 0x01, 0x42, 0x6b, 0x0a, 0x15, 0x69, 0x6f, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, + 0x61, 0x6c, 0x74, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x42, 0x0f, 0x48, + 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, + 0x5a, 0x3f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, + 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x61, 0x6c, 0x73, 0x2f, 0x61, 0x6c, 0x74, 0x73, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x5f, 0x67, 0x63, + 0x70, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_grpc_gcp_handshaker_proto_rawDescOnce sync.Once + file_grpc_gcp_handshaker_proto_rawDescData = file_grpc_gcp_handshaker_proto_rawDesc +) + +func file_grpc_gcp_handshaker_proto_rawDescGZIP() []byte { + file_grpc_gcp_handshaker_proto_rawDescOnce.Do(func() { + file_grpc_gcp_handshaker_proto_rawDescData = protoimpl.X.CompressGZIP(file_grpc_gcp_handshaker_proto_rawDescData) + }) + return file_grpc_gcp_handshaker_proto_rawDescData +} + +var file_grpc_gcp_handshaker_proto_enumTypes = make([]protoimpl.EnumInfo, 2) +var file_grpc_gcp_handshaker_proto_msgTypes = make([]protoimpl.MessageInfo, 12) +var file_grpc_gcp_handshaker_proto_goTypes = []interface{}{ + (HandshakeProtocol)(0), // 0: grpc.gcp.HandshakeProtocol + (NetworkProtocol)(0), // 1: grpc.gcp.NetworkProtocol + (*Endpoint)(nil), // 2: grpc.gcp.Endpoint + (*Identity)(nil), // 3: grpc.gcp.Identity + (*StartClientHandshakeReq)(nil), // 4: grpc.gcp.StartClientHandshakeReq + (*ServerHandshakeParameters)(nil), // 5: grpc.gcp.ServerHandshakeParameters + (*StartServerHandshakeReq)(nil), // 6: grpc.gcp.StartServerHandshakeReq + (*NextHandshakeMessageReq)(nil), // 7: grpc.gcp.NextHandshakeMessageReq + (*HandshakerReq)(nil), // 8: grpc.gcp.HandshakerReq + (*HandshakerResult)(nil), // 9: grpc.gcp.HandshakerResult + (*HandshakerStatus)(nil), // 10: grpc.gcp.HandshakerStatus + (*HandshakerResp)(nil), // 11: grpc.gcp.HandshakerResp + nil, // 12: grpc.gcp.Identity.AttributesEntry + nil, // 13: grpc.gcp.StartServerHandshakeReq.HandshakeParametersEntry + (*RpcProtocolVersions)(nil), // 14: grpc.gcp.RpcProtocolVersions +} +var file_grpc_gcp_handshaker_proto_depIdxs = []int32{ + 1, // 0: grpc.gcp.Endpoint.protocol:type_name -> grpc.gcp.NetworkProtocol + 12, // 1: grpc.gcp.Identity.attributes:type_name -> grpc.gcp.Identity.AttributesEntry + 0, // 2: grpc.gcp.StartClientHandshakeReq.handshake_security_protocol:type_name -> grpc.gcp.HandshakeProtocol + 3, // 3: grpc.gcp.StartClientHandshakeReq.target_identities:type_name -> grpc.gcp.Identity + 3, // 4: grpc.gcp.StartClientHandshakeReq.local_identity:type_name -> grpc.gcp.Identity + 2, // 5: grpc.gcp.StartClientHandshakeReq.local_endpoint:type_name -> grpc.gcp.Endpoint + 2, // 6: grpc.gcp.StartClientHandshakeReq.remote_endpoint:type_name -> grpc.gcp.Endpoint + 14, // 7: grpc.gcp.StartClientHandshakeReq.rpc_versions:type_name -> grpc.gcp.RpcProtocolVersions + 3, // 8: grpc.gcp.ServerHandshakeParameters.local_identities:type_name -> grpc.gcp.Identity + 13, // 9: grpc.gcp.StartServerHandshakeReq.handshake_parameters:type_name -> grpc.gcp.StartServerHandshakeReq.HandshakeParametersEntry + 2, // 10: grpc.gcp.StartServerHandshakeReq.local_endpoint:type_name -> grpc.gcp.Endpoint + 2, // 11: grpc.gcp.StartServerHandshakeReq.remote_endpoint:type_name -> grpc.gcp.Endpoint + 14, // 12: grpc.gcp.StartServerHandshakeReq.rpc_versions:type_name -> grpc.gcp.RpcProtocolVersions + 4, // 13: grpc.gcp.HandshakerReq.client_start:type_name -> grpc.gcp.StartClientHandshakeReq + 6, // 14: grpc.gcp.HandshakerReq.server_start:type_name -> grpc.gcp.StartServerHandshakeReq + 7, // 15: grpc.gcp.HandshakerReq.next:type_name -> grpc.gcp.NextHandshakeMessageReq + 3, // 16: grpc.gcp.HandshakerResult.peer_identity:type_name -> grpc.gcp.Identity + 3, // 17: grpc.gcp.HandshakerResult.local_identity:type_name -> grpc.gcp.Identity + 14, // 18: grpc.gcp.HandshakerResult.peer_rpc_versions:type_name -> grpc.gcp.RpcProtocolVersions + 9, // 19: grpc.gcp.HandshakerResp.result:type_name -> grpc.gcp.HandshakerResult + 10, // 20: grpc.gcp.HandshakerResp.status:type_name -> grpc.gcp.HandshakerStatus + 5, // 21: grpc.gcp.StartServerHandshakeReq.HandshakeParametersEntry.value:type_name -> grpc.gcp.ServerHandshakeParameters + 8, // 22: grpc.gcp.HandshakerService.DoHandshake:input_type -> grpc.gcp.HandshakerReq + 11, // 23: grpc.gcp.HandshakerService.DoHandshake:output_type -> grpc.gcp.HandshakerResp + 23, // [23:24] is the sub-list for method output_type + 22, // [22:23] is the sub-list for method input_type + 22, // [22:22] is the sub-list for extension type_name + 22, // [22:22] is the sub-list for extension extendee + 0, // [0:22] is the sub-list for field type_name +} + +func init() { file_grpc_gcp_handshaker_proto_init() } +func file_grpc_gcp_handshaker_proto_init() { + if File_grpc_gcp_handshaker_proto != nil { + return + } + file_grpc_gcp_transport_security_common_proto_init() + if !protoimpl.UnsafeEnabled { + file_grpc_gcp_handshaker_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Endpoint); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_grpc_gcp_handshaker_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Identity); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_grpc_gcp_handshaker_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StartClientHandshakeReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_grpc_gcp_handshaker_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ServerHandshakeParameters); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_grpc_gcp_handshaker_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StartServerHandshakeReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_grpc_gcp_handshaker_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NextHandshakeMessageReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_grpc_gcp_handshaker_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*HandshakerReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_grpc_gcp_handshaker_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*HandshakerResult); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_grpc_gcp_handshaker_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*HandshakerStatus); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_grpc_gcp_handshaker_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*HandshakerResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_grpc_gcp_handshaker_proto_msgTypes[1].OneofWrappers = []interface{}{ + (*Identity_ServiceAccount)(nil), + (*Identity_Hostname)(nil), + } + file_grpc_gcp_handshaker_proto_msgTypes[6].OneofWrappers = []interface{}{ + (*HandshakerReq_ClientStart)(nil), + (*HandshakerReq_ServerStart)(nil), + (*HandshakerReq_Next)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_grpc_gcp_handshaker_proto_rawDesc, + NumEnums: 2, + NumMessages: 12, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_grpc_gcp_handshaker_proto_goTypes, + DependencyIndexes: file_grpc_gcp_handshaker_proto_depIdxs, + EnumInfos: file_grpc_gcp_handshaker_proto_enumTypes, + MessageInfos: file_grpc_gcp_handshaker_proto_msgTypes, + }.Build() + File_grpc_gcp_handshaker_proto = out.File + file_grpc_gcp_handshaker_proto_rawDesc = nil + file_grpc_gcp_handshaker_proto_goTypes = nil + file_grpc_gcp_handshaker_proto_depIdxs = nil +} diff --git a/vendor/google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp/handshaker_grpc.pb.go b/vendor/google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp/handshaker_grpc.pb.go new file mode 100644 index 00000000000..39ecccf878e --- /dev/null +++ b/vendor/google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp/handshaker_grpc.pb.go @@ -0,0 +1,170 @@ +// Copyright 2018 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// The canonical version of this proto can be found at +// https://github.com/grpc/grpc-proto/blob/master/grpc/gcp/handshaker.proto + +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.3.0 +// - protoc v4.22.0 +// source: grpc/gcp/handshaker.proto + +package grpc_gcp + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +const ( + HandshakerService_DoHandshake_FullMethodName = "/grpc.gcp.HandshakerService/DoHandshake" +) + +// HandshakerServiceClient is the client API for HandshakerService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type HandshakerServiceClient interface { + // Handshaker service accepts a stream of handshaker request, returning a + // stream of handshaker response. Client is expected to send exactly one + // message with either client_start or server_start followed by one or more + // messages with next. Each time client sends a request, the handshaker + // service expects to respond. Client does not have to wait for service's + // response before sending next request. + DoHandshake(ctx context.Context, opts ...grpc.CallOption) (HandshakerService_DoHandshakeClient, error) +} + +type handshakerServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewHandshakerServiceClient(cc grpc.ClientConnInterface) HandshakerServiceClient { + return &handshakerServiceClient{cc} +} + +func (c *handshakerServiceClient) DoHandshake(ctx context.Context, opts ...grpc.CallOption) (HandshakerService_DoHandshakeClient, error) { + stream, err := c.cc.NewStream(ctx, &HandshakerService_ServiceDesc.Streams[0], HandshakerService_DoHandshake_FullMethodName, opts...) + if err != nil { + return nil, err + } + x := &handshakerServiceDoHandshakeClient{stream} + return x, nil +} + +type HandshakerService_DoHandshakeClient interface { + Send(*HandshakerReq) error + Recv() (*HandshakerResp, error) + grpc.ClientStream +} + +type handshakerServiceDoHandshakeClient struct { + grpc.ClientStream +} + +func (x *handshakerServiceDoHandshakeClient) Send(m *HandshakerReq) error { + return x.ClientStream.SendMsg(m) +} + +func (x *handshakerServiceDoHandshakeClient) Recv() (*HandshakerResp, error) { + m := new(HandshakerResp) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +// HandshakerServiceServer is the server API for HandshakerService service. +// All implementations must embed UnimplementedHandshakerServiceServer +// for forward compatibility +type HandshakerServiceServer interface { + // Handshaker service accepts a stream of handshaker request, returning a + // stream of handshaker response. Client is expected to send exactly one + // message with either client_start or server_start followed by one or more + // messages with next. Each time client sends a request, the handshaker + // service expects to respond. Client does not have to wait for service's + // response before sending next request. + DoHandshake(HandshakerService_DoHandshakeServer) error + mustEmbedUnimplementedHandshakerServiceServer() +} + +// UnimplementedHandshakerServiceServer must be embedded to have forward compatible implementations. +type UnimplementedHandshakerServiceServer struct { +} + +func (UnimplementedHandshakerServiceServer) DoHandshake(HandshakerService_DoHandshakeServer) error { + return status.Errorf(codes.Unimplemented, "method DoHandshake not implemented") +} +func (UnimplementedHandshakerServiceServer) mustEmbedUnimplementedHandshakerServiceServer() {} + +// UnsafeHandshakerServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to HandshakerServiceServer will +// result in compilation errors. +type UnsafeHandshakerServiceServer interface { + mustEmbedUnimplementedHandshakerServiceServer() +} + +func RegisterHandshakerServiceServer(s grpc.ServiceRegistrar, srv HandshakerServiceServer) { + s.RegisterService(&HandshakerService_ServiceDesc, srv) +} + +func _HandshakerService_DoHandshake_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(HandshakerServiceServer).DoHandshake(&handshakerServiceDoHandshakeServer{stream}) +} + +type HandshakerService_DoHandshakeServer interface { + Send(*HandshakerResp) error + Recv() (*HandshakerReq, error) + grpc.ServerStream +} + +type handshakerServiceDoHandshakeServer struct { + grpc.ServerStream +} + +func (x *handshakerServiceDoHandshakeServer) Send(m *HandshakerResp) error { + return x.ServerStream.SendMsg(m) +} + +func (x *handshakerServiceDoHandshakeServer) Recv() (*HandshakerReq, error) { + m := new(HandshakerReq) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +// HandshakerService_ServiceDesc is the grpc.ServiceDesc for HandshakerService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var HandshakerService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "grpc.gcp.HandshakerService", + HandlerType: (*HandshakerServiceServer)(nil), + Methods: []grpc.MethodDesc{}, + Streams: []grpc.StreamDesc{ + { + StreamName: "DoHandshake", + Handler: _HandshakerService_DoHandshake_Handler, + ServerStreams: true, + ClientStreams: true, + }, + }, + Metadata: "grpc/gcp/handshaker.proto", +} diff --git a/vendor/google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp/transport_security_common.pb.go b/vendor/google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp/transport_security_common.pb.go new file mode 100644 index 00000000000..c2e564c7ded --- /dev/null +++ b/vendor/google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp/transport_security_common.pb.go @@ -0,0 +1,321 @@ +// Copyright 2018 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// The canonical version of this proto can be found at +// https://github.com/grpc/grpc-proto/blob/master/grpc/gcp/transport_security_common.proto + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.30.0 +// protoc v4.22.0 +// source: grpc/gcp/transport_security_common.proto + +package grpc_gcp + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// The security level of the created channel. The list is sorted in increasing +// level of security. This order must always be maintained. +type SecurityLevel int32 + +const ( + SecurityLevel_SECURITY_NONE SecurityLevel = 0 + SecurityLevel_INTEGRITY_ONLY SecurityLevel = 1 + SecurityLevel_INTEGRITY_AND_PRIVACY SecurityLevel = 2 +) + +// Enum value maps for SecurityLevel. +var ( + SecurityLevel_name = map[int32]string{ + 0: "SECURITY_NONE", + 1: "INTEGRITY_ONLY", + 2: "INTEGRITY_AND_PRIVACY", + } + SecurityLevel_value = map[string]int32{ + "SECURITY_NONE": 0, + "INTEGRITY_ONLY": 1, + "INTEGRITY_AND_PRIVACY": 2, + } +) + +func (x SecurityLevel) Enum() *SecurityLevel { + p := new(SecurityLevel) + *p = x + return p +} + +func (x SecurityLevel) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (SecurityLevel) Descriptor() protoreflect.EnumDescriptor { + return file_grpc_gcp_transport_security_common_proto_enumTypes[0].Descriptor() +} + +func (SecurityLevel) Type() protoreflect.EnumType { + return &file_grpc_gcp_transport_security_common_proto_enumTypes[0] +} + +func (x SecurityLevel) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use SecurityLevel.Descriptor instead. +func (SecurityLevel) EnumDescriptor() ([]byte, []int) { + return file_grpc_gcp_transport_security_common_proto_rawDescGZIP(), []int{0} +} + +// Max and min supported RPC protocol versions. +type RpcProtocolVersions struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Maximum supported RPC version. + MaxRpcVersion *RpcProtocolVersions_Version `protobuf:"bytes,1,opt,name=max_rpc_version,json=maxRpcVersion,proto3" json:"max_rpc_version,omitempty"` + // Minimum supported RPC version. + MinRpcVersion *RpcProtocolVersions_Version `protobuf:"bytes,2,opt,name=min_rpc_version,json=minRpcVersion,proto3" json:"min_rpc_version,omitempty"` +} + +func (x *RpcProtocolVersions) Reset() { + *x = RpcProtocolVersions{} + if protoimpl.UnsafeEnabled { + mi := &file_grpc_gcp_transport_security_common_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RpcProtocolVersions) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RpcProtocolVersions) ProtoMessage() {} + +func (x *RpcProtocolVersions) ProtoReflect() protoreflect.Message { + mi := &file_grpc_gcp_transport_security_common_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RpcProtocolVersions.ProtoReflect.Descriptor instead. +func (*RpcProtocolVersions) Descriptor() ([]byte, []int) { + return file_grpc_gcp_transport_security_common_proto_rawDescGZIP(), []int{0} +} + +func (x *RpcProtocolVersions) GetMaxRpcVersion() *RpcProtocolVersions_Version { + if x != nil { + return x.MaxRpcVersion + } + return nil +} + +func (x *RpcProtocolVersions) GetMinRpcVersion() *RpcProtocolVersions_Version { + if x != nil { + return x.MinRpcVersion + } + return nil +} + +// RPC version contains a major version and a minor version. +type RpcProtocolVersions_Version struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Major uint32 `protobuf:"varint,1,opt,name=major,proto3" json:"major,omitempty"` + Minor uint32 `protobuf:"varint,2,opt,name=minor,proto3" json:"minor,omitempty"` +} + +func (x *RpcProtocolVersions_Version) Reset() { + *x = RpcProtocolVersions_Version{} + if protoimpl.UnsafeEnabled { + mi := &file_grpc_gcp_transport_security_common_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RpcProtocolVersions_Version) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RpcProtocolVersions_Version) ProtoMessage() {} + +func (x *RpcProtocolVersions_Version) ProtoReflect() protoreflect.Message { + mi := &file_grpc_gcp_transport_security_common_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RpcProtocolVersions_Version.ProtoReflect.Descriptor instead. +func (*RpcProtocolVersions_Version) Descriptor() ([]byte, []int) { + return file_grpc_gcp_transport_security_common_proto_rawDescGZIP(), []int{0, 0} +} + +func (x *RpcProtocolVersions_Version) GetMajor() uint32 { + if x != nil { + return x.Major + } + return 0 +} + +func (x *RpcProtocolVersions_Version) GetMinor() uint32 { + if x != nil { + return x.Minor + } + return 0 +} + +var File_grpc_gcp_transport_security_common_proto protoreflect.FileDescriptor + +var file_grpc_gcp_transport_security_common_proto_rawDesc = []byte{ + 0x0a, 0x28, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x67, 0x63, 0x70, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, + 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x67, 0x72, 0x70, 0x63, + 0x2e, 0x67, 0x63, 0x70, 0x22, 0xea, 0x01, 0x0a, 0x13, 0x52, 0x70, 0x63, 0x50, 0x72, 0x6f, 0x74, + 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x4d, 0x0a, 0x0f, + 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x70, 0x63, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x63, 0x70, + 0x2e, 0x52, 0x70, 0x63, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0d, 0x6d, 0x61, + 0x78, 0x52, 0x70, 0x63, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x4d, 0x0a, 0x0f, 0x6d, + 0x69, 0x6e, 0x5f, 0x72, 0x70, 0x63, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x67, 0x63, 0x70, 0x2e, + 0x52, 0x70, 0x63, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0d, 0x6d, 0x69, 0x6e, + 0x52, 0x70, 0x63, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x1a, 0x35, 0x0a, 0x07, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x6d, + 0x69, 0x6e, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x6d, 0x69, 0x6e, 0x6f, + 0x72, 0x2a, 0x51, 0x0a, 0x0d, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x4c, 0x65, 0x76, + 0x65, 0x6c, 0x12, 0x11, 0x0a, 0x0d, 0x53, 0x45, 0x43, 0x55, 0x52, 0x49, 0x54, 0x59, 0x5f, 0x4e, + 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, 0x49, + 0x54, 0x59, 0x5f, 0x4f, 0x4e, 0x4c, 0x59, 0x10, 0x01, 0x12, 0x19, 0x0a, 0x15, 0x49, 0x4e, 0x54, + 0x45, 0x47, 0x52, 0x49, 0x54, 0x59, 0x5f, 0x41, 0x4e, 0x44, 0x5f, 0x50, 0x52, 0x49, 0x56, 0x41, + 0x43, 0x59, 0x10, 0x02, 0x42, 0x78, 0x0a, 0x15, 0x69, 0x6f, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, + 0x61, 0x6c, 0x74, 0x73, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x42, 0x1c, 0x54, + 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, + 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3f, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, + 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, + 0x73, 0x2f, 0x61, 0x6c, 0x74, 0x73, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x5f, 0x67, 0x63, 0x70, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_grpc_gcp_transport_security_common_proto_rawDescOnce sync.Once + file_grpc_gcp_transport_security_common_proto_rawDescData = file_grpc_gcp_transport_security_common_proto_rawDesc +) + +func file_grpc_gcp_transport_security_common_proto_rawDescGZIP() []byte { + file_grpc_gcp_transport_security_common_proto_rawDescOnce.Do(func() { + file_grpc_gcp_transport_security_common_proto_rawDescData = protoimpl.X.CompressGZIP(file_grpc_gcp_transport_security_common_proto_rawDescData) + }) + return file_grpc_gcp_transport_security_common_proto_rawDescData +} + +var file_grpc_gcp_transport_security_common_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_grpc_gcp_transport_security_common_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_grpc_gcp_transport_security_common_proto_goTypes = []interface{}{ + (SecurityLevel)(0), // 0: grpc.gcp.SecurityLevel + (*RpcProtocolVersions)(nil), // 1: grpc.gcp.RpcProtocolVersions + (*RpcProtocolVersions_Version)(nil), // 2: grpc.gcp.RpcProtocolVersions.Version +} +var file_grpc_gcp_transport_security_common_proto_depIdxs = []int32{ + 2, // 0: grpc.gcp.RpcProtocolVersions.max_rpc_version:type_name -> grpc.gcp.RpcProtocolVersions.Version + 2, // 1: grpc.gcp.RpcProtocolVersions.min_rpc_version:type_name -> grpc.gcp.RpcProtocolVersions.Version + 2, // [2:2] is the sub-list for method output_type + 2, // [2:2] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_grpc_gcp_transport_security_common_proto_init() } +func file_grpc_gcp_transport_security_common_proto_init() { + if File_grpc_gcp_transport_security_common_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_grpc_gcp_transport_security_common_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RpcProtocolVersions); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_grpc_gcp_transport_security_common_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RpcProtocolVersions_Version); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_grpc_gcp_transport_security_common_proto_rawDesc, + NumEnums: 1, + NumMessages: 2, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_grpc_gcp_transport_security_common_proto_goTypes, + DependencyIndexes: file_grpc_gcp_transport_security_common_proto_depIdxs, + EnumInfos: file_grpc_gcp_transport_security_common_proto_enumTypes, + MessageInfos: file_grpc_gcp_transport_security_common_proto_msgTypes, + }.Build() + File_grpc_gcp_transport_security_common_proto = out.File + file_grpc_gcp_transport_security_common_proto_rawDesc = nil + file_grpc_gcp_transport_security_common_proto_goTypes = nil + file_grpc_gcp_transport_security_common_proto_depIdxs = nil +} diff --git a/vendor/google.golang.org/grpc/credentials/alts/utils.go b/vendor/google.golang.org/grpc/credentials/alts/utils.go new file mode 100644 index 00000000000..cbfd056cfb1 --- /dev/null +++ b/vendor/google.golang.org/grpc/credentials/alts/utils.go @@ -0,0 +1,70 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package alts + +import ( + "context" + "errors" + "strings" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/peer" + "google.golang.org/grpc/status" +) + +// AuthInfoFromContext extracts the alts.AuthInfo object from the given context, +// if it exists. This API should be used by gRPC server RPC handlers to get +// information about the communicating peer. For client-side, use grpc.Peer() +// CallOption. +func AuthInfoFromContext(ctx context.Context) (AuthInfo, error) { + p, ok := peer.FromContext(ctx) + if !ok { + return nil, errors.New("no Peer found in Context") + } + return AuthInfoFromPeer(p) +} + +// AuthInfoFromPeer extracts the alts.AuthInfo object from the given peer, if it +// exists. This API should be used by gRPC clients after obtaining a peer object +// using the grpc.Peer() CallOption. +func AuthInfoFromPeer(p *peer.Peer) (AuthInfo, error) { + altsAuthInfo, ok := p.AuthInfo.(AuthInfo) + if !ok { + return nil, errors.New("no alts.AuthInfo found in Peer") + } + return altsAuthInfo, nil +} + +// ClientAuthorizationCheck checks whether the client is authorized to access +// the requested resources based on the given expected client service accounts. +// This API should be used by gRPC server RPC handlers. This API should not be +// used by clients. +func ClientAuthorizationCheck(ctx context.Context, expectedServiceAccounts []string) error { + authInfo, err := AuthInfoFromContext(ctx) + if err != nil { + return status.Errorf(codes.PermissionDenied, "The context is not an ALTS-compatible context: %v", err) + } + peer := authInfo.PeerServiceAccount() + for _, sa := range expectedServiceAccounts { + if strings.EqualFold(peer, sa) { + return nil + } + } + return status.Errorf(codes.PermissionDenied, "Client %v is not authorized", peer) +} diff --git a/vendor/google.golang.org/grpc/credentials/credentials.go b/vendor/google.golang.org/grpc/credentials/credentials.go index e69562e7878..5feac3aa0e4 100644 --- a/vendor/google.golang.org/grpc/credentials/credentials.go +++ b/vendor/google.golang.org/grpc/credentials/credentials.go @@ -30,22 +30,22 @@ import ( "github.com/golang/protobuf/proto" "google.golang.org/grpc/attributes" - "google.golang.org/grpc/internal" + icredentials "google.golang.org/grpc/internal/credentials" ) // PerRPCCredentials defines the common interface for the credentials which need to // attach security information to every RPC (e.g., oauth2). type PerRPCCredentials interface { - // GetRequestMetadata gets the current request metadata, refreshing - // tokens if required. This should be called by the transport layer on - // each request, and the data should be populated in headers or other - // context. If a status code is returned, it will be used as the status - // for the RPC. uri is the URI of the entry point for the request. - // When supported by the underlying implementation, ctx can be used for - // timeout and cancellation. Additionally, RequestInfo data will be - // available via ctx to this call. - // TODO(zhaoq): Define the set of the qualified keys instead of leaving - // it as an arbitrary string. + // GetRequestMetadata gets the current request metadata, refreshing tokens + // if required. This should be called by the transport layer on each + // request, and the data should be populated in headers or other + // context. If a status code is returned, it will be used as the status for + // the RPC (restricted to an allowable set of codes as defined by gRFC + // A54). uri is the URI of the entry point for the request. When supported + // by the underlying implementation, ctx can be used for timeout and + // cancellation. Additionally, RequestInfo data will be available via ctx + // to this call. TODO(zhaoq): Define the set of the qualified keys instead + // of leaving it as an arbitrary string. GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) // RequireTransportSecurity indicates whether the credentials requires // transport security. @@ -140,6 +140,11 @@ type TransportCredentials interface { // Additionally, ClientHandshakeInfo data will be available via the context // passed to this call. // + // The second argument to this method is the `:authority` header value used + // while creating new streams on this connection after authentication + // succeeds. Implementations must use this as the server name during the + // authentication handshake. + // // If the returned net.Conn is closed, it MUST close the net.Conn provided. ClientHandshake(context.Context, string, net.Conn) (net.Conn, AuthInfo, error) // ServerHandshake does the authentication handshake for servers. It returns @@ -153,9 +158,13 @@ type TransportCredentials interface { Info() ProtocolInfo // Clone makes a copy of this TransportCredentials. Clone() TransportCredentials - // OverrideServerName overrides the server name used to verify the hostname on the returned certificates from the server. - // gRPC internals also use it to override the virtual hosting name if it is set. - // It must be called before dialing. Currently, this is only used by grpclb. + // OverrideServerName specifies the value used for the following: + // - verifying the hostname on the returned certificates + // - as SNI in the client's handshake to support virtual hosting + // - as the value for `:authority` header at stream creation time + // + // Deprecated: use grpc.WithAuthority instead. Will be supported + // throughout 1.x. OverrideServerName(string) error } @@ -169,8 +178,18 @@ type TransportCredentials interface { // // This API is experimental. type Bundle interface { + // TransportCredentials returns the transport credentials from the Bundle. + // + // Implementations must return non-nil transport credentials. If transport + // security is not needed by the Bundle, implementations may choose to + // return insecure.NewCredentials(). TransportCredentials() TransportCredentials + + // PerRPCCredentials returns the per-RPC credentials from the Bundle. + // + // May be nil if per-RPC credentials are not needed. PerRPCCredentials() PerRPCCredentials + // NewWithMode should make a copy of Bundle, and switch mode. Modifying the // existing Bundle may cause races. // @@ -188,15 +207,12 @@ type RequestInfo struct { AuthInfo AuthInfo } -// requestInfoKey is a struct to be used as the key when attaching a RequestInfo to a context object. -type requestInfoKey struct{} - // RequestInfoFromContext extracts the RequestInfo from the context if it exists. // // This API is experimental. func RequestInfoFromContext(ctx context.Context) (ri RequestInfo, ok bool) { - ri, ok = ctx.Value(requestInfoKey{}).(RequestInfo) - return + ri, ok = icredentials.RequestInfoFromContext(ctx).(RequestInfo) + return ri, ok } // ClientHandshakeInfo holds data to be passed to ClientHandshake. This makes @@ -211,16 +227,12 @@ type ClientHandshakeInfo struct { Attributes *attributes.Attributes } -// clientHandshakeInfoKey is a struct used as the key to store -// ClientHandshakeInfo in a context. -type clientHandshakeInfoKey struct{} - // ClientHandshakeInfoFromContext returns the ClientHandshakeInfo struct stored // in ctx. // // This API is experimental. func ClientHandshakeInfoFromContext(ctx context.Context) ClientHandshakeInfo { - chi, _ := ctx.Value(clientHandshakeInfoKey{}).(ClientHandshakeInfo) + chi, _ := icredentials.ClientHandshakeInfoFromContext(ctx).(ClientHandshakeInfo) return chi } @@ -249,15 +261,6 @@ func CheckSecurityLevel(ai AuthInfo, level SecurityLevel) error { return nil } -func init() { - internal.NewRequestInfoContext = func(ctx context.Context, ri RequestInfo) context.Context { - return context.WithValue(ctx, requestInfoKey{}, ri) - } - internal.NewClientHandshakeInfoContext = func(ctx context.Context, chi ClientHandshakeInfo) context.Context { - return context.WithValue(ctx, clientHandshakeInfoKey{}, chi) - } -} - // ChannelzSecurityInfo defines the interface that security protocols should implement // in order to provide security info to channelz. // diff --git a/vendor/google.golang.org/grpc/credentials/google/google.go b/vendor/google.golang.org/grpc/credentials/google/google.go new file mode 100644 index 00000000000..fbdf7dc2997 --- /dev/null +++ b/vendor/google.golang.org/grpc/credentials/google/google.go @@ -0,0 +1,145 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Package google defines credentials for google cloud services. +package google + +import ( + "context" + "fmt" + "time" + + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/credentials/alts" + "google.golang.org/grpc/credentials/oauth" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/internal" +) + +const tokenRequestTimeout = 30 * time.Second + +var logger = grpclog.Component("credentials") + +// DefaultCredentialsOptions constructs options to build DefaultCredentials. +type DefaultCredentialsOptions struct { + // PerRPCCreds is a per RPC credentials that is passed to a bundle. + PerRPCCreds credentials.PerRPCCredentials +} + +// NewDefaultCredentialsWithOptions returns a credentials bundle that is +// configured to work with google services. +// +// This API is experimental. +func NewDefaultCredentialsWithOptions(opts DefaultCredentialsOptions) credentials.Bundle { + if opts.PerRPCCreds == nil { + ctx, cancel := context.WithTimeout(context.Background(), tokenRequestTimeout) + defer cancel() + var err error + opts.PerRPCCreds, err = newADC(ctx) + if err != nil { + logger.Warningf("NewDefaultCredentialsWithOptions: failed to create application oauth: %v", err) + } + } + c := &creds{opts: opts} + bundle, err := c.NewWithMode(internal.CredsBundleModeFallback) + if err != nil { + logger.Warningf("NewDefaultCredentialsWithOptions: failed to create new creds: %v", err) + } + return bundle +} + +// NewDefaultCredentials returns a credentials bundle that is configured to work +// with google services. +// +// This API is experimental. +func NewDefaultCredentials() credentials.Bundle { + return NewDefaultCredentialsWithOptions(DefaultCredentialsOptions{}) +} + +// NewComputeEngineCredentials returns a credentials bundle that is configured to work +// with google services. This API must only be used when running on GCE. Authentication configured +// by this API represents the GCE VM's default service account. +// +// This API is experimental. +func NewComputeEngineCredentials() credentials.Bundle { + return NewDefaultCredentialsWithOptions(DefaultCredentialsOptions{ + PerRPCCreds: oauth.NewComputeEngine(), + }) +} + +// creds implements credentials.Bundle. +type creds struct { + opts DefaultCredentialsOptions + + // Supported modes are defined in internal/internal.go. + mode string + // The active transport credentials associated with this bundle. + transportCreds credentials.TransportCredentials + // The active per RPC credentials associated with this bundle. + perRPCCreds credentials.PerRPCCredentials +} + +func (c *creds) TransportCredentials() credentials.TransportCredentials { + return c.transportCreds +} + +func (c *creds) PerRPCCredentials() credentials.PerRPCCredentials { + if c == nil { + return nil + } + return c.perRPCCreds +} + +var ( + newTLS = func() credentials.TransportCredentials { + return credentials.NewTLS(nil) + } + newALTS = func() credentials.TransportCredentials { + return alts.NewClientCreds(alts.DefaultClientOptions()) + } + newADC = func(ctx context.Context) (credentials.PerRPCCredentials, error) { + return oauth.NewApplicationDefault(ctx) + } +) + +// NewWithMode should make a copy of Bundle, and switch mode. Modifying the +// existing Bundle may cause races. +func (c *creds) NewWithMode(mode string) (credentials.Bundle, error) { + newCreds := &creds{ + opts: c.opts, + mode: mode, + } + + // Create transport credentials. + switch mode { + case internal.CredsBundleModeFallback: + newCreds.transportCreds = newClusterTransportCreds(newTLS(), newALTS()) + case internal.CredsBundleModeBackendFromBalancer, internal.CredsBundleModeBalancer: + // Only the clients can use google default credentials, so we only need + // to create new ALTS client creds here. + newCreds.transportCreds = newALTS() + default: + return nil, fmt.Errorf("unsupported mode: %v", mode) + } + + if mode == internal.CredsBundleModeFallback || mode == internal.CredsBundleModeBackendFromBalancer { + newCreds.perRPCCreds = newCreds.opts.PerRPCCreds + } + + return newCreds, nil +} diff --git a/vendor/google.golang.org/grpc/credentials/google/xds.go b/vendor/google.golang.org/grpc/credentials/google/xds.go new file mode 100644 index 00000000000..2c5c8b9eee1 --- /dev/null +++ b/vendor/google.golang.org/grpc/credentials/google/xds.go @@ -0,0 +1,128 @@ +/* + * + * Copyright 2021 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package google + +import ( + "context" + "net" + "net/url" + "strings" + + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/internal" +) + +const cfeClusterNamePrefix = "google_cfe_" +const cfeClusterResourceNamePrefix = "/envoy.config.cluster.v3.Cluster/google_cfe_" +const cfeClusterAuthorityName = "traffic-director-c2p.xds.googleapis.com" + +// clusterTransportCreds is a combo of TLS + ALTS. +// +// On the client, ClientHandshake picks TLS or ALTS based on address attributes. +// - if attributes has cluster name +// - if cluster name has prefix "google_cfe_", or +// "xdstp://traffic-director-c2p.xds.googleapis.com/envoy.config.cluster.v3.Cluster/google_cfe_", +// use TLS +// - otherwise, use ALTS +// +// - else, do TLS +// +// On the server, ServerHandshake always does TLS. +type clusterTransportCreds struct { + tls credentials.TransportCredentials + alts credentials.TransportCredentials +} + +func newClusterTransportCreds(tls, alts credentials.TransportCredentials) *clusterTransportCreds { + return &clusterTransportCreds{ + tls: tls, + alts: alts, + } +} + +// clusterName returns the xDS cluster name stored in the attributes in the +// context. +func clusterName(ctx context.Context) string { + chi := credentials.ClientHandshakeInfoFromContext(ctx) + if chi.Attributes == nil { + return "" + } + cluster, _ := internal.GetXDSHandshakeClusterName(chi.Attributes) + return cluster +} + +// isDirectPathCluster returns true if the cluster in the context is a +// directpath cluster, meaning ALTS should be used. +func isDirectPathCluster(ctx context.Context) bool { + cluster := clusterName(ctx) + if cluster == "" { + // No cluster; not xDS; use TLS. + return false + } + if strings.HasPrefix(cluster, cfeClusterNamePrefix) { + // xDS cluster prefixed by "google_cfe_"; use TLS. + return false + } + if !strings.HasPrefix(cluster, "xdstp:") { + // Other xDS cluster name; use ALTS. + return true + } + u, err := url.Parse(cluster) + if err != nil { + // Shouldn't happen, but assume ALTS. + return true + } + // If authority AND path match our CFE checks, use TLS; otherwise use ALTS. + return u.Host != cfeClusterAuthorityName || !strings.HasPrefix(u.Path, cfeClusterResourceNamePrefix) +} + +func (c *clusterTransportCreds) ClientHandshake(ctx context.Context, authority string, rawConn net.Conn) (net.Conn, credentials.AuthInfo, error) { + if isDirectPathCluster(ctx) { + // If attributes have cluster name, and cluster name is not cfe, it's a + // backend address, use ALTS. + return c.alts.ClientHandshake(ctx, authority, rawConn) + } + return c.tls.ClientHandshake(ctx, authority, rawConn) +} + +func (c *clusterTransportCreds) ServerHandshake(conn net.Conn) (net.Conn, credentials.AuthInfo, error) { + return c.tls.ServerHandshake(conn) +} + +func (c *clusterTransportCreds) Info() credentials.ProtocolInfo { + // TODO: this always returns tls.Info now, because we don't have a cluster + // name to check when this method is called. This method doesn't affect + // anything important now. We may want to revisit this if it becomes more + // important later. + return c.tls.Info() +} + +func (c *clusterTransportCreds) Clone() credentials.TransportCredentials { + return &clusterTransportCreds{ + tls: c.tls.Clone(), + alts: c.alts.Clone(), + } +} + +func (c *clusterTransportCreds) OverrideServerName(s string) error { + if err := c.tls.OverrideServerName(s); err != nil { + return err + } + return c.alts.OverrideServerName(s) +} diff --git a/vendor/google.golang.org/grpc/credentials/insecure/insecure.go b/vendor/google.golang.org/grpc/credentials/insecure/insecure.go new file mode 100644 index 00000000000..82bee1443bf --- /dev/null +++ b/vendor/google.golang.org/grpc/credentials/insecure/insecure.go @@ -0,0 +1,98 @@ +/* + * + * Copyright 2020 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Package insecure provides an implementation of the +// credentials.TransportCredentials interface which disables transport security. +package insecure + +import ( + "context" + "net" + + "google.golang.org/grpc/credentials" +) + +// NewCredentials returns a credentials which disables transport security. +// +// Note that using this credentials with per-RPC credentials which require +// transport security is incompatible and will cause grpc.Dial() to fail. +func NewCredentials() credentials.TransportCredentials { + return insecureTC{} +} + +// insecureTC implements the insecure transport credentials. The handshake +// methods simply return the passed in net.Conn and set the security level to +// NoSecurity. +type insecureTC struct{} + +func (insecureTC) ClientHandshake(ctx context.Context, _ string, conn net.Conn) (net.Conn, credentials.AuthInfo, error) { + return conn, info{credentials.CommonAuthInfo{SecurityLevel: credentials.NoSecurity}}, nil +} + +func (insecureTC) ServerHandshake(conn net.Conn) (net.Conn, credentials.AuthInfo, error) { + return conn, info{credentials.CommonAuthInfo{SecurityLevel: credentials.NoSecurity}}, nil +} + +func (insecureTC) Info() credentials.ProtocolInfo { + return credentials.ProtocolInfo{SecurityProtocol: "insecure"} +} + +func (insecureTC) Clone() credentials.TransportCredentials { + return insecureTC{} +} + +func (insecureTC) OverrideServerName(string) error { + return nil +} + +// info contains the auth information for an insecure connection. +// It implements the AuthInfo interface. +type info struct { + credentials.CommonAuthInfo +} + +// AuthType returns the type of info as a string. +func (info) AuthType() string { + return "insecure" +} + +// insecureBundle implements an insecure bundle. +// An insecure bundle provides a thin wrapper around insecureTC to support +// the credentials.Bundle interface. +type insecureBundle struct{} + +// NewBundle returns a bundle with disabled transport security and no per rpc credential. +func NewBundle() credentials.Bundle { + return insecureBundle{} +} + +// NewWithMode returns a new insecure Bundle. The mode is ignored. +func (insecureBundle) NewWithMode(string) (credentials.Bundle, error) { + return insecureBundle{}, nil +} + +// PerRPCCredentials returns an nil implementation as insecure +// bundle does not support a per rpc credential. +func (insecureBundle) PerRPCCredentials() credentials.PerRPCCredentials { + return nil +} + +// TransportCredentials returns the underlying insecure transport credential. +func (insecureBundle) TransportCredentials() credentials.TransportCredentials { + return NewCredentials() +} diff --git a/vendor/google.golang.org/grpc/credentials/oauth/oauth.go b/vendor/google.golang.org/grpc/credentials/oauth/oauth.go new file mode 100644 index 00000000000..d475cbc0894 --- /dev/null +++ b/vendor/google.golang.org/grpc/credentials/oauth/oauth.go @@ -0,0 +1,244 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Package oauth implements gRPC credentials using OAuth. +package oauth + +import ( + "context" + "fmt" + "net/url" + "os" + "sync" + + "golang.org/x/oauth2" + "golang.org/x/oauth2/google" + "golang.org/x/oauth2/jwt" + "google.golang.org/grpc/credentials" +) + +// TokenSource supplies PerRPCCredentials from an oauth2.TokenSource. +type TokenSource struct { + oauth2.TokenSource +} + +// GetRequestMetadata gets the request metadata as a map from a TokenSource. +func (ts TokenSource) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) { + token, err := ts.Token() + if err != nil { + return nil, err + } + ri, _ := credentials.RequestInfoFromContext(ctx) + if err = credentials.CheckSecurityLevel(ri.AuthInfo, credentials.PrivacyAndIntegrity); err != nil { + return nil, fmt.Errorf("unable to transfer TokenSource PerRPCCredentials: %v", err) + } + return map[string]string{ + "authorization": token.Type() + " " + token.AccessToken, + }, nil +} + +// RequireTransportSecurity indicates whether the credentials requires transport security. +func (ts TokenSource) RequireTransportSecurity() bool { + return true +} + +// removeServiceNameFromJWTURI removes RPC service name from URI. +func removeServiceNameFromJWTURI(uri string) (string, error) { + parsed, err := url.Parse(uri) + if err != nil { + return "", err + } + parsed.Path = "/" + return parsed.String(), nil +} + +type jwtAccess struct { + jsonKey []byte +} + +// NewJWTAccessFromFile creates PerRPCCredentials from the given keyFile. +func NewJWTAccessFromFile(keyFile string) (credentials.PerRPCCredentials, error) { + jsonKey, err := os.ReadFile(keyFile) + if err != nil { + return nil, fmt.Errorf("credentials: failed to read the service account key file: %v", err) + } + return NewJWTAccessFromKey(jsonKey) +} + +// NewJWTAccessFromKey creates PerRPCCredentials from the given jsonKey. +func NewJWTAccessFromKey(jsonKey []byte) (credentials.PerRPCCredentials, error) { + return jwtAccess{jsonKey}, nil +} + +func (j jwtAccess) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) { + // Remove RPC service name from URI that will be used as audience + // in a self-signed JWT token. It follows https://google.aip.dev/auth/4111. + aud, err := removeServiceNameFromJWTURI(uri[0]) + if err != nil { + return nil, err + } + // TODO: the returned TokenSource is reusable. Store it in a sync.Map, with + // uri as the key, to avoid recreating for every RPC. + ts, err := google.JWTAccessTokenSourceFromJSON(j.jsonKey, aud) + if err != nil { + return nil, err + } + token, err := ts.Token() + if err != nil { + return nil, err + } + ri, _ := credentials.RequestInfoFromContext(ctx) + if err = credentials.CheckSecurityLevel(ri.AuthInfo, credentials.PrivacyAndIntegrity); err != nil { + return nil, fmt.Errorf("unable to transfer jwtAccess PerRPCCredentials: %v", err) + } + return map[string]string{ + "authorization": token.Type() + " " + token.AccessToken, + }, nil +} + +func (j jwtAccess) RequireTransportSecurity() bool { + return true +} + +// oauthAccess supplies PerRPCCredentials from a given token. +type oauthAccess struct { + token oauth2.Token +} + +// NewOauthAccess constructs the PerRPCCredentials using a given token. +// +// Deprecated: use oauth.TokenSource instead. +func NewOauthAccess(token *oauth2.Token) credentials.PerRPCCredentials { + return oauthAccess{token: *token} +} + +func (oa oauthAccess) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) { + ri, _ := credentials.RequestInfoFromContext(ctx) + if err := credentials.CheckSecurityLevel(ri.AuthInfo, credentials.PrivacyAndIntegrity); err != nil { + return nil, fmt.Errorf("unable to transfer oauthAccess PerRPCCredentials: %v", err) + } + return map[string]string{ + "authorization": oa.token.Type() + " " + oa.token.AccessToken, + }, nil +} + +func (oa oauthAccess) RequireTransportSecurity() bool { + return true +} + +// NewComputeEngine constructs the PerRPCCredentials that fetches access tokens from +// Google Compute Engine (GCE)'s metadata server. It is only valid to use this +// if your program is running on a GCE instance. +// TODO(dsymonds): Deprecate and remove this. +func NewComputeEngine() credentials.PerRPCCredentials { + return TokenSource{google.ComputeTokenSource("")} +} + +// serviceAccount represents PerRPCCredentials via JWT signing key. +type serviceAccount struct { + mu sync.Mutex + config *jwt.Config + t *oauth2.Token +} + +func (s *serviceAccount) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) { + s.mu.Lock() + defer s.mu.Unlock() + if !s.t.Valid() { + var err error + s.t, err = s.config.TokenSource(ctx).Token() + if err != nil { + return nil, err + } + } + ri, _ := credentials.RequestInfoFromContext(ctx) + if err := credentials.CheckSecurityLevel(ri.AuthInfo, credentials.PrivacyAndIntegrity); err != nil { + return nil, fmt.Errorf("unable to transfer serviceAccount PerRPCCredentials: %v", err) + } + return map[string]string{ + "authorization": s.t.Type() + " " + s.t.AccessToken, + }, nil +} + +func (s *serviceAccount) RequireTransportSecurity() bool { + return true +} + +// NewServiceAccountFromKey constructs the PerRPCCredentials using the JSON key slice +// from a Google Developers service account. +func NewServiceAccountFromKey(jsonKey []byte, scope ...string) (credentials.PerRPCCredentials, error) { + config, err := google.JWTConfigFromJSON(jsonKey, scope...) + if err != nil { + return nil, err + } + return &serviceAccount{config: config}, nil +} + +// NewServiceAccountFromFile constructs the PerRPCCredentials using the JSON key file +// of a Google Developers service account. +func NewServiceAccountFromFile(keyFile string, scope ...string) (credentials.PerRPCCredentials, error) { + jsonKey, err := os.ReadFile(keyFile) + if err != nil { + return nil, fmt.Errorf("credentials: failed to read the service account key file: %v", err) + } + return NewServiceAccountFromKey(jsonKey, scope...) +} + +// NewApplicationDefault returns "Application Default Credentials". For more +// detail, see https://developers.google.com/accounts/docs/application-default-credentials. +func NewApplicationDefault(ctx context.Context, scope ...string) (credentials.PerRPCCredentials, error) { + creds, err := google.FindDefaultCredentials(ctx, scope...) + if err != nil { + return nil, err + } + + // If JSON is nil, the authentication is provided by the environment and not + // with a credentials file, e.g. when code is running on Google Cloud + // Platform. Use the returned token source. + if creds.JSON == nil { + return TokenSource{creds.TokenSource}, nil + } + + // If auth is provided by env variable or creds file, the behavior will be + // different based on whether scope is set. Because the returned + // creds.TokenSource does oauth with jwt by default, and it requires scope. + // We can only use it if scope is not empty, otherwise it will fail with + // missing scope error. + // + // If scope is set, use it, it should just work. + // + // If scope is not set, we try to use jwt directly without oauth (this only + // works if it's a service account). + + if len(scope) != 0 { + return TokenSource{creds.TokenSource}, nil + } + + // Try to convert JSON to a jwt config without setting the optional scope + // parameter to check if it's a service account (the function errors if it's + // not). This is necessary because the returned config doesn't show the type + // of the account. + if _, err := google.JWTConfigFromJSON(creds.JSON); err != nil { + // If this fails, it's not a service account, return the original + // TokenSource from above. + return TokenSource{creds.TokenSource}, nil + } + + // If it's a service account, create a JWT only access with the key. + return NewJWTAccessFromKey(creds.JSON) +} diff --git a/vendor/google.golang.org/grpc/credentials/tls.go b/vendor/google.golang.org/grpc/credentials/tls.go index 8ee7124f226..877b7cd21af 100644 --- a/vendor/google.golang.org/grpc/credentials/tls.go +++ b/vendor/google.golang.org/grpc/credentials/tls.go @@ -23,9 +23,9 @@ import ( "crypto/tls" "crypto/x509" "fmt" - "io/ioutil" "net" "net/url" + "os" credinternal "google.golang.org/grpc/internal/credentials" ) @@ -166,7 +166,7 @@ func NewClientTLSFromCert(cp *x509.CertPool, serverNameOverride string) Transpor // it will override the virtual host name of authority (e.g. :authority header // field) in requests. func NewClientTLSFromFile(certFile, serverNameOverride string) (TransportCredentials, error) { - b, err := ioutil.ReadFile(certFile) + b, err := os.ReadFile(certFile) if err != nil { return nil, err } @@ -195,7 +195,7 @@ func NewServerTLSFromFile(certFile, keyFile string) (TransportCredentials, error // TLSChannelzSecurityValue defines the struct that TLS protocol should return // from GetSecurityValue(), containing security info like cipher and certificate used. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. @@ -230,4 +230,7 @@ var cipherSuiteLookup = map[uint16]string{ tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305: "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305: "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", + tls.TLS_AES_128_GCM_SHA256: "TLS_AES_128_GCM_SHA256", + tls.TLS_AES_256_GCM_SHA384: "TLS_AES_256_GCM_SHA384", + tls.TLS_CHACHA20_POLY1305_SHA256: "TLS_CHACHA20_POLY1305_SHA256", } diff --git a/vendor/google.golang.org/grpc/dialoptions.go b/vendor/google.golang.org/grpc/dialoptions.go index e7f86e6d7c8..15a3d5102a9 100644 --- a/vendor/google.golang.org/grpc/dialoptions.go +++ b/vendor/google.golang.org/grpc/dialoptions.go @@ -20,22 +20,34 @@ package grpc import ( "context" - "fmt" "net" "time" "google.golang.org/grpc/backoff" - "google.golang.org/grpc/balancer" + "google.golang.org/grpc/channelz" "google.golang.org/grpc/credentials" + "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/internal" internalbackoff "google.golang.org/grpc/internal/backoff" - "google.golang.org/grpc/internal/envconfig" + "google.golang.org/grpc/internal/binarylog" "google.golang.org/grpc/internal/transport" "google.golang.org/grpc/keepalive" "google.golang.org/grpc/resolver" "google.golang.org/grpc/stats" ) +func init() { + internal.AddGlobalDialOptions = func(opt ...DialOption) { + globalDialOptions = append(globalDialOptions, opt...) + } + internal.ClearGlobalDialOptions = func() { + globalDialOptions = nil + } + internal.WithBinaryLogger = withBinaryLogger + internal.JoinDialOptions = newJoinDialOption + internal.DisableGlobalDialOptions = newDisableGlobalDialOptions +} + // dialOptions configure a Dial call. dialOptions are set by the DialOption // values passed to Dial. type dialOptions struct { @@ -45,20 +57,18 @@ type dialOptions struct { chainUnaryInts []UnaryClientInterceptor chainStreamInts []StreamClientInterceptor - cp Compressor - dc Decompressor - bs internalbackoff.Strategy - block bool - returnLastError bool - insecure bool - timeout time.Duration - scChan <-chan ServiceConfig - authority string - copts transport.ConnectOptions - callOptions []CallOption - // This is used by WithBalancerName dial option. - balancerBuilder balancer.Builder - channelzParentID int64 + cp Compressor + dc Decompressor + bs internalbackoff.Strategy + block bool + returnLastError bool + timeout time.Duration + scChan <-chan ServiceConfig + authority string + binaryLogger binarylog.Logger + copts transport.ConnectOptions + callOptions []CallOption + channelzParentID *channelz.Identifier disableServiceConfig bool disableRetry bool disableHealthCheck bool @@ -66,11 +76,8 @@ type dialOptions struct { minConnectTimeout func() time.Duration defaultServiceConfig *ServiceConfig // defaultServiceConfig is parsed from defaultServiceConfigRawJSON. defaultServiceConfigRawJSON *string - // This is used by ccResolverWrapper to backoff between successive calls to - // resolver.ResolveNow(). The user will have no need to configure this, but - // we need to be able to configure this in tests. - resolveNowBackoff func(int) time.Duration - resolvers []resolver.Builder + resolvers []resolver.Builder + idleTimeout time.Duration } // DialOption configures how we set up the connection. @@ -78,10 +85,12 @@ type DialOption interface { apply(*dialOptions) } +var globalDialOptions []DialOption + // EmptyDialOption does not alter the dial configuration. It can be embedded in // another structure to build custom dial options. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. @@ -89,6 +98,16 @@ type EmptyDialOption struct{} func (EmptyDialOption) apply(*dialOptions) {} +type disableGlobalDialOptions struct{} + +func (disableGlobalDialOptions) apply(*dialOptions) {} + +// newDisableGlobalDialOptions returns a DialOption that prevents the ClientConn +// from applying the global DialOptions (set via AddGlobalDialOptions). +func newDisableGlobalDialOptions() DialOption { + return &disableGlobalDialOptions{} +} + // funcDialOption wraps a function that modifies dialOptions into an // implementation of the DialOption interface. type funcDialOption struct { @@ -105,13 +124,28 @@ func newFuncDialOption(f func(*dialOptions)) *funcDialOption { } } +type joinDialOption struct { + opts []DialOption +} + +func (jdo *joinDialOption) apply(do *dialOptions) { + for _, opt := range jdo.opts { + opt.apply(do) + } +} + +func newJoinDialOption(opts ...DialOption) DialOption { + return &joinDialOption{opts: opts} +} + // WithWriteBufferSize determines how much data can be batched before doing a // write on the wire. The corresponding memory allocation for this buffer will // be twice the size to keep syscalls low. The default value for this buffer is // 32KB. // -// Zero will disable the write buffer such that each write will be on underlying -// connection. Note: A Send call may not directly translate to a write. +// Zero or negative values will disable the write buffer such that each write +// will be on underlying connection. Note: A Send call may not directly +// translate to a write. func WithWriteBufferSize(s int) DialOption { return newFuncDialOption(func(o *dialOptions) { o.copts.WriteBufferSize = s @@ -121,8 +155,9 @@ func WithWriteBufferSize(s int) DialOption { // WithReadBufferSize lets you set the size of read buffer, this determines how // much data can be read at most for each read syscall. // -// The default value for this buffer is 32KB. Zero will disable read buffer for -// a connection so data framer can access the underlying conn directly. +// The default value for this buffer is 32KB. Zero or negative values will +// disable read buffer for a connection so data framer can access the +// underlying conn directly. func WithReadBufferSize(s int) DialOption { return newFuncDialOption(func(o *dialOptions) { o.copts.ReadBufferSize = s @@ -200,25 +235,6 @@ func WithDecompressor(dc Decompressor) DialOption { }) } -// WithBalancerName sets the balancer that the ClientConn will be initialized -// with. Balancer registered with balancerName will be used. This function -// panics if no balancer was registered by balancerName. -// -// The balancer cannot be overridden by balancer option specified by service -// config. -// -// Deprecated: use WithDefaultServiceConfig and WithDisableServiceConfig -// instead. Will be removed in a future 1.x release. -func WithBalancerName(balancerName string) DialOption { - builder := balancer.Get(balancerName) - if builder == nil { - panic(fmt.Sprintf("grpc.WithBalancerName: no balancer is registered for name %v", balancerName)) - } - return newFuncDialOption(func(o *dialOptions) { - o.balancerBuilder = builder - }) -} - // WithServiceConfig returns a DialOption which has a channel to read the // service configuration. // @@ -232,18 +248,14 @@ func WithServiceConfig(c <-chan ServiceConfig) DialOption { }) } -// WithConnectParams configures the dialer to use the provided ConnectParams. +// WithConnectParams configures the ClientConn to use the provided ConnectParams +// for creating and maintaining connections to servers. // // The backoff configuration specified as part of the ConnectParams overrides // all defaults specified in // https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md. Consider // using the backoff.DefaultConfig as a base, in cases where you want to // override only a subset of the backoff configuration. -// -// Experimental -// -// Notice: This API is EXPERIMENTAL and may be changed or removed in a -// later release. func WithConnectParams(p ConnectParams) DialOption { return newFuncDialOption(func(o *dialOptions) { o.bs = internalbackoff.Exponential{Config: p.Backoff} @@ -281,9 +293,12 @@ func withBackoff(bs internalbackoff.Strategy) DialOption { }) } -// WithBlock returns a DialOption which makes caller of Dial blocks until the +// WithBlock returns a DialOption which makes callers of Dial block until the // underlying connection is up. Without this, Dial returns immediately and // connecting the server happens in background. +// +// Use of this feature is not recommended. For more information, please see: +// https://github.com/grpc/grpc-go/blob/master/Documentation/anti-patterns.md func WithBlock() DialOption { return newFuncDialOption(func(o *dialOptions) { o.block = true @@ -295,7 +310,10 @@ func WithBlock() DialOption { // the context.DeadlineExceeded error. // Implies WithBlock() // -// Experimental +// Use of this feature is not recommended. For more information, please see: +// https://github.com/grpc/grpc-go/blob/master/Documentation/anti-patterns.md +// +// # Experimental // // Notice: This API is EXPERIMENTAL and may be changed or removed in a // later release. @@ -307,18 +325,24 @@ func WithReturnConnectionError() DialOption { } // WithInsecure returns a DialOption which disables transport security for this -// ClientConn. Note that transport security is required unless WithInsecure is -// set. +// ClientConn. Under the hood, it uses insecure.NewCredentials(). +// +// Note that using this DialOption with per-RPC credentials (through +// WithCredentialsBundle or WithPerRPCCredentials) which require transport +// security is incompatible and will cause grpc.Dial() to fail. +// +// Deprecated: use WithTransportCredentials and insecure.NewCredentials() +// instead. Will be supported throughout 1.x. func WithInsecure() DialOption { return newFuncDialOption(func(o *dialOptions) { - o.insecure = true + o.copts.TransportCredentials = insecure.NewCredentials() }) } // WithNoProxy returns a DialOption which disables the use of proxies for this // ClientConn. This is ignored if WithDialer or WithContextDialer are used. // -// Experimental +// # Experimental // // Notice: This API is EXPERIMENTAL and may be changed or removed in a // later release. @@ -349,7 +373,7 @@ func WithPerRPCCredentials(creds credentials.PerRPCCredentials) DialOption { // the ClientConn.WithCreds. This should not be used together with // WithTransportCredentials. // -// Experimental +// # Experimental // // Notice: This API is EXPERIMENTAL and may be changed or removed in a // later release. @@ -405,7 +429,21 @@ func WithDialer(f func(string, time.Duration) (net.Conn, error)) DialOption { // all the RPCs and underlying network connections in this ClientConn. func WithStatsHandler(h stats.Handler) DialOption { return newFuncDialOption(func(o *dialOptions) { - o.copts.StatsHandler = h + if h == nil { + logger.Error("ignoring nil parameter in grpc.WithStatsHandler ClientOption") + // Do not allow a nil stats handler, which would otherwise cause + // panics. + return + } + o.copts.StatsHandlers = append(o.copts.StatsHandlers, h) + }) +} + +// withBinaryLogger returns a DialOption that specifies the binary logger for +// this ClientConn. +func withBinaryLogger(bl binarylog.Logger) DialOption { + return newFuncDialOption(func(o *dialOptions) { + o.binaryLogger = bl }) } @@ -417,7 +455,10 @@ func WithStatsHandler(h stats.Handler) DialOption { // FailOnNonTempDialError only affects the initial dial, and does not do // anything useful unless you are also using WithBlock(). // -// Experimental +// Use of this feature is not recommended. For more information, please see: +// https://github.com/grpc/grpc-go/blob/master/Documentation/anti-patterns.md +// +// # Experimental // // Notice: This API is EXPERIMENTAL and may be changed or removed in a // later release. @@ -486,8 +527,7 @@ func WithChainStreamInterceptor(interceptors ...StreamClientInterceptor) DialOpt } // WithAuthority returns a DialOption that specifies the value to be used as the -// :authority pseudo-header. This value only works with WithInsecure and has no -// effect if TransportCredentials are present. +// :authority pseudo-header and as the server name in authentication handshake. func WithAuthority(a string) DialOption { return newFuncDialOption(func(o *dialOptions) { o.authority = a @@ -498,11 +538,11 @@ func WithAuthority(a string) DialOption { // current ClientConn's parent. This function is used in nested channel creation // (e.g. grpclb dial). // -// Experimental +// # Experimental // // Notice: This API is EXPERIMENTAL and may be changed or removed in a // later release. -func WithChannelzParentID(id int64) DialOption { +func WithChannelzParentID(id *channelz.Identifier) DialOption { return newFuncDialOption(func(o *dialOptions) { o.channelzParentID = id }) @@ -523,14 +563,16 @@ func WithDisableServiceConfig() DialOption { // WithDefaultServiceConfig returns a DialOption that configures the default // service config, which will be used in cases where: // -// 1. WithDisableServiceConfig is also used. -// 2. Resolver does not return a service config or if the resolver returns an -// invalid service config. +// 1. WithDisableServiceConfig is also used, or // -// Experimental +// 2. The name resolver does not provide a service config or provides an +// invalid service config. // -// Notice: This API is EXPERIMENTAL and may be changed or removed in a -// later release. +// The parameter s is the JSON representation of the default service config. +// For more information about service configs, see: +// https://github.com/grpc/grpc/blob/master/doc/service_config.md +// For a simple example of usage, see: +// examples/features/load_balancing/client/main.go func WithDefaultServiceConfig(s string) DialOption { return newFuncDialOption(func(o *dialOptions) { o.defaultServiceConfigRawJSON = &s @@ -541,15 +583,6 @@ func WithDefaultServiceConfig(s string) DialOption { // service config enables them. This does not impact transparent retries, which // will happen automatically if no data is written to the wire or if the RPC is // unprocessed by the remote server. -// -// Retry support is currently disabled by default, but will be enabled by -// default in the future. Until then, it may be enabled by setting the -// environment variable "GRPC_GO_RETRY" to "on". -// -// Experimental -// -// Notice: This API is EXPERIMENTAL and may be changed or removed in a -// later release. func WithDisableRetry() DialOption { return newFuncDialOption(func(o *dialOptions) { o.disableRetry = true @@ -567,7 +600,7 @@ func WithMaxHeaderListSize(s uint32) DialOption { // WithDisableHealthCheck disables the LB channel health checking for all // SubConns of this ClientConn. // -// Experimental +// # Experimental // // Notice: This API is EXPERIMENTAL and may be changed or removed in a // later release. @@ -589,14 +622,12 @@ func withHealthCheckFunc(f internal.HealthChecker) DialOption { func defaultDialOptions() dialOptions { return dialOptions{ - disableRetry: !envconfig.Retry, healthCheckFunc: internal.HealthCheckFunc, copts: transport.ConnectOptions{ WriteBufferSize: defaultWriteBufSize, ReadBufferSize: defaultReadBufSize, UseProxy: true, }, - resolveNowBackoff: internalbackoff.DefaultExponential.Backoff, } } @@ -611,22 +642,12 @@ func withMinConnectDeadline(f func() time.Duration) DialOption { }) } -// withResolveNowBackoff specifies the function that clientconn uses to backoff -// between successive calls to resolver.ResolveNow(). -// -// For testing purpose only. -func withResolveNowBackoff(f func(int) time.Duration) DialOption { - return newFuncDialOption(func(o *dialOptions) { - o.resolveNowBackoff = f - }) -} - // WithResolvers allows a list of resolver implementations to be registered // locally with the ClientConn without needing to be globally registered via // resolver.Register. They will be matched against the scheme used for the // current Dial only, and will take precedence over the global registry. // -// Experimental +// # Experimental // // Notice: This API is EXPERIMENTAL and may be changed or removed in a // later release. @@ -635,3 +656,23 @@ func WithResolvers(rs ...resolver.Builder) DialOption { o.resolvers = append(o.resolvers, rs...) }) } + +// WithIdleTimeout returns a DialOption that configures an idle timeout for the +// channel. If the channel is idle for the configured timeout, i.e there are no +// ongoing RPCs and no new RPCs are initiated, the channel will enter idle mode +// and as a result the name resolver and load balancer will be shut down. The +// channel will exit idle mode when the Connect() method is called or when an +// RPC is initiated. +// +// By default this feature is disabled, which can also be explicitly configured +// by passing zero to this function. +// +// # Experimental +// +// Notice: This API is EXPERIMENTAL and may be changed or removed in a +// later release. +func WithIdleTimeout(d time.Duration) DialOption { + return newFuncDialOption(func(o *dialOptions) { + o.idleTimeout = d + }) +} diff --git a/vendor/google.golang.org/grpc/encoding/encoding.go b/vendor/google.golang.org/grpc/encoding/encoding.go index 6d84f74c7d0..07a5861352a 100644 --- a/vendor/google.golang.org/grpc/encoding/encoding.go +++ b/vendor/google.golang.org/grpc/encoding/encoding.go @@ -19,7 +19,7 @@ // Package encoding defines the interface for the compressor and codec, and // functions to register and retrieve compressors and codecs. // -// Experimental +// # Experimental // // Notice: This package is EXPERIMENTAL and may be changed or removed in a // later release. @@ -28,6 +28,8 @@ package encoding import ( "io" "strings" + + "google.golang.org/grpc/internal/grpcutil" ) // Identity specifies the optional encoding for uncompressed streams. @@ -73,6 +75,9 @@ var registeredCompressor = make(map[string]Compressor) // registered with the same name, the one registered last will take effect. func RegisterCompressor(c Compressor) { registeredCompressor[c.Name()] = c + if !grpcutil.IsCompressorNameRegistered(c.Name()) { + grpcutil.RegisteredCompressorNames = append(grpcutil.RegisteredCompressorNames, c.Name()) + } } // GetCompressor returns Compressor for the given compressor name. @@ -108,7 +113,7 @@ var registeredCodecs = make(map[string]Codec) // more details. // // NOTE: this function must only be called during initialization time (i.e. in -// an init() function), and is not thread-safe. If multiple Compressors are +// an init() function), and is not thread-safe. If multiple Codecs are // registered with the same name, the one registered last will take effect. func RegisterCodec(codec Codec) { if codec == nil { diff --git a/vendor/google.golang.org/grpc/grpclog/loggerv2.go b/vendor/google.golang.org/grpc/grpclog/loggerv2.go index 4ee33171e00..5de66e40d36 100644 --- a/vendor/google.golang.org/grpc/grpclog/loggerv2.go +++ b/vendor/google.golang.org/grpc/grpclog/loggerv2.go @@ -19,11 +19,13 @@ package grpclog import ( + "encoding/json" + "fmt" "io" - "io/ioutil" "log" "os" "strconv" + "strings" "google.golang.org/grpc/internal/grpclog" ) @@ -95,8 +97,9 @@ var severityName = []string{ // loggerT is the default logger used by grpclog. type loggerT struct { - m []*log.Logger - v int + m []*log.Logger + v int + jsonFormat bool } // NewLoggerV2 creates a loggerV2 with the provided writers. @@ -105,27 +108,40 @@ type loggerT struct { // Warning logs will be written to warningW and infoW. // Info logs will be written to infoW. func NewLoggerV2(infoW, warningW, errorW io.Writer) LoggerV2 { - return NewLoggerV2WithVerbosity(infoW, warningW, errorW, 0) + return newLoggerV2WithConfig(infoW, warningW, errorW, loggerV2Config{}) } // NewLoggerV2WithVerbosity creates a loggerV2 with the provided writers and // verbosity level. func NewLoggerV2WithVerbosity(infoW, warningW, errorW io.Writer, v int) LoggerV2 { + return newLoggerV2WithConfig(infoW, warningW, errorW, loggerV2Config{verbose: v}) +} + +type loggerV2Config struct { + verbose int + jsonFormat bool +} + +func newLoggerV2WithConfig(infoW, warningW, errorW io.Writer, c loggerV2Config) LoggerV2 { var m []*log.Logger - m = append(m, log.New(infoW, severityName[infoLog]+": ", log.LstdFlags)) - m = append(m, log.New(io.MultiWriter(infoW, warningW), severityName[warningLog]+": ", log.LstdFlags)) + flag := log.LstdFlags + if c.jsonFormat { + flag = 0 + } + m = append(m, log.New(infoW, "", flag)) + m = append(m, log.New(io.MultiWriter(infoW, warningW), "", flag)) ew := io.MultiWriter(infoW, warningW, errorW) // ew will be used for error and fatal. - m = append(m, log.New(ew, severityName[errorLog]+": ", log.LstdFlags)) - m = append(m, log.New(ew, severityName[fatalLog]+": ", log.LstdFlags)) - return &loggerT{m: m, v: v} + m = append(m, log.New(ew, "", flag)) + m = append(m, log.New(ew, "", flag)) + return &loggerT{m: m, v: c.verbose, jsonFormat: c.jsonFormat} } // newLoggerV2 creates a loggerV2 to be used as default logger. // All logs are written to stderr. func newLoggerV2() LoggerV2 { - errorW := ioutil.Discard - warningW := ioutil.Discard - infoW := ioutil.Discard + errorW := io.Discard + warningW := io.Discard + infoW := io.Discard logLevel := os.Getenv("GRPC_GO_LOG_SEVERITY_LEVEL") switch logLevel { @@ -142,58 +158,79 @@ func newLoggerV2() LoggerV2 { if vl, err := strconv.Atoi(vLevel); err == nil { v = vl } - return NewLoggerV2WithVerbosity(infoW, warningW, errorW, v) + + jsonFormat := strings.EqualFold(os.Getenv("GRPC_GO_LOG_FORMATTER"), "json") + + return newLoggerV2WithConfig(infoW, warningW, errorW, loggerV2Config{ + verbose: v, + jsonFormat: jsonFormat, + }) +} + +func (g *loggerT) output(severity int, s string) { + sevStr := severityName[severity] + if !g.jsonFormat { + g.m[severity].Output(2, fmt.Sprintf("%v: %v", sevStr, s)) + return + } + // TODO: we can also include the logging component, but that needs more + // (API) changes. + b, _ := json.Marshal(map[string]string{ + "severity": sevStr, + "message": s, + }) + g.m[severity].Output(2, string(b)) } func (g *loggerT) Info(args ...interface{}) { - g.m[infoLog].Print(args...) + g.output(infoLog, fmt.Sprint(args...)) } func (g *loggerT) Infoln(args ...interface{}) { - g.m[infoLog].Println(args...) + g.output(infoLog, fmt.Sprintln(args...)) } func (g *loggerT) Infof(format string, args ...interface{}) { - g.m[infoLog].Printf(format, args...) + g.output(infoLog, fmt.Sprintf(format, args...)) } func (g *loggerT) Warning(args ...interface{}) { - g.m[warningLog].Print(args...) + g.output(warningLog, fmt.Sprint(args...)) } func (g *loggerT) Warningln(args ...interface{}) { - g.m[warningLog].Println(args...) + g.output(warningLog, fmt.Sprintln(args...)) } func (g *loggerT) Warningf(format string, args ...interface{}) { - g.m[warningLog].Printf(format, args...) + g.output(warningLog, fmt.Sprintf(format, args...)) } func (g *loggerT) Error(args ...interface{}) { - g.m[errorLog].Print(args...) + g.output(errorLog, fmt.Sprint(args...)) } func (g *loggerT) Errorln(args ...interface{}) { - g.m[errorLog].Println(args...) + g.output(errorLog, fmt.Sprintln(args...)) } func (g *loggerT) Errorf(format string, args ...interface{}) { - g.m[errorLog].Printf(format, args...) + g.output(errorLog, fmt.Sprintf(format, args...)) } func (g *loggerT) Fatal(args ...interface{}) { - g.m[fatalLog].Fatal(args...) - // No need to call os.Exit() again because log.Logger.Fatal() calls os.Exit(). + g.output(fatalLog, fmt.Sprint(args...)) + os.Exit(1) } func (g *loggerT) Fatalln(args ...interface{}) { - g.m[fatalLog].Fatalln(args...) - // No need to call os.Exit() again because log.Logger.Fatal() calls os.Exit(). + g.output(fatalLog, fmt.Sprintln(args...)) + os.Exit(1) } func (g *loggerT) Fatalf(format string, args ...interface{}) { - g.m[fatalLog].Fatalf(format, args...) - // No need to call os.Exit() again because log.Logger.Fatal() calls os.Exit(). + g.output(fatalLog, fmt.Sprintf(format, args...)) + os.Exit(1) } func (g *loggerT) V(l int) bool { @@ -204,18 +241,18 @@ func (g *loggerT) V(l int) bool { // DepthLoggerV2, the below functions will be called with the appropriate stack // depth set for trivial functions the logger may ignore. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. type DepthLoggerV2 interface { LoggerV2 - // InfoDepth logs to INFO log at the specified depth. Arguments are handled in the manner of fmt.Print. + // InfoDepth logs to INFO log at the specified depth. Arguments are handled in the manner of fmt.Println. InfoDepth(depth int, args ...interface{}) - // WarningDepth logs to WARNING log at the specified depth. Arguments are handled in the manner of fmt.Print. + // WarningDepth logs to WARNING log at the specified depth. Arguments are handled in the manner of fmt.Println. WarningDepth(depth int, args ...interface{}) - // ErrorDetph logs to ERROR log at the specified depth. Arguments are handled in the manner of fmt.Print. + // ErrorDepth logs to ERROR log at the specified depth. Arguments are handled in the manner of fmt.Println. ErrorDepth(depth int, args ...interface{}) - // FatalDepth logs to FATAL log at the specified depth. Arguments are handled in the manner of fmt.Print. + // FatalDepth logs to FATAL log at the specified depth. Arguments are handled in the manner of fmt.Println. FatalDepth(depth int, args ...interface{}) } diff --git a/vendor/google.golang.org/grpc/idle.go b/vendor/google.golang.org/grpc/idle.go new file mode 100644 index 00000000000..dc3dc72f6b0 --- /dev/null +++ b/vendor/google.golang.org/grpc/idle.go @@ -0,0 +1,287 @@ +/* + * + * Copyright 2023 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package grpc + +import ( + "fmt" + "math" + "sync" + "sync/atomic" + "time" +) + +// For overriding in unit tests. +var timeAfterFunc = func(d time.Duration, f func()) *time.Timer { + return time.AfterFunc(d, f) +} + +// idlenessEnforcer is the functionality provided by grpc.ClientConn to enter +// and exit from idle mode. +type idlenessEnforcer interface { + exitIdleMode() error + enterIdleMode() error +} + +// idlenessManager defines the functionality required to track RPC activity on a +// channel. +type idlenessManager interface { + onCallBegin() error + onCallEnd() + close() +} + +type noopIdlenessManager struct{} + +func (noopIdlenessManager) onCallBegin() error { return nil } +func (noopIdlenessManager) onCallEnd() {} +func (noopIdlenessManager) close() {} + +// idlenessManagerImpl implements the idlenessManager interface. It uses atomic +// operations to synchronize access to shared state and a mutex to guarantee +// mutual exclusion in a critical section. +type idlenessManagerImpl struct { + // State accessed atomically. + lastCallEndTime int64 // Unix timestamp in nanos; time when the most recent RPC completed. + activeCallsCount int32 // Count of active RPCs; -math.MaxInt32 means channel is idle or is trying to get there. + activeSinceLastTimerCheck int32 // Boolean; True if there was an RPC since the last timer callback. + closed int32 // Boolean; True when the manager is closed. + + // Can be accessed without atomics or mutex since these are set at creation + // time and read-only after that. + enforcer idlenessEnforcer // Functionality provided by grpc.ClientConn. + timeout int64 // Idle timeout duration nanos stored as an int64. + + // idleMu is used to guarantee mutual exclusion in two scenarios: + // - Opposing intentions: + // - a: Idle timeout has fired and handleIdleTimeout() is trying to put + // the channel in idle mode because the channel has been inactive. + // - b: At the same time an RPC is made on the channel, and onCallBegin() + // is trying to prevent the channel from going idle. + // - Competing intentions: + // - The channel is in idle mode and there are multiple RPCs starting at + // the same time, all trying to move the channel out of idle. Only one + // of them should succeed in doing so, while the other RPCs should + // piggyback on the first one and be successfully handled. + idleMu sync.RWMutex + actuallyIdle bool + timer *time.Timer +} + +// newIdlenessManager creates a new idleness manager implementation for the +// given idle timeout. +func newIdlenessManager(enforcer idlenessEnforcer, idleTimeout time.Duration) idlenessManager { + if idleTimeout == 0 { + return noopIdlenessManager{} + } + + i := &idlenessManagerImpl{ + enforcer: enforcer, + timeout: int64(idleTimeout), + } + i.timer = timeAfterFunc(idleTimeout, i.handleIdleTimeout) + return i +} + +// resetIdleTimer resets the idle timer to the given duration. This method +// should only be called from the timer callback. +func (i *idlenessManagerImpl) resetIdleTimer(d time.Duration) { + i.idleMu.Lock() + defer i.idleMu.Unlock() + + if i.timer == nil { + // Only close sets timer to nil. We are done. + return + } + + // It is safe to ignore the return value from Reset() because this method is + // only ever called from the timer callback, which means the timer has + // already fired. + i.timer.Reset(d) +} + +// handleIdleTimeout is the timer callback that is invoked upon expiry of the +// configured idle timeout. The channel is considered inactive if there are no +// ongoing calls and no RPC activity since the last time the timer fired. +func (i *idlenessManagerImpl) handleIdleTimeout() { + if i.isClosed() { + return + } + + if atomic.LoadInt32(&i.activeCallsCount) > 0 { + i.resetIdleTimer(time.Duration(i.timeout)) + return + } + + // There has been activity on the channel since we last got here. Reset the + // timer and return. + if atomic.LoadInt32(&i.activeSinceLastTimerCheck) == 1 { + // Set the timer to fire after a duration of idle timeout, calculated + // from the time the most recent RPC completed. + atomic.StoreInt32(&i.activeSinceLastTimerCheck, 0) + i.resetIdleTimer(time.Duration(atomic.LoadInt64(&i.lastCallEndTime) + i.timeout - time.Now().UnixNano())) + return + } + + // This CAS operation is extremely likely to succeed given that there has + // been no activity since the last time we were here. Setting the + // activeCallsCount to -math.MaxInt32 indicates to onCallBegin() that the + // channel is either in idle mode or is trying to get there. + if !atomic.CompareAndSwapInt32(&i.activeCallsCount, 0, -math.MaxInt32) { + // This CAS operation can fail if an RPC started after we checked for + // activity at the top of this method, or one was ongoing from before + // the last time we were here. In both case, reset the timer and return. + i.resetIdleTimer(time.Duration(i.timeout)) + return + } + + // Now that we've set the active calls count to -math.MaxInt32, it's time to + // actually move to idle mode. + if i.tryEnterIdleMode() { + // Successfully entered idle mode. No timer needed until we exit idle. + return + } + + // Failed to enter idle mode due to a concurrent RPC that kept the channel + // active, or because of an error from the channel. Undo the attempt to + // enter idle, and reset the timer to try again later. + atomic.AddInt32(&i.activeCallsCount, math.MaxInt32) + i.resetIdleTimer(time.Duration(i.timeout)) +} + +// tryEnterIdleMode instructs the channel to enter idle mode. But before +// that, it performs a last minute check to ensure that no new RPC has come in, +// making the channel active. +// +// Return value indicates whether or not the channel moved to idle mode. +// +// Holds idleMu which ensures mutual exclusion with exitIdleMode. +func (i *idlenessManagerImpl) tryEnterIdleMode() bool { + i.idleMu.Lock() + defer i.idleMu.Unlock() + + if atomic.LoadInt32(&i.activeCallsCount) != -math.MaxInt32 { + // We raced and lost to a new RPC. Very rare, but stop entering idle. + return false + } + if atomic.LoadInt32(&i.activeSinceLastTimerCheck) == 1 { + // An very short RPC could have come in (and also finished) after we + // checked for calls count and activity in handleIdleTimeout(), but + // before the CAS operation. So, we need to check for activity again. + return false + } + + // No new RPCs have come in since we last set the active calls count value + // -math.MaxInt32 in the timer callback. And since we have the lock, it is + // safe to enter idle mode now. + if err := i.enforcer.enterIdleMode(); err != nil { + logger.Errorf("Failed to enter idle mode: %v", err) + return false + } + + // Successfully entered idle mode. + i.actuallyIdle = true + return true +} + +// onCallBegin is invoked at the start of every RPC. +func (i *idlenessManagerImpl) onCallBegin() error { + if i.isClosed() { + return nil + } + + if atomic.AddInt32(&i.activeCallsCount, 1) > 0 { + // Channel is not idle now. Set the activity bit and allow the call. + atomic.StoreInt32(&i.activeSinceLastTimerCheck, 1) + return nil + } + + // Channel is either in idle mode or is in the process of moving to idle + // mode. Attempt to exit idle mode to allow this RPC. + if err := i.exitIdleMode(); err != nil { + // Undo the increment to calls count, and return an error causing the + // RPC to fail. + atomic.AddInt32(&i.activeCallsCount, -1) + return err + } + + atomic.StoreInt32(&i.activeSinceLastTimerCheck, 1) + return nil +} + +// exitIdleMode instructs the channel to exit idle mode. +// +// Holds idleMu which ensures mutual exclusion with tryEnterIdleMode. +func (i *idlenessManagerImpl) exitIdleMode() error { + i.idleMu.Lock() + defer i.idleMu.Unlock() + + if !i.actuallyIdle { + // This can happen in two scenarios: + // - handleIdleTimeout() set the calls count to -math.MaxInt32 and called + // tryEnterIdleMode(). But before the latter could grab the lock, an RPC + // came in and onCallBegin() noticed that the calls count is negative. + // - Channel is in idle mode, and multiple new RPCs come in at the same + // time, all of them notice a negative calls count in onCallBegin and get + // here. The first one to get the lock would got the channel to exit idle. + // + // Either way, nothing to do here. + return nil + } + + if err := i.enforcer.exitIdleMode(); err != nil { + return fmt.Errorf("channel failed to exit idle mode: %v", err) + } + + // Undo the idle entry process. This also respects any new RPC attempts. + atomic.AddInt32(&i.activeCallsCount, math.MaxInt32) + i.actuallyIdle = false + + // Start a new timer to fire after the configured idle timeout. + i.timer = timeAfterFunc(time.Duration(i.timeout), i.handleIdleTimeout) + return nil +} + +// onCallEnd is invoked at the end of every RPC. +func (i *idlenessManagerImpl) onCallEnd() { + if i.isClosed() { + return + } + + // Record the time at which the most recent call finished. + atomic.StoreInt64(&i.lastCallEndTime, time.Now().UnixNano()) + + // Decrement the active calls count. This count can temporarily go negative + // when the timer callback is in the process of moving the channel to idle + // mode, but one or more RPCs come in and complete before the timer callback + // can get done with the process of moving to idle mode. + atomic.AddInt32(&i.activeCallsCount, -1) +} + +func (i *idlenessManagerImpl) isClosed() bool { + return atomic.LoadInt32(&i.closed) == 1 +} + +func (i *idlenessManagerImpl) close() { + atomic.StoreInt32(&i.closed, 1) + + i.idleMu.Lock() + i.timer.Stop() + i.timer = nil + i.idleMu.Unlock() +} diff --git a/vendor/google.golang.org/grpc/install_gae.sh b/vendor/google.golang.org/grpc/install_gae.sh deleted file mode 100644 index 15ff9facdd7..00000000000 --- a/vendor/google.golang.org/grpc/install_gae.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash - -TMP=$(mktemp -d /tmp/sdk.XXX) \ -&& curl -o $TMP.zip "https://storage.googleapis.com/appengine-sdks/featured/go_appengine_sdk_linux_amd64-1.9.68.zip" \ -&& unzip -q $TMP.zip -d $TMP \ -&& export PATH="$PATH:$TMP/go_appengine" \ No newline at end of file diff --git a/vendor/google.golang.org/grpc/interceptor.go b/vendor/google.golang.org/grpc/interceptor.go index 668e0adcf0a..bb96ef57be8 100644 --- a/vendor/google.golang.org/grpc/interceptor.go +++ b/vendor/google.golang.org/grpc/interceptor.go @@ -72,9 +72,12 @@ type UnaryServerInfo struct { } // UnaryHandler defines the handler invoked by UnaryServerInterceptor to complete the normal -// execution of a unary RPC. If a UnaryHandler returns an error, it should be produced by the -// status package, or else gRPC will use codes.Unknown as the status code and err.Error() as -// the status message of the RPC. +// execution of a unary RPC. +// +// If a UnaryHandler returns an error, it should either be produced by the +// status package, or be one of the context errors. Otherwise, gRPC will use +// codes.Unknown as the status code and err.Error() as the status message of the +// RPC. type UnaryHandler func(ctx context.Context, req interface{}) (interface{}, error) // UnaryServerInterceptor provides a hook to intercept the execution of a unary RPC on the server. info diff --git a/vendor/google.golang.org/grpc/internal/balancer/gracefulswitch/gracefulswitch.go b/vendor/google.golang.org/grpc/internal/balancer/gracefulswitch/gracefulswitch.go new file mode 100644 index 00000000000..08666f62a7c --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/balancer/gracefulswitch/gracefulswitch.go @@ -0,0 +1,384 @@ +/* + * + * Copyright 2022 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Package gracefulswitch implements a graceful switch load balancer. +package gracefulswitch + +import ( + "errors" + "fmt" + "sync" + + "google.golang.org/grpc/balancer" + "google.golang.org/grpc/balancer/base" + "google.golang.org/grpc/connectivity" + "google.golang.org/grpc/resolver" +) + +var errBalancerClosed = errors.New("gracefulSwitchBalancer is closed") +var _ balancer.Balancer = (*Balancer)(nil) + +// NewBalancer returns a graceful switch Balancer. +func NewBalancer(cc balancer.ClientConn, opts balancer.BuildOptions) *Balancer { + return &Balancer{ + cc: cc, + bOpts: opts, + } +} + +// Balancer is a utility to gracefully switch from one balancer to +// a new balancer. It implements the balancer.Balancer interface. +type Balancer struct { + bOpts balancer.BuildOptions + cc balancer.ClientConn + + // mu protects the following fields and all fields within balancerCurrent + // and balancerPending. mu does not need to be held when calling into the + // child balancers, as all calls into these children happen only as a direct + // result of a call into the gracefulSwitchBalancer, which are also + // guaranteed to be synchronous. There is one exception: an UpdateState call + // from a child balancer when current and pending are populated can lead to + // calling Close() on the current. To prevent that racing with an + // UpdateSubConnState from the channel, we hold currentMu during Close and + // UpdateSubConnState calls. + mu sync.Mutex + balancerCurrent *balancerWrapper + balancerPending *balancerWrapper + closed bool // set to true when this balancer is closed + + // currentMu must be locked before mu. This mutex guards against this + // sequence of events: UpdateSubConnState() called, finds the + // balancerCurrent, gives up lock, updateState comes in, causes Close() on + // balancerCurrent before the UpdateSubConnState is called on the + // balancerCurrent. + currentMu sync.Mutex +} + +// swap swaps out the current lb with the pending lb and updates the ClientConn. +// The caller must hold gsb.mu. +func (gsb *Balancer) swap() { + gsb.cc.UpdateState(gsb.balancerPending.lastState) + cur := gsb.balancerCurrent + gsb.balancerCurrent = gsb.balancerPending + gsb.balancerPending = nil + go func() { + gsb.currentMu.Lock() + defer gsb.currentMu.Unlock() + cur.Close() + }() +} + +// Helper function that checks if the balancer passed in is current or pending. +// The caller must hold gsb.mu. +func (gsb *Balancer) balancerCurrentOrPending(bw *balancerWrapper) bool { + return bw == gsb.balancerCurrent || bw == gsb.balancerPending +} + +// SwitchTo initializes the graceful switch process, which completes based on +// connectivity state changes on the current/pending balancer. Thus, the switch +// process is not complete when this method returns. This method must be called +// synchronously alongside the rest of the balancer.Balancer methods this +// Graceful Switch Balancer implements. +func (gsb *Balancer) SwitchTo(builder balancer.Builder) error { + gsb.mu.Lock() + if gsb.closed { + gsb.mu.Unlock() + return errBalancerClosed + } + bw := &balancerWrapper{ + gsb: gsb, + lastState: balancer.State{ + ConnectivityState: connectivity.Connecting, + Picker: base.NewErrPicker(balancer.ErrNoSubConnAvailable), + }, + subconns: make(map[balancer.SubConn]bool), + } + balToClose := gsb.balancerPending // nil if there is no pending balancer + if gsb.balancerCurrent == nil { + gsb.balancerCurrent = bw + } else { + gsb.balancerPending = bw + } + gsb.mu.Unlock() + balToClose.Close() + // This function takes a builder instead of a balancer because builder.Build + // can call back inline, and this utility needs to handle the callbacks. + newBalancer := builder.Build(bw, gsb.bOpts) + if newBalancer == nil { + // This is illegal and should never happen; we clear the balancerWrapper + // we were constructing if it happens to avoid a potential panic. + gsb.mu.Lock() + if gsb.balancerPending != nil { + gsb.balancerPending = nil + } else { + gsb.balancerCurrent = nil + } + gsb.mu.Unlock() + return balancer.ErrBadResolverState + } + + // This write doesn't need to take gsb.mu because this field never gets read + // or written to on any calls from the current or pending. Calls from grpc + // to this balancer are guaranteed to be called synchronously, so this + // bw.Balancer field will never be forwarded to until this SwitchTo() + // function returns. + bw.Balancer = newBalancer + return nil +} + +// Returns nil if the graceful switch balancer is closed. +func (gsb *Balancer) latestBalancer() *balancerWrapper { + gsb.mu.Lock() + defer gsb.mu.Unlock() + if gsb.balancerPending != nil { + return gsb.balancerPending + } + return gsb.balancerCurrent +} + +// UpdateClientConnState forwards the update to the latest balancer created. +func (gsb *Balancer) UpdateClientConnState(state balancer.ClientConnState) error { + // The resolver data is only relevant to the most recent LB Policy. + balToUpdate := gsb.latestBalancer() + if balToUpdate == nil { + return errBalancerClosed + } + // Perform this call without gsb.mu to prevent deadlocks if the child calls + // back into the channel. The latest balancer can never be closed during a + // call from the channel, even without gsb.mu held. + return balToUpdate.UpdateClientConnState(state) +} + +// ResolverError forwards the error to the latest balancer created. +func (gsb *Balancer) ResolverError(err error) { + // The resolver data is only relevant to the most recent LB Policy. + balToUpdate := gsb.latestBalancer() + if balToUpdate == nil { + return + } + // Perform this call without gsb.mu to prevent deadlocks if the child calls + // back into the channel. The latest balancer can never be closed during a + // call from the channel, even without gsb.mu held. + balToUpdate.ResolverError(err) +} + +// ExitIdle forwards the call to the latest balancer created. +// +// If the latest balancer does not support ExitIdle, the subConns are +// re-connected to manually. +func (gsb *Balancer) ExitIdle() { + balToUpdate := gsb.latestBalancer() + if balToUpdate == nil { + return + } + // There is no need to protect this read with a mutex, as the write to the + // Balancer field happens in SwitchTo, which completes before this can be + // called. + if ei, ok := balToUpdate.Balancer.(balancer.ExitIdler); ok { + ei.ExitIdle() + return + } + gsb.mu.Lock() + defer gsb.mu.Unlock() + for sc := range balToUpdate.subconns { + sc.Connect() + } +} + +// UpdateSubConnState forwards the update to the appropriate child. +func (gsb *Balancer) UpdateSubConnState(sc balancer.SubConn, state balancer.SubConnState) { + gsb.currentMu.Lock() + defer gsb.currentMu.Unlock() + gsb.mu.Lock() + // Forward update to the appropriate child. Even if there is a pending + // balancer, the current balancer should continue to get SubConn updates to + // maintain the proper state while the pending is still connecting. + var balToUpdate *balancerWrapper + if gsb.balancerCurrent != nil && gsb.balancerCurrent.subconns[sc] { + balToUpdate = gsb.balancerCurrent + } else if gsb.balancerPending != nil && gsb.balancerPending.subconns[sc] { + balToUpdate = gsb.balancerPending + } + gsb.mu.Unlock() + if balToUpdate == nil { + // SubConn belonged to a stale lb policy that has not yet fully closed, + // or the balancer was already closed. + return + } + balToUpdate.UpdateSubConnState(sc, state) +} + +// Close closes any active child balancers. +func (gsb *Balancer) Close() { + gsb.mu.Lock() + gsb.closed = true + currentBalancerToClose := gsb.balancerCurrent + gsb.balancerCurrent = nil + pendingBalancerToClose := gsb.balancerPending + gsb.balancerPending = nil + gsb.mu.Unlock() + + currentBalancerToClose.Close() + pendingBalancerToClose.Close() +} + +// balancerWrapper wraps a balancer.Balancer, and overrides some Balancer +// methods to help cleanup SubConns created by the wrapped balancer. +// +// It implements the balancer.ClientConn interface and is passed down in that +// capacity to the wrapped balancer. It maintains a set of subConns created by +// the wrapped balancer and calls from the latter to create/update/remove +// SubConns update this set before being forwarded to the parent ClientConn. +// State updates from the wrapped balancer can result in invocation of the +// graceful switch logic. +type balancerWrapper struct { + balancer.Balancer + gsb *Balancer + + lastState balancer.State + subconns map[balancer.SubConn]bool // subconns created by this balancer +} + +func (bw *balancerWrapper) UpdateSubConnState(sc balancer.SubConn, state balancer.SubConnState) { + if state.ConnectivityState == connectivity.Shutdown { + bw.gsb.mu.Lock() + delete(bw.subconns, sc) + bw.gsb.mu.Unlock() + } + // There is no need to protect this read with a mutex, as the write to the + // Balancer field happens in SwitchTo, which completes before this can be + // called. + bw.Balancer.UpdateSubConnState(sc, state) +} + +// Close closes the underlying LB policy and removes the subconns it created. bw +// must not be referenced via balancerCurrent or balancerPending in gsb when +// called. gsb.mu must not be held. Does not panic with a nil receiver. +func (bw *balancerWrapper) Close() { + // before Close is called. + if bw == nil { + return + } + // There is no need to protect this read with a mutex, as Close() is + // impossible to be called concurrently with the write in SwitchTo(). The + // callsites of Close() for this balancer in Graceful Switch Balancer will + // never be called until SwitchTo() returns. + bw.Balancer.Close() + bw.gsb.mu.Lock() + for sc := range bw.subconns { + bw.gsb.cc.RemoveSubConn(sc) + } + bw.gsb.mu.Unlock() +} + +func (bw *balancerWrapper) UpdateState(state balancer.State) { + // Hold the mutex for this entire call to ensure it cannot occur + // concurrently with other updateState() calls. This causes updates to + // lastState and calls to cc.UpdateState to happen atomically. + bw.gsb.mu.Lock() + defer bw.gsb.mu.Unlock() + bw.lastState = state + + if !bw.gsb.balancerCurrentOrPending(bw) { + return + } + + if bw == bw.gsb.balancerCurrent { + // In the case that the current balancer exits READY, and there is a pending + // balancer, you can forward the pending balancer's cached State up to + // ClientConn and swap the pending into the current. This is because there + // is no reason to gracefully switch from and keep using the old policy as + // the ClientConn is not connected to any backends. + if state.ConnectivityState != connectivity.Ready && bw.gsb.balancerPending != nil { + bw.gsb.swap() + return + } + // Even if there is a pending balancer waiting to be gracefully switched to, + // continue to forward current balancer updates to the Client Conn. Ignoring + // state + picker from the current would cause undefined behavior/cause the + // system to behave incorrectly from the current LB policies perspective. + // Also, the current LB is still being used by grpc to choose SubConns per + // RPC, and thus should use the most updated form of the current balancer. + bw.gsb.cc.UpdateState(state) + return + } + // This method is now dealing with a state update from the pending balancer. + // If the current balancer is currently in a state other than READY, the new + // policy can be swapped into place immediately. This is because there is no + // reason to gracefully switch from and keep using the old policy as the + // ClientConn is not connected to any backends. + if state.ConnectivityState != connectivity.Connecting || bw.gsb.balancerCurrent.lastState.ConnectivityState != connectivity.Ready { + bw.gsb.swap() + } +} + +func (bw *balancerWrapper) NewSubConn(addrs []resolver.Address, opts balancer.NewSubConnOptions) (balancer.SubConn, error) { + bw.gsb.mu.Lock() + if !bw.gsb.balancerCurrentOrPending(bw) { + bw.gsb.mu.Unlock() + return nil, fmt.Errorf("%T at address %p that called NewSubConn is deleted", bw, bw) + } + bw.gsb.mu.Unlock() + + sc, err := bw.gsb.cc.NewSubConn(addrs, opts) + if err != nil { + return nil, err + } + bw.gsb.mu.Lock() + if !bw.gsb.balancerCurrentOrPending(bw) { // balancer was closed during this call + bw.gsb.cc.RemoveSubConn(sc) + bw.gsb.mu.Unlock() + return nil, fmt.Errorf("%T at address %p that called NewSubConn is deleted", bw, bw) + } + bw.subconns[sc] = true + bw.gsb.mu.Unlock() + return sc, nil +} + +func (bw *balancerWrapper) ResolveNow(opts resolver.ResolveNowOptions) { + // Ignore ResolveNow requests from anything other than the most recent + // balancer, because older balancers were already removed from the config. + if bw != bw.gsb.latestBalancer() { + return + } + bw.gsb.cc.ResolveNow(opts) +} + +func (bw *balancerWrapper) RemoveSubConn(sc balancer.SubConn) { + bw.gsb.mu.Lock() + if !bw.gsb.balancerCurrentOrPending(bw) { + bw.gsb.mu.Unlock() + return + } + bw.gsb.mu.Unlock() + bw.gsb.cc.RemoveSubConn(sc) +} + +func (bw *balancerWrapper) UpdateAddresses(sc balancer.SubConn, addrs []resolver.Address) { + bw.gsb.mu.Lock() + if !bw.gsb.balancerCurrentOrPending(bw) { + bw.gsb.mu.Unlock() + return + } + bw.gsb.mu.Unlock() + bw.gsb.cc.UpdateAddresses(sc, addrs) +} + +func (bw *balancerWrapper) Target() string { + return bw.gsb.cc.Target() +} diff --git a/vendor/google.golang.org/grpc/internal/binarylog/binarylog.go b/vendor/google.golang.org/grpc/internal/binarylog/binarylog.go index 5cc3aeddb21..755fdebc1b1 100644 --- a/vendor/google.golang.org/grpc/internal/binarylog/binarylog.go +++ b/vendor/google.golang.org/grpc/internal/binarylog/binarylog.go @@ -28,38 +28,48 @@ import ( "google.golang.org/grpc/internal/grpcutil" ) -// Logger is the global binary logger. It can be used to get binary logger for -// each method. +var grpclogLogger = grpclog.Component("binarylog") + +// Logger specifies MethodLoggers for method names with a Log call that +// takes a context. +// +// This is used in the 1.0 release of gcp/observability, and thus must not be +// deleted or changed. type Logger interface { - getMethodLogger(methodName string) *MethodLogger + GetMethodLogger(methodName string) MethodLogger } // binLogger is the global binary logger for the binary. One of this should be // built at init time from the configuration (environment variable or flags). // -// It is used to get a methodLogger for each individual method. +// It is used to get a MethodLogger for each individual method. var binLogger Logger -var grpclogLogger = grpclog.Component("binarylog") - -// SetLogger sets the binarg logger. +// SetLogger sets the binary logger. // // Only call this at init time. func SetLogger(l Logger) { binLogger = l } -// GetMethodLogger returns the methodLogger for the given methodName. +// GetLogger gets the binary logger. +// +// Only call this at init time. +func GetLogger() Logger { + return binLogger +} + +// GetMethodLogger returns the MethodLogger for the given methodName. // // methodName should be in the format of "/service/method". // -// Each methodLogger returned by this method is a new instance. This is to +// Each MethodLogger returned by this method is a new instance. This is to // generate sequence id within the call. -func GetMethodLogger(methodName string) *MethodLogger { +func GetMethodLogger(methodName string) MethodLogger { if binLogger == nil { return nil } - return binLogger.getMethodLogger(methodName) + return binLogger.GetMethodLogger(methodName) } func init() { @@ -68,17 +78,29 @@ func init() { binLogger = NewLoggerFromConfigString(configStr) } -type methodLoggerConfig struct { +// MethodLoggerConfig contains the setting for logging behavior of a method +// logger. Currently, it contains the max length of header and message. +type MethodLoggerConfig struct { // Max length of header and message. - hdr, msg uint64 + Header, Message uint64 +} + +// LoggerConfig contains the config for loggers to create method loggers. +type LoggerConfig struct { + All *MethodLoggerConfig + Services map[string]*MethodLoggerConfig + Methods map[string]*MethodLoggerConfig + + Blacklist map[string]struct{} } type logger struct { - all *methodLoggerConfig - services map[string]*methodLoggerConfig - methods map[string]*methodLoggerConfig + config LoggerConfig +} - blacklist map[string]struct{} +// NewLoggerFromConfig builds a logger with the given LoggerConfig. +func NewLoggerFromConfig(config LoggerConfig) Logger { + return &logger{config: config} } // newEmptyLogger creates an empty logger. The map fields need to be filled in @@ -88,83 +110,83 @@ func newEmptyLogger() *logger { } // Set method logger for "*". -func (l *logger) setDefaultMethodLogger(ml *methodLoggerConfig) error { - if l.all != nil { +func (l *logger) setDefaultMethodLogger(ml *MethodLoggerConfig) error { + if l.config.All != nil { return fmt.Errorf("conflicting global rules found") } - l.all = ml + l.config.All = ml return nil } // Set method logger for "service/*". // -// New methodLogger with same service overrides the old one. -func (l *logger) setServiceMethodLogger(service string, ml *methodLoggerConfig) error { - if _, ok := l.services[service]; ok { +// New MethodLogger with same service overrides the old one. +func (l *logger) setServiceMethodLogger(service string, ml *MethodLoggerConfig) error { + if _, ok := l.config.Services[service]; ok { return fmt.Errorf("conflicting service rules for service %v found", service) } - if l.services == nil { - l.services = make(map[string]*methodLoggerConfig) + if l.config.Services == nil { + l.config.Services = make(map[string]*MethodLoggerConfig) } - l.services[service] = ml + l.config.Services[service] = ml return nil } // Set method logger for "service/method". // -// New methodLogger with same method overrides the old one. -func (l *logger) setMethodMethodLogger(method string, ml *methodLoggerConfig) error { - if _, ok := l.blacklist[method]; ok { +// New MethodLogger with same method overrides the old one. +func (l *logger) setMethodMethodLogger(method string, ml *MethodLoggerConfig) error { + if _, ok := l.config.Blacklist[method]; ok { return fmt.Errorf("conflicting blacklist rules for method %v found", method) } - if _, ok := l.methods[method]; ok { + if _, ok := l.config.Methods[method]; ok { return fmt.Errorf("conflicting method rules for method %v found", method) } - if l.methods == nil { - l.methods = make(map[string]*methodLoggerConfig) + if l.config.Methods == nil { + l.config.Methods = make(map[string]*MethodLoggerConfig) } - l.methods[method] = ml + l.config.Methods[method] = ml return nil } // Set blacklist method for "-service/method". func (l *logger) setBlacklist(method string) error { - if _, ok := l.blacklist[method]; ok { + if _, ok := l.config.Blacklist[method]; ok { return fmt.Errorf("conflicting blacklist rules for method %v found", method) } - if _, ok := l.methods[method]; ok { + if _, ok := l.config.Methods[method]; ok { return fmt.Errorf("conflicting method rules for method %v found", method) } - if l.blacklist == nil { - l.blacklist = make(map[string]struct{}) + if l.config.Blacklist == nil { + l.config.Blacklist = make(map[string]struct{}) } - l.blacklist[method] = struct{}{} + l.config.Blacklist[method] = struct{}{} return nil } -// getMethodLogger returns the methodLogger for the given methodName. +// getMethodLogger returns the MethodLogger for the given methodName. // // methodName should be in the format of "/service/method". // -// Each methodLogger returned by this method is a new instance. This is to +// Each MethodLogger returned by this method is a new instance. This is to // generate sequence id within the call. -func (l *logger) getMethodLogger(methodName string) *MethodLogger { +func (l *logger) GetMethodLogger(methodName string) MethodLogger { s, m, err := grpcutil.ParseMethod(methodName) if err != nil { grpclogLogger.Infof("binarylogging: failed to parse %q: %v", methodName, err) return nil } - if ml, ok := l.methods[s+"/"+m]; ok { - return newMethodLogger(ml.hdr, ml.msg) + if ml, ok := l.config.Methods[s+"/"+m]; ok { + return NewTruncatingMethodLogger(ml.Header, ml.Message) } - if _, ok := l.blacklist[s+"/"+m]; ok { + if _, ok := l.config.Blacklist[s+"/"+m]; ok { return nil } - if ml, ok := l.services[s]; ok { - return newMethodLogger(ml.hdr, ml.msg) + if ml, ok := l.config.Services[s]; ok { + return NewTruncatingMethodLogger(ml.Header, ml.Message) } - if l.all == nil { + if l.config.All == nil { return nil } - return newMethodLogger(l.all.hdr, l.all.msg) + return NewTruncatingMethodLogger(l.config.All.Header, l.config.All.Message) } diff --git a/vendor/google.golang.org/grpc/internal/binarylog/env_config.go b/vendor/google.golang.org/grpc/internal/binarylog/env_config.go index d8f4e7602fd..f9e80e27ab6 100644 --- a/vendor/google.golang.org/grpc/internal/binarylog/env_config.go +++ b/vendor/google.golang.org/grpc/internal/binarylog/env_config.go @@ -30,15 +30,15 @@ import ( // to build a new logger and assign it to binarylog.Logger. // // Example filter config strings: -// - "" Nothing will be logged -// - "*" All headers and messages will be fully logged. -// - "*{h}" Only headers will be logged. -// - "*{m:256}" Only the first 256 bytes of each message will be logged. -// - "Foo/*" Logs every method in service Foo -// - "Foo/*,-Foo/Bar" Logs every method in service Foo except method /Foo/Bar -// - "Foo/*,Foo/Bar{m:256}" Logs the first 256 bytes of each message in method -// /Foo/Bar, logs all headers and messages in every other method in service -// Foo. +// - "" Nothing will be logged +// - "*" All headers and messages will be fully logged. +// - "*{h}" Only headers will be logged. +// - "*{m:256}" Only the first 256 bytes of each message will be logged. +// - "Foo/*" Logs every method in service Foo +// - "Foo/*,-Foo/Bar" Logs every method in service Foo except method /Foo/Bar +// - "Foo/*,Foo/Bar{m:256}" Logs the first 256 bytes of each message in method +// /Foo/Bar, logs all headers and messages in every other method in service +// Foo. // // If two configs exist for one certain method or service, the one specified // later overrides the previous config. @@ -57,7 +57,7 @@ func NewLoggerFromConfigString(s string) Logger { return l } -// fillMethodLoggerWithConfigString parses config, creates methodLogger and adds +// fillMethodLoggerWithConfigString parses config, creates TruncatingMethodLogger and adds // it to the right map in the logger. func (l *logger) fillMethodLoggerWithConfigString(config string) error { // "" is invalid. @@ -89,7 +89,7 @@ func (l *logger) fillMethodLoggerWithConfigString(config string) error { if err != nil { return fmt.Errorf("invalid config: %q, %v", config, err) } - if err := l.setDefaultMethodLogger(&methodLoggerConfig{hdr: hdr, msg: msg}); err != nil { + if err := l.setDefaultMethodLogger(&MethodLoggerConfig{Header: hdr, Message: msg}); err != nil { return fmt.Errorf("invalid config: %v", err) } return nil @@ -104,11 +104,11 @@ func (l *logger) fillMethodLoggerWithConfigString(config string) error { return fmt.Errorf("invalid header/message length config: %q, %v", suffix, err) } if m == "*" { - if err := l.setServiceMethodLogger(s, &methodLoggerConfig{hdr: hdr, msg: msg}); err != nil { + if err := l.setServiceMethodLogger(s, &MethodLoggerConfig{Header: hdr, Message: msg}); err != nil { return fmt.Errorf("invalid config: %v", err) } } else { - if err := l.setMethodMethodLogger(s+"/"+m, &methodLoggerConfig{hdr: hdr, msg: msg}); err != nil { + if err := l.setMethodMethodLogger(s+"/"+m, &MethodLoggerConfig{Header: hdr, Message: msg}); err != nil { return fmt.Errorf("invalid config: %v", err) } } diff --git a/vendor/google.golang.org/grpc/internal/binarylog/method_logger.go b/vendor/google.golang.org/grpc/internal/binarylog/method_logger.go index 0cdb4183150..6c3f632215f 100644 --- a/vendor/google.golang.org/grpc/internal/binarylog/method_logger.go +++ b/vendor/google.golang.org/grpc/internal/binarylog/method_logger.go @@ -19,6 +19,7 @@ package binarylog import ( + "context" "net" "strings" "sync/atomic" @@ -26,7 +27,7 @@ import ( "github.com/golang/protobuf/proto" "github.com/golang/protobuf/ptypes" - pb "google.golang.org/grpc/binarylog/grpc_binarylog_v1" + binlogpb "google.golang.org/grpc/binarylog/grpc_binarylog_v1" "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" ) @@ -48,7 +49,16 @@ func (g *callIDGenerator) reset() { var idGen callIDGenerator // MethodLogger is the sub-logger for each method. -type MethodLogger struct { +// +// This is used in the 1.0 release of gcp/observability, and thus must not be +// deleted or changed. +type MethodLogger interface { + Log(context.Context, LogEntryConfig) +} + +// TruncatingMethodLogger is a method logger that truncates headers and messages +// based on configured fields. +type TruncatingMethodLogger struct { headerMaxLen, messageMaxLen uint64 callID uint64 @@ -57,8 +67,12 @@ type MethodLogger struct { sink Sink // TODO(blog): make this plugable. } -func newMethodLogger(h, m uint64) *MethodLogger { - return &MethodLogger{ +// NewTruncatingMethodLogger returns a new truncating method logger. +// +// This is used in the 1.0 release of gcp/observability, and thus must not be +// deleted or changed. +func NewTruncatingMethodLogger(h, m uint64) *TruncatingMethodLogger { + return &TruncatingMethodLogger{ headerMaxLen: h, messageMaxLen: m, @@ -69,8 +83,10 @@ func newMethodLogger(h, m uint64) *MethodLogger { } } -// Log creates a proto binary log entry, and logs it to the sink. -func (ml *MethodLogger) Log(c LogEntryConfig) { +// Build is an internal only method for building the proto message out of the +// input event. It's made public to enable other library to reuse as much logic +// in TruncatingMethodLogger as possible. +func (ml *TruncatingMethodLogger) Build(c LogEntryConfig) *binlogpb.GrpcLogEntry { m := c.toProto() timestamp, _ := ptypes.TimestampProto(time.Now()) m.Timestamp = timestamp @@ -78,18 +94,22 @@ func (ml *MethodLogger) Log(c LogEntryConfig) { m.SequenceIdWithinCall = ml.idWithinCallGen.next() switch pay := m.Payload.(type) { - case *pb.GrpcLogEntry_ClientHeader: + case *binlogpb.GrpcLogEntry_ClientHeader: m.PayloadTruncated = ml.truncateMetadata(pay.ClientHeader.GetMetadata()) - case *pb.GrpcLogEntry_ServerHeader: + case *binlogpb.GrpcLogEntry_ServerHeader: m.PayloadTruncated = ml.truncateMetadata(pay.ServerHeader.GetMetadata()) - case *pb.GrpcLogEntry_Message: + case *binlogpb.GrpcLogEntry_Message: m.PayloadTruncated = ml.truncateMessage(pay.Message) } + return m +} - ml.sink.Write(m) +// Log creates a proto binary log entry, and logs it to the sink. +func (ml *TruncatingMethodLogger) Log(ctx context.Context, c LogEntryConfig) { + ml.sink.Write(ml.Build(c)) } -func (ml *MethodLogger) truncateMetadata(mdPb *pb.Metadata) (truncated bool) { +func (ml *TruncatingMethodLogger) truncateMetadata(mdPb *binlogpb.Metadata) (truncated bool) { if ml.headerMaxLen == maxUInt { return false } @@ -108,7 +128,7 @@ func (ml *MethodLogger) truncateMetadata(mdPb *pb.Metadata) (truncated bool) { // but not counted towards the size limit. continue } - currentEntryLen := uint64(len(entry.Value)) + currentEntryLen := uint64(len(entry.GetKey())) + uint64(len(entry.GetValue())) if currentEntryLen > bytesLimit { break } @@ -119,7 +139,7 @@ func (ml *MethodLogger) truncateMetadata(mdPb *pb.Metadata) (truncated bool) { return truncated } -func (ml *MethodLogger) truncateMessage(msgPb *pb.Message) (truncated bool) { +func (ml *TruncatingMethodLogger) truncateMessage(msgPb *binlogpb.Message) (truncated bool) { if ml.messageMaxLen == maxUInt { return false } @@ -131,8 +151,11 @@ func (ml *MethodLogger) truncateMessage(msgPb *pb.Message) (truncated bool) { } // LogEntryConfig represents the configuration for binary log entry. +// +// This is used in the 1.0 release of gcp/observability, and thus must not be +// deleted or changed. type LogEntryConfig interface { - toProto() *pb.GrpcLogEntry + toProto() *binlogpb.GrpcLogEntry } // ClientHeader configs the binary log entry to be a ClientHeader entry. @@ -146,10 +169,10 @@ type ClientHeader struct { PeerAddr net.Addr } -func (c *ClientHeader) toProto() *pb.GrpcLogEntry { +func (c *ClientHeader) toProto() *binlogpb.GrpcLogEntry { // This function doesn't need to set all the fields (e.g. seq ID). The Log // function will set the fields when necessary. - clientHeader := &pb.ClientHeader{ + clientHeader := &binlogpb.ClientHeader{ Metadata: mdToMetadataProto(c.Header), MethodName: c.MethodName, Authority: c.Authority, @@ -157,16 +180,16 @@ func (c *ClientHeader) toProto() *pb.GrpcLogEntry { if c.Timeout > 0 { clientHeader.Timeout = ptypes.DurationProto(c.Timeout) } - ret := &pb.GrpcLogEntry{ - Type: pb.GrpcLogEntry_EVENT_TYPE_CLIENT_HEADER, - Payload: &pb.GrpcLogEntry_ClientHeader{ + ret := &binlogpb.GrpcLogEntry{ + Type: binlogpb.GrpcLogEntry_EVENT_TYPE_CLIENT_HEADER, + Payload: &binlogpb.GrpcLogEntry_ClientHeader{ ClientHeader: clientHeader, }, } if c.OnClientSide { - ret.Logger = pb.GrpcLogEntry_LOGGER_CLIENT + ret.Logger = binlogpb.GrpcLogEntry_LOGGER_CLIENT } else { - ret.Logger = pb.GrpcLogEntry_LOGGER_SERVER + ret.Logger = binlogpb.GrpcLogEntry_LOGGER_SERVER } if c.PeerAddr != nil { ret.Peer = addrToProto(c.PeerAddr) @@ -182,19 +205,19 @@ type ServerHeader struct { PeerAddr net.Addr } -func (c *ServerHeader) toProto() *pb.GrpcLogEntry { - ret := &pb.GrpcLogEntry{ - Type: pb.GrpcLogEntry_EVENT_TYPE_SERVER_HEADER, - Payload: &pb.GrpcLogEntry_ServerHeader{ - ServerHeader: &pb.ServerHeader{ +func (c *ServerHeader) toProto() *binlogpb.GrpcLogEntry { + ret := &binlogpb.GrpcLogEntry{ + Type: binlogpb.GrpcLogEntry_EVENT_TYPE_SERVER_HEADER, + Payload: &binlogpb.GrpcLogEntry_ServerHeader{ + ServerHeader: &binlogpb.ServerHeader{ Metadata: mdToMetadataProto(c.Header), }, }, } if c.OnClientSide { - ret.Logger = pb.GrpcLogEntry_LOGGER_CLIENT + ret.Logger = binlogpb.GrpcLogEntry_LOGGER_CLIENT } else { - ret.Logger = pb.GrpcLogEntry_LOGGER_SERVER + ret.Logger = binlogpb.GrpcLogEntry_LOGGER_SERVER } if c.PeerAddr != nil { ret.Peer = addrToProto(c.PeerAddr) @@ -210,7 +233,7 @@ type ClientMessage struct { Message interface{} } -func (c *ClientMessage) toProto() *pb.GrpcLogEntry { +func (c *ClientMessage) toProto() *binlogpb.GrpcLogEntry { var ( data []byte err error @@ -225,19 +248,19 @@ func (c *ClientMessage) toProto() *pb.GrpcLogEntry { } else { grpclogLogger.Infof("binarylogging: message to log is neither proto.message nor []byte") } - ret := &pb.GrpcLogEntry{ - Type: pb.GrpcLogEntry_EVENT_TYPE_CLIENT_MESSAGE, - Payload: &pb.GrpcLogEntry_Message{ - Message: &pb.Message{ + ret := &binlogpb.GrpcLogEntry{ + Type: binlogpb.GrpcLogEntry_EVENT_TYPE_CLIENT_MESSAGE, + Payload: &binlogpb.GrpcLogEntry_Message{ + Message: &binlogpb.Message{ Length: uint32(len(data)), Data: data, }, }, } if c.OnClientSide { - ret.Logger = pb.GrpcLogEntry_LOGGER_CLIENT + ret.Logger = binlogpb.GrpcLogEntry_LOGGER_CLIENT } else { - ret.Logger = pb.GrpcLogEntry_LOGGER_SERVER + ret.Logger = binlogpb.GrpcLogEntry_LOGGER_SERVER } return ret } @@ -250,7 +273,7 @@ type ServerMessage struct { Message interface{} } -func (c *ServerMessage) toProto() *pb.GrpcLogEntry { +func (c *ServerMessage) toProto() *binlogpb.GrpcLogEntry { var ( data []byte err error @@ -265,19 +288,19 @@ func (c *ServerMessage) toProto() *pb.GrpcLogEntry { } else { grpclogLogger.Infof("binarylogging: message to log is neither proto.message nor []byte") } - ret := &pb.GrpcLogEntry{ - Type: pb.GrpcLogEntry_EVENT_TYPE_SERVER_MESSAGE, - Payload: &pb.GrpcLogEntry_Message{ - Message: &pb.Message{ + ret := &binlogpb.GrpcLogEntry{ + Type: binlogpb.GrpcLogEntry_EVENT_TYPE_SERVER_MESSAGE, + Payload: &binlogpb.GrpcLogEntry_Message{ + Message: &binlogpb.Message{ Length: uint32(len(data)), Data: data, }, }, } if c.OnClientSide { - ret.Logger = pb.GrpcLogEntry_LOGGER_CLIENT + ret.Logger = binlogpb.GrpcLogEntry_LOGGER_CLIENT } else { - ret.Logger = pb.GrpcLogEntry_LOGGER_SERVER + ret.Logger = binlogpb.GrpcLogEntry_LOGGER_SERVER } return ret } @@ -287,15 +310,15 @@ type ClientHalfClose struct { OnClientSide bool } -func (c *ClientHalfClose) toProto() *pb.GrpcLogEntry { - ret := &pb.GrpcLogEntry{ - Type: pb.GrpcLogEntry_EVENT_TYPE_CLIENT_HALF_CLOSE, +func (c *ClientHalfClose) toProto() *binlogpb.GrpcLogEntry { + ret := &binlogpb.GrpcLogEntry{ + Type: binlogpb.GrpcLogEntry_EVENT_TYPE_CLIENT_HALF_CLOSE, Payload: nil, // No payload here. } if c.OnClientSide { - ret.Logger = pb.GrpcLogEntry_LOGGER_CLIENT + ret.Logger = binlogpb.GrpcLogEntry_LOGGER_CLIENT } else { - ret.Logger = pb.GrpcLogEntry_LOGGER_SERVER + ret.Logger = binlogpb.GrpcLogEntry_LOGGER_SERVER } return ret } @@ -311,7 +334,7 @@ type ServerTrailer struct { PeerAddr net.Addr } -func (c *ServerTrailer) toProto() *pb.GrpcLogEntry { +func (c *ServerTrailer) toProto() *binlogpb.GrpcLogEntry { st, ok := status.FromError(c.Err) if !ok { grpclogLogger.Info("binarylogging: error in trailer is not a status error") @@ -327,10 +350,10 @@ func (c *ServerTrailer) toProto() *pb.GrpcLogEntry { grpclogLogger.Infof("binarylogging: failed to marshal status proto: %v", err) } } - ret := &pb.GrpcLogEntry{ - Type: pb.GrpcLogEntry_EVENT_TYPE_SERVER_TRAILER, - Payload: &pb.GrpcLogEntry_Trailer{ - Trailer: &pb.Trailer{ + ret := &binlogpb.GrpcLogEntry{ + Type: binlogpb.GrpcLogEntry_EVENT_TYPE_SERVER_TRAILER, + Payload: &binlogpb.GrpcLogEntry_Trailer{ + Trailer: &binlogpb.Trailer{ Metadata: mdToMetadataProto(c.Trailer), StatusCode: uint32(st.Code()), StatusMessage: st.Message(), @@ -339,9 +362,9 @@ func (c *ServerTrailer) toProto() *pb.GrpcLogEntry { }, } if c.OnClientSide { - ret.Logger = pb.GrpcLogEntry_LOGGER_CLIENT + ret.Logger = binlogpb.GrpcLogEntry_LOGGER_CLIENT } else { - ret.Logger = pb.GrpcLogEntry_LOGGER_SERVER + ret.Logger = binlogpb.GrpcLogEntry_LOGGER_SERVER } if c.PeerAddr != nil { ret.Peer = addrToProto(c.PeerAddr) @@ -354,15 +377,15 @@ type Cancel struct { OnClientSide bool } -func (c *Cancel) toProto() *pb.GrpcLogEntry { - ret := &pb.GrpcLogEntry{ - Type: pb.GrpcLogEntry_EVENT_TYPE_CANCEL, +func (c *Cancel) toProto() *binlogpb.GrpcLogEntry { + ret := &binlogpb.GrpcLogEntry{ + Type: binlogpb.GrpcLogEntry_EVENT_TYPE_CANCEL, Payload: nil, } if c.OnClientSide { - ret.Logger = pb.GrpcLogEntry_LOGGER_CLIENT + ret.Logger = binlogpb.GrpcLogEntry_LOGGER_CLIENT } else { - ret.Logger = pb.GrpcLogEntry_LOGGER_SERVER + ret.Logger = binlogpb.GrpcLogEntry_LOGGER_SERVER } return ret } @@ -379,15 +402,15 @@ func metadataKeyOmit(key string) bool { return strings.HasPrefix(key, "grpc-") } -func mdToMetadataProto(md metadata.MD) *pb.Metadata { - ret := &pb.Metadata{} +func mdToMetadataProto(md metadata.MD) *binlogpb.Metadata { + ret := &binlogpb.Metadata{} for k, vv := range md { if metadataKeyOmit(k) { continue } for _, v := range vv { ret.Entry = append(ret.Entry, - &pb.MetadataEntry{ + &binlogpb.MetadataEntry{ Key: k, Value: []byte(v), }, @@ -397,26 +420,26 @@ func mdToMetadataProto(md metadata.MD) *pb.Metadata { return ret } -func addrToProto(addr net.Addr) *pb.Address { - ret := &pb.Address{} +func addrToProto(addr net.Addr) *binlogpb.Address { + ret := &binlogpb.Address{} switch a := addr.(type) { case *net.TCPAddr: if a.IP.To4() != nil { - ret.Type = pb.Address_TYPE_IPV4 + ret.Type = binlogpb.Address_TYPE_IPV4 } else if a.IP.To16() != nil { - ret.Type = pb.Address_TYPE_IPV6 + ret.Type = binlogpb.Address_TYPE_IPV6 } else { - ret.Type = pb.Address_TYPE_UNKNOWN + ret.Type = binlogpb.Address_TYPE_UNKNOWN // Do not set address and port fields. break } ret.Address = a.IP.String() ret.IpPort = uint32(a.Port) case *net.UnixAddr: - ret.Type = pb.Address_TYPE_UNIX + ret.Type = binlogpb.Address_TYPE_UNIX ret.Address = a.String() default: - ret.Type = pb.Address_TYPE_UNKNOWN + ret.Type = binlogpb.Address_TYPE_UNKNOWN } return ret } diff --git a/vendor/google.golang.org/grpc/internal/binarylog/sink.go b/vendor/google.golang.org/grpc/internal/binarylog/sink.go index 7d7a3056b71..264de387c2a 100644 --- a/vendor/google.golang.org/grpc/internal/binarylog/sink.go +++ b/vendor/google.golang.org/grpc/internal/binarylog/sink.go @@ -26,7 +26,7 @@ import ( "time" "github.com/golang/protobuf/proto" - pb "google.golang.org/grpc/binarylog/grpc_binarylog_v1" + binlogpb "google.golang.org/grpc/binarylog/grpc_binarylog_v1" ) var ( @@ -42,15 +42,15 @@ type Sink interface { // Write will be called to write the log entry into the sink. // // It should be thread-safe so it can be called in parallel. - Write(*pb.GrpcLogEntry) error + Write(*binlogpb.GrpcLogEntry) error // Close will be called when the Sink is replaced by a new Sink. Close() error } type noopSink struct{} -func (ns *noopSink) Write(*pb.GrpcLogEntry) error { return nil } -func (ns *noopSink) Close() error { return nil } +func (ns *noopSink) Write(*binlogpb.GrpcLogEntry) error { return nil } +func (ns *noopSink) Close() error { return nil } // newWriterSink creates a binary log sink with the given writer. // @@ -66,10 +66,11 @@ type writerSink struct { out io.Writer } -func (ws *writerSink) Write(e *pb.GrpcLogEntry) error { +func (ws *writerSink) Write(e *binlogpb.GrpcLogEntry) error { b, err := proto.Marshal(e) if err != nil { - grpclogLogger.Infof("binary logging: failed to marshal proto message: %v", err) + grpclogLogger.Errorf("binary logging: failed to marshal proto message: %v", err) + return err } hdr := make([]byte, 4) binary.BigEndian.PutUint32(hdr, uint32(len(b))) @@ -85,24 +86,27 @@ func (ws *writerSink) Write(e *pb.GrpcLogEntry) error { func (ws *writerSink) Close() error { return nil } type bufferedSink struct { - mu sync.Mutex - closer io.Closer - out Sink // out is built on buf. - buf *bufio.Writer // buf is kept for flush. - - writeStartOnce sync.Once - writeTicker *time.Ticker + mu sync.Mutex + closer io.Closer + out Sink // out is built on buf. + buf *bufio.Writer // buf is kept for flush. + flusherStarted bool + + writeTicker *time.Ticker + done chan struct{} } -func (fs *bufferedSink) Write(e *pb.GrpcLogEntry) error { - // Start the write loop when Write is called. - fs.writeStartOnce.Do(fs.startFlushGoroutine) +func (fs *bufferedSink) Write(e *binlogpb.GrpcLogEntry) error { fs.mu.Lock() + defer fs.mu.Unlock() + if !fs.flusherStarted { + // Start the write loop when Write is called. + fs.startFlushGoroutine() + fs.flusherStarted = true + } if err := fs.out.Write(e); err != nil { - fs.mu.Unlock() return err } - fs.mu.Unlock() return nil } @@ -113,7 +117,12 @@ const ( func (fs *bufferedSink) startFlushGoroutine() { fs.writeTicker = time.NewTicker(bufFlushDuration) go func() { - for range fs.writeTicker.C { + for { + select { + case <-fs.done: + return + case <-fs.writeTicker.C: + } fs.mu.Lock() if err := fs.buf.Flush(); err != nil { grpclogLogger.Warningf("failed to flush to Sink: %v", err) @@ -124,10 +133,12 @@ func (fs *bufferedSink) startFlushGoroutine() { } func (fs *bufferedSink) Close() error { + fs.mu.Lock() + defer fs.mu.Unlock() if fs.writeTicker != nil { fs.writeTicker.Stop() } - fs.mu.Lock() + close(fs.done) if err := fs.buf.Flush(); err != nil { grpclogLogger.Warningf("failed to flush to Sink: %v", err) } @@ -137,7 +148,6 @@ func (fs *bufferedSink) Close() error { if err := fs.out.Close(); err != nil { grpclogLogger.Warningf("failed to close the Sink: %v", err) } - fs.mu.Unlock() return nil } @@ -155,5 +165,6 @@ func NewBufferedSink(o io.WriteCloser) Sink { closer: o, out: newWriterSink(bufW), buf: bufW, + done: make(chan struct{}), } } diff --git a/vendor/google.golang.org/grpc/internal/buffer/unbounded.go b/vendor/google.golang.org/grpc/internal/buffer/unbounded.go index 9f6a0c1200d..81c2f5fd761 100644 --- a/vendor/google.golang.org/grpc/internal/buffer/unbounded.go +++ b/vendor/google.golang.org/grpc/internal/buffer/unbounded.go @@ -35,6 +35,7 @@ import "sync" // internal/transport/transport.go for an example of this. type Unbounded struct { c chan interface{} + closed bool mu sync.Mutex backlog []interface{} } @@ -47,16 +48,18 @@ func NewUnbounded() *Unbounded { // Put adds t to the unbounded buffer. func (b *Unbounded) Put(t interface{}) { b.mu.Lock() + defer b.mu.Unlock() + if b.closed { + return + } if len(b.backlog) == 0 { select { case b.c <- t: - b.mu.Unlock() return default: } } b.backlog = append(b.backlog, t) - b.mu.Unlock() } // Load sends the earliest buffered data, if any, onto the read channel @@ -64,6 +67,10 @@ func (b *Unbounded) Put(t interface{}) { // value from the read channel. func (b *Unbounded) Load() { b.mu.Lock() + defer b.mu.Unlock() + if b.closed { + return + } if len(b.backlog) > 0 { select { case b.c <- b.backlog[0]: @@ -72,7 +79,6 @@ func (b *Unbounded) Load() { default: } } - b.mu.Unlock() } // Get returns a read channel on which values added to the buffer, via Put(), @@ -80,6 +86,20 @@ func (b *Unbounded) Load() { // // Upon reading a value from this channel, users are expected to call Load() to // send the next buffered value onto the channel if there is any. +// +// If the unbounded buffer is closed, the read channel returned by this method +// is closed. func (b *Unbounded) Get() <-chan interface{} { return b.c } + +// Close closes the unbounded buffer. +func (b *Unbounded) Close() { + b.mu.Lock() + defer b.mu.Unlock() + if b.closed { + return + } + b.closed = true + close(b.c) +} diff --git a/vendor/google.golang.org/grpc/internal/channelz/funcs.go b/vendor/google.golang.org/grpc/internal/channelz/funcs.go index f7314139303..777cbcd7921 100644 --- a/vendor/google.golang.org/grpc/internal/channelz/funcs.go +++ b/vendor/google.golang.org/grpc/internal/channelz/funcs.go @@ -24,6 +24,8 @@ package channelz import ( + "context" + "errors" "fmt" "sort" "sync" @@ -49,7 +51,8 @@ var ( // TurnOn turns on channelz data collection. func TurnOn() { if !IsOn() { - NewChannelzStorage() + db.set(newChannelMap()) + idGen.reset() atomic.StoreInt32(&curState, 1) } } @@ -94,46 +97,40 @@ func (d *dbWrapper) get() *channelMap { return d.DB } -// NewChannelzStorage initializes channelz data storage and id generator. +// NewChannelzStorageForTesting initializes channelz data storage and id +// generator for testing purposes. // -// This function returns a cleanup function to wait for all channelz state to be reset by the -// grpc goroutines when those entities get closed. By using this cleanup function, we make sure tests -// don't mess up each other, i.e. lingering goroutine from previous test doing entity removal happen -// to remove some entity just register by the new test, since the id space is the same. -// -// Note: This function is exported for testing purpose only. User should not call -// it in most cases. -func NewChannelzStorage() (cleanup func() error) { - db.set(&channelMap{ - topLevelChannels: make(map[int64]struct{}), - channels: make(map[int64]*channel), - listenSockets: make(map[int64]*listenSocket), - normalSockets: make(map[int64]*normalSocket), - servers: make(map[int64]*server), - subChannels: make(map[int64]*subChannel), - }) +// Returns a cleanup function to be invoked by the test, which waits for up to +// 10s for all channelz state to be reset by the grpc goroutines when those +// entities get closed. This cleanup function helps with ensuring that tests +// don't mess up each other. +func NewChannelzStorageForTesting() (cleanup func() error) { + db.set(newChannelMap()) idGen.reset() + return func() error { - var err error cm := db.get() if cm == nil { return nil } - for i := 0; i < 1000; i++ { - cm.mu.Lock() - if len(cm.topLevelChannels) == 0 && len(cm.servers) == 0 && len(cm.channels) == 0 && len(cm.subChannels) == 0 && len(cm.listenSockets) == 0 && len(cm.normalSockets) == 0 { - cm.mu.Unlock() - // all things stored in the channelz map have been cleared. + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + ticker := time.NewTicker(10 * time.Millisecond) + defer ticker.Stop() + for { + cm.mu.RLock() + topLevelChannels, servers, channels, subChannels, listenSockets, normalSockets := len(cm.topLevelChannels), len(cm.servers), len(cm.channels), len(cm.subChannels), len(cm.listenSockets), len(cm.normalSockets) + cm.mu.RUnlock() + + if err := ctx.Err(); err != nil { + return fmt.Errorf("after 10s the channelz map has not been cleaned up yet, topchannels: %d, servers: %d, channels: %d, subchannels: %d, listen sockets: %d, normal sockets: %d", topLevelChannels, servers, channels, subChannels, listenSockets, normalSockets) + } + if topLevelChannels == 0 && servers == 0 && channels == 0 && subChannels == 0 && listenSockets == 0 && normalSockets == 0 { return nil } - cm.mu.Unlock() - time.Sleep(10 * time.Millisecond) + <-ticker.C } - - cm.mu.Lock() - err = fmt.Errorf("after 10s the channelz map has not been cleaned up yet, topchannels: %d, servers: %d, channels: %d, subchannels: %d, listen sockets: %d, normal sockets: %d", len(cm.topLevelChannels), len(cm.servers), len(cm.channels), len(cm.subChannels), len(cm.listenSockets), len(cm.normalSockets)) - cm.mu.Unlock() - return err } } @@ -188,54 +185,77 @@ func GetServer(id int64) *ServerMetric { return db.get().GetServer(id) } -// RegisterChannel registers the given channel c in channelz database with ref -// as its reference name, and add it to the child list of its parent (identified -// by pid). pid = 0 means no parent. It returns the unique channelz tracking id -// assigned to this channel. -func RegisterChannel(c Channel, pid int64, ref string) int64 { +// RegisterChannel registers the given channel c in the channelz database with +// ref as its reference name, and adds it to the child list of its parent +// (identified by pid). pid == nil means no parent. +// +// Returns a unique channelz identifier assigned to this channel. +// +// If channelz is not turned ON, the channelz database is not mutated. +func RegisterChannel(c Channel, pid *Identifier, ref string) *Identifier { id := idGen.genID() + var parent int64 + isTopChannel := true + if pid != nil { + isTopChannel = false + parent = pid.Int() + } + + if !IsOn() { + return newIdentifer(RefChannel, id, pid) + } + cn := &channel{ refName: ref, c: c, subChans: make(map[int64]string), nestedChans: make(map[int64]string), id: id, - pid: pid, + pid: parent, trace: &channelTrace{createdTime: time.Now(), events: make([]*TraceEvent, 0, getMaxTraceEntry())}, } - if pid == 0 { - db.get().addChannel(id, cn, true, pid, ref) - } else { - db.get().addChannel(id, cn, false, pid, ref) - } - return id + db.get().addChannel(id, cn, isTopChannel, parent) + return newIdentifer(RefChannel, id, pid) } -// RegisterSubChannel registers the given channel c in channelz database with ref -// as its reference name, and add it to the child list of its parent (identified -// by pid). It returns the unique channelz tracking id assigned to this subchannel. -func RegisterSubChannel(c Channel, pid int64, ref string) int64 { - if pid == 0 { - logger.Error("a SubChannel's parent id cannot be 0") - return 0 +// RegisterSubChannel registers the given subChannel c in the channelz database +// with ref as its reference name, and adds it to the child list of its parent +// (identified by pid). +// +// Returns a unique channelz identifier assigned to this subChannel. +// +// If channelz is not turned ON, the channelz database is not mutated. +func RegisterSubChannel(c Channel, pid *Identifier, ref string) (*Identifier, error) { + if pid == nil { + return nil, errors.New("a SubChannel's parent id cannot be nil") } id := idGen.genID() + if !IsOn() { + return newIdentifer(RefSubChannel, id, pid), nil + } + sc := &subChannel{ refName: ref, c: c, sockets: make(map[int64]string), id: id, - pid: pid, + pid: pid.Int(), trace: &channelTrace{createdTime: time.Now(), events: make([]*TraceEvent, 0, getMaxTraceEntry())}, } - db.get().addSubChannel(id, sc, pid, ref) - return id + db.get().addSubChannel(id, sc, pid.Int()) + return newIdentifer(RefSubChannel, id, pid), nil } // RegisterServer registers the given server s in channelz database. It returns // the unique channelz tracking id assigned to this server. -func RegisterServer(s Server, ref string) int64 { +// +// If channelz is not turned ON, the channelz database is not mutated. +func RegisterServer(s Server, ref string) *Identifier { id := idGen.genID() + if !IsOn() { + return newIdentifer(RefServer, id, nil) + } + svr := &server{ refName: ref, s: s, @@ -244,71 +264,92 @@ func RegisterServer(s Server, ref string) int64 { id: id, } db.get().addServer(id, svr) - return id + return newIdentifer(RefServer, id, nil) } // RegisterListenSocket registers the given listen socket s in channelz database // with ref as its reference name, and add it to the child list of its parent // (identified by pid). It returns the unique channelz tracking id assigned to // this listen socket. -func RegisterListenSocket(s Socket, pid int64, ref string) int64 { - if pid == 0 { - logger.Error("a ListenSocket's parent id cannot be 0") - return 0 +// +// If channelz is not turned ON, the channelz database is not mutated. +func RegisterListenSocket(s Socket, pid *Identifier, ref string) (*Identifier, error) { + if pid == nil { + return nil, errors.New("a ListenSocket's parent id cannot be 0") } id := idGen.genID() - ls := &listenSocket{refName: ref, s: s, id: id, pid: pid} - db.get().addListenSocket(id, ls, pid, ref) - return id + if !IsOn() { + return newIdentifer(RefListenSocket, id, pid), nil + } + + ls := &listenSocket{refName: ref, s: s, id: id, pid: pid.Int()} + db.get().addListenSocket(id, ls, pid.Int()) + return newIdentifer(RefListenSocket, id, pid), nil } // RegisterNormalSocket registers the given normal socket s in channelz database -// with ref as its reference name, and add it to the child list of its parent +// with ref as its reference name, and adds it to the child list of its parent // (identified by pid). It returns the unique channelz tracking id assigned to // this normal socket. -func RegisterNormalSocket(s Socket, pid int64, ref string) int64 { - if pid == 0 { - logger.Error("a NormalSocket's parent id cannot be 0") - return 0 +// +// If channelz is not turned ON, the channelz database is not mutated. +func RegisterNormalSocket(s Socket, pid *Identifier, ref string) (*Identifier, error) { + if pid == nil { + return nil, errors.New("a NormalSocket's parent id cannot be 0") } id := idGen.genID() - ns := &normalSocket{refName: ref, s: s, id: id, pid: pid} - db.get().addNormalSocket(id, ns, pid, ref) - return id + if !IsOn() { + return newIdentifer(RefNormalSocket, id, pid), nil + } + + ns := &normalSocket{refName: ref, s: s, id: id, pid: pid.Int()} + db.get().addNormalSocket(id, ns, pid.Int()) + return newIdentifer(RefNormalSocket, id, pid), nil } -// RemoveEntry removes an entry with unique channelz trakcing id to be id from +// RemoveEntry removes an entry with unique channelz tracking id to be id from // channelz database. -func RemoveEntry(id int64) { - db.get().removeEntry(id) +// +// If channelz is not turned ON, this function is a no-op. +func RemoveEntry(id *Identifier) { + if !IsOn() { + return + } + db.get().removeEntry(id.Int()) } -// TraceEventDesc is what the caller of AddTraceEvent should provide to describe the event to be added -// to the channel trace. -// The Parent field is optional. It is used for event that will be recorded in the entity's parent -// trace also. +// TraceEventDesc is what the caller of AddTraceEvent should provide to describe +// the event to be added to the channel trace. +// +// The Parent field is optional. It is used for an event that will be recorded +// in the entity's parent trace. type TraceEventDesc struct { Desc string Severity Severity Parent *TraceEventDesc } -// AddTraceEvent adds trace related to the entity with specified id, using the provided TraceEventDesc. -func AddTraceEvent(l grpclog.DepthLoggerV2, id int64, depth int, desc *TraceEventDesc) { - for d := desc; d != nil; d = d.Parent { - switch d.Severity { - case CtUnknown, CtInfo: - l.InfoDepth(depth+1, d.Desc) - case CtWarning: - l.WarningDepth(depth+1, d.Desc) - case CtError: - l.ErrorDepth(depth+1, d.Desc) - } +// AddTraceEvent adds trace related to the entity with specified id, using the +// provided TraceEventDesc. +// +// If channelz is not turned ON, this will simply log the event descriptions. +func AddTraceEvent(l grpclog.DepthLoggerV2, id *Identifier, depth int, desc *TraceEventDesc) { + // Log only the trace description associated with the bottom most entity. + switch desc.Severity { + case CtUnknown, CtInfo: + l.InfoDepth(depth+1, withParens(id)+desc.Desc) + case CtWarning: + l.WarningDepth(depth+1, withParens(id)+desc.Desc) + case CtError: + l.ErrorDepth(depth+1, withParens(id)+desc.Desc) } + if getMaxTraceEntry() == 0 { return } - db.get().traceEvent(id, desc) + if IsOn() { + db.get().traceEvent(id.Int(), desc) + } } // channelMap is the storage data structure for channelz. @@ -326,6 +367,17 @@ type channelMap struct { normalSockets map[int64]*normalSocket } +func newChannelMap() *channelMap { + return &channelMap{ + topLevelChannels: make(map[int64]struct{}), + channels: make(map[int64]*channel), + listenSockets: make(map[int64]*listenSocket), + normalSockets: make(map[int64]*normalSocket), + servers: make(map[int64]*server), + subChannels: make(map[int64]*subChannel), + } +} + func (c *channelMap) addServer(id int64, s *server) { c.mu.Lock() s.cm = c @@ -333,7 +385,7 @@ func (c *channelMap) addServer(id int64, s *server) { c.mu.Unlock() } -func (c *channelMap) addChannel(id int64, cn *channel, isTopChannel bool, pid int64, ref string) { +func (c *channelMap) addChannel(id int64, cn *channel, isTopChannel bool, pid int64) { c.mu.Lock() cn.cm = c cn.trace.cm = c @@ -346,7 +398,7 @@ func (c *channelMap) addChannel(id int64, cn *channel, isTopChannel bool, pid in c.mu.Unlock() } -func (c *channelMap) addSubChannel(id int64, sc *subChannel, pid int64, ref string) { +func (c *channelMap) addSubChannel(id int64, sc *subChannel, pid int64) { c.mu.Lock() sc.cm = c sc.trace.cm = c @@ -355,7 +407,7 @@ func (c *channelMap) addSubChannel(id int64, sc *subChannel, pid int64, ref stri c.mu.Unlock() } -func (c *channelMap) addListenSocket(id int64, ls *listenSocket, pid int64, ref string) { +func (c *channelMap) addListenSocket(id int64, ls *listenSocket, pid int64) { c.mu.Lock() ls.cm = c c.listenSockets[id] = ls @@ -363,7 +415,7 @@ func (c *channelMap) addListenSocket(id int64, ls *listenSocket, pid int64, ref c.mu.Unlock() } -func (c *channelMap) addNormalSocket(id int64, ns *normalSocket, pid int64, ref string) { +func (c *channelMap) addNormalSocket(id int64, ns *normalSocket, pid int64) { c.mu.Lock() ns.cm = c c.normalSockets[id] = ns @@ -630,7 +682,7 @@ func (c *channelMap) GetServerSockets(id int64, startID int64, maxResults int64) if count == 0 { end = true } - var s []*SocketMetric + s := make([]*SocketMetric, 0, len(sks)) for _, ns := range sks { sm := &SocketMetric{} sm.SocketData = ns.s.ChannelzMetric() diff --git a/vendor/google.golang.org/grpc/internal/channelz/id.go b/vendor/google.golang.org/grpc/internal/channelz/id.go new file mode 100644 index 00000000000..c9a27acd371 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/channelz/id.go @@ -0,0 +1,75 @@ +/* + * + * Copyright 2022 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package channelz + +import "fmt" + +// Identifier is an opaque identifier which uniquely identifies an entity in the +// channelz database. +type Identifier struct { + typ RefChannelType + id int64 + str string + pid *Identifier +} + +// Type returns the entity type corresponding to id. +func (id *Identifier) Type() RefChannelType { + return id.typ +} + +// Int returns the integer identifier corresponding to id. +func (id *Identifier) Int() int64 { + return id.id +} + +// String returns a string representation of the entity corresponding to id. +// +// This includes some information about the parent as well. Examples: +// Top-level channel: [Channel #channel-number] +// Nested channel: [Channel #parent-channel-number Channel #channel-number] +// Sub channel: [Channel #parent-channel SubChannel #subchannel-number] +func (id *Identifier) String() string { + return id.str +} + +// Equal returns true if other is the same as id. +func (id *Identifier) Equal(other *Identifier) bool { + if (id != nil) != (other != nil) { + return false + } + if id == nil && other == nil { + return true + } + return id.typ == other.typ && id.id == other.id && id.pid == other.pid +} + +// NewIdentifierForTesting returns a new opaque identifier to be used only for +// testing purposes. +func NewIdentifierForTesting(typ RefChannelType, id int64, pid *Identifier) *Identifier { + return newIdentifer(typ, id, pid) +} + +func newIdentifer(typ RefChannelType, id int64, pid *Identifier) *Identifier { + str := fmt.Sprintf("%s #%d", typ, id) + if pid != nil { + str = fmt.Sprintf("%s %s", pid, str) + } + return &Identifier{typ: typ, id: id, str: str, pid: pid} +} diff --git a/vendor/google.golang.org/grpc/internal/channelz/logging.go b/vendor/google.golang.org/grpc/internal/channelz/logging.go index b0013f9c886..8e13a3d2ce7 100644 --- a/vendor/google.golang.org/grpc/internal/channelz/logging.go +++ b/vendor/google.golang.org/grpc/internal/channelz/logging.go @@ -26,77 +26,54 @@ import ( var logger = grpclog.Component("channelz") +func withParens(id *Identifier) string { + return "[" + id.String() + "] " +} + // Info logs and adds a trace event if channelz is on. -func Info(l grpclog.DepthLoggerV2, id int64, args ...interface{}) { - if IsOn() { - AddTraceEvent(l, id, 1, &TraceEventDesc{ - Desc: fmt.Sprint(args...), - Severity: CtInfo, - }) - } else { - l.InfoDepth(1, args...) - } +func Info(l grpclog.DepthLoggerV2, id *Identifier, args ...interface{}) { + AddTraceEvent(l, id, 1, &TraceEventDesc{ + Desc: fmt.Sprint(args...), + Severity: CtInfo, + }) } // Infof logs and adds a trace event if channelz is on. -func Infof(l grpclog.DepthLoggerV2, id int64, format string, args ...interface{}) { - msg := fmt.Sprintf(format, args...) - if IsOn() { - AddTraceEvent(l, id, 1, &TraceEventDesc{ - Desc: msg, - Severity: CtInfo, - }) - } else { - l.InfoDepth(1, msg) - } +func Infof(l grpclog.DepthLoggerV2, id *Identifier, format string, args ...interface{}) { + AddTraceEvent(l, id, 1, &TraceEventDesc{ + Desc: fmt.Sprintf(format, args...), + Severity: CtInfo, + }) } // Warning logs and adds a trace event if channelz is on. -func Warning(l grpclog.DepthLoggerV2, id int64, args ...interface{}) { - if IsOn() { - AddTraceEvent(l, id, 1, &TraceEventDesc{ - Desc: fmt.Sprint(args...), - Severity: CtWarning, - }) - } else { - l.WarningDepth(1, args...) - } +func Warning(l grpclog.DepthLoggerV2, id *Identifier, args ...interface{}) { + AddTraceEvent(l, id, 1, &TraceEventDesc{ + Desc: fmt.Sprint(args...), + Severity: CtWarning, + }) } // Warningf logs and adds a trace event if channelz is on. -func Warningf(l grpclog.DepthLoggerV2, id int64, format string, args ...interface{}) { - msg := fmt.Sprintf(format, args...) - if IsOn() { - AddTraceEvent(l, id, 1, &TraceEventDesc{ - Desc: msg, - Severity: CtWarning, - }) - } else { - l.WarningDepth(1, msg) - } +func Warningf(l grpclog.DepthLoggerV2, id *Identifier, format string, args ...interface{}) { + AddTraceEvent(l, id, 1, &TraceEventDesc{ + Desc: fmt.Sprintf(format, args...), + Severity: CtWarning, + }) } // Error logs and adds a trace event if channelz is on. -func Error(l grpclog.DepthLoggerV2, id int64, args ...interface{}) { - if IsOn() { - AddTraceEvent(l, id, 1, &TraceEventDesc{ - Desc: fmt.Sprint(args...), - Severity: CtError, - }) - } else { - l.ErrorDepth(1, args...) - } +func Error(l grpclog.DepthLoggerV2, id *Identifier, args ...interface{}) { + AddTraceEvent(l, id, 1, &TraceEventDesc{ + Desc: fmt.Sprint(args...), + Severity: CtError, + }) } // Errorf logs and adds a trace event if channelz is on. -func Errorf(l grpclog.DepthLoggerV2, id int64, format string, args ...interface{}) { - msg := fmt.Sprintf(format, args...) - if IsOn() { - AddTraceEvent(l, id, 1, &TraceEventDesc{ - Desc: msg, - Severity: CtError, - }) - } else { - l.ErrorDepth(1, msg) - } +func Errorf(l grpclog.DepthLoggerV2, id *Identifier, format string, args ...interface{}) { + AddTraceEvent(l, id, 1, &TraceEventDesc{ + Desc: fmt.Sprintf(format, args...), + Severity: CtError, + }) } diff --git a/vendor/google.golang.org/grpc/internal/channelz/types.go b/vendor/google.golang.org/grpc/internal/channelz/types.go index 3c595d154bd..7b2f350e2e6 100644 --- a/vendor/google.golang.org/grpc/internal/channelz/types.go +++ b/vendor/google.golang.org/grpc/internal/channelz/types.go @@ -273,10 +273,10 @@ func (c *channel) deleteSelfFromMap() (delete bool) { // deleteSelfIfReady tries to delete the channel itself from the channelz database. // The delete process includes two steps: -// 1. delete the channel from the entry relation tree, i.e. delete the channel reference from its -// parent's child list. -// 2. delete the channel from the map, i.e. delete the channel entirely from channelz. Lookup by id -// will return entry not found error. +// 1. delete the channel from the entry relation tree, i.e. delete the channel reference from its +// parent's child list. +// 2. delete the channel from the map, i.e. delete the channel entirely from channelz. Lookup by id +// will return entry not found error. func (c *channel) deleteSelfIfReady() { if !c.deleteSelfFromTree() { return @@ -381,10 +381,10 @@ func (sc *subChannel) deleteSelfFromMap() (delete bool) { // deleteSelfIfReady tries to delete the subchannel itself from the channelz database. // The delete process includes two steps: -// 1. delete the subchannel from the entry relation tree, i.e. delete the subchannel reference from -// its parent's child list. -// 2. delete the subchannel from the map, i.e. delete the subchannel entirely from channelz. Lookup -// by id will return entry not found error. +// 1. delete the subchannel from the entry relation tree, i.e. delete the subchannel reference from +// its parent's child list. +// 2. delete the subchannel from the map, i.e. delete the subchannel entirely from channelz. Lookup +// by id will return entry not found error. func (sc *subChannel) deleteSelfIfReady() { if !sc.deleteSelfFromTree() { return @@ -686,12 +686,33 @@ const ( type RefChannelType int const ( + // RefUnknown indicates an unknown entity type, the zero value for this type. + RefUnknown RefChannelType = iota // RefChannel indicates the referenced entity is a Channel. - RefChannel RefChannelType = iota + RefChannel // RefSubChannel indicates the referenced entity is a SubChannel. RefSubChannel + // RefServer indicates the referenced entity is a Server. + RefServer + // RefListenSocket indicates the referenced entity is a ListenSocket. + RefListenSocket + // RefNormalSocket indicates the referenced entity is a NormalSocket. + RefNormalSocket ) +var refChannelTypeToString = map[RefChannelType]string{ + RefUnknown: "Unknown", + RefChannel: "Channel", + RefSubChannel: "SubChannel", + RefServer: "Server", + RefListenSocket: "ListenSocket", + RefNormalSocket: "NormalSocket", +} + +func (r RefChannelType) String() string { + return refChannelTypeToString[r] +} + func (c *channelTrace) dumpData() *ChannelTrace { c.mu.Lock() ct := &ChannelTrace{EventNum: c.eventCount, CreationTime: c.createdTime} diff --git a/vendor/google.golang.org/grpc/internal/channelz/types_linux.go b/vendor/google.golang.org/grpc/internal/channelz/types_linux.go index 692dd618177..1b1c4cce34a 100644 --- a/vendor/google.golang.org/grpc/internal/channelz/types_linux.go +++ b/vendor/google.golang.org/grpc/internal/channelz/types_linux.go @@ -1,5 +1,3 @@ -// +build !appengine - /* * * Copyright 2018 gRPC authors. diff --git a/vendor/google.golang.org/grpc/internal/channelz/types_nonlinux.go b/vendor/google.golang.org/grpc/internal/channelz/types_nonlinux.go index 19c2fc521dc..8b06eed1ab8 100644 --- a/vendor/google.golang.org/grpc/internal/channelz/types_nonlinux.go +++ b/vendor/google.golang.org/grpc/internal/channelz/types_nonlinux.go @@ -1,4 +1,5 @@ -// +build !linux appengine +//go:build !linux +// +build !linux /* * @@ -37,6 +38,6 @@ type SocketOptionData struct { // Windows OS doesn't support Socket Option func (s *SocketOptionData) Getsockopt(fd uintptr) { once.Do(func() { - logger.Warning("Channelz: socket options are not supported on non-linux os and appengine.") + logger.Warning("Channelz: socket options are not supported on non-linux environments") }) } diff --git a/vendor/google.golang.org/grpc/internal/channelz/util_linux.go b/vendor/google.golang.org/grpc/internal/channelz/util_linux.go index fdf409d55de..8d194e44e1d 100644 --- a/vendor/google.golang.org/grpc/internal/channelz/util_linux.go +++ b/vendor/google.golang.org/grpc/internal/channelz/util_linux.go @@ -1,5 +1,3 @@ -// +build linux,!appengine - /* * * Copyright 2018 gRPC authors. diff --git a/vendor/google.golang.org/grpc/internal/channelz/util_nonlinux.go b/vendor/google.golang.org/grpc/internal/channelz/util_nonlinux.go index 8864a081116..837ddc40240 100644 --- a/vendor/google.golang.org/grpc/internal/channelz/util_nonlinux.go +++ b/vendor/google.golang.org/grpc/internal/channelz/util_nonlinux.go @@ -1,4 +1,5 @@ -// +build !linux appengine +//go:build !linux +// +build !linux /* * diff --git a/vendor/google.golang.org/grpc/internal/credentials/credentials.go b/vendor/google.golang.org/grpc/internal/credentials/credentials.go new file mode 100644 index 00000000000..32c9b59033c --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/credentials/credentials.go @@ -0,0 +1,49 @@ +/* + * Copyright 2021 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package credentials + +import ( + "context" +) + +// requestInfoKey is a struct to be used as the key to store RequestInfo in a +// context. +type requestInfoKey struct{} + +// NewRequestInfoContext creates a context with ri. +func NewRequestInfoContext(ctx context.Context, ri interface{}) context.Context { + return context.WithValue(ctx, requestInfoKey{}, ri) +} + +// RequestInfoFromContext extracts the RequestInfo from ctx. +func RequestInfoFromContext(ctx context.Context) interface{} { + return ctx.Value(requestInfoKey{}) +} + +// clientHandshakeInfoKey is a struct used as the key to store +// ClientHandshakeInfo in a context. +type clientHandshakeInfoKey struct{} + +// ClientHandshakeInfoFromContext extracts the ClientHandshakeInfo from ctx. +func ClientHandshakeInfoFromContext(ctx context.Context) interface{} { + return ctx.Value(clientHandshakeInfoKey{}) +} + +// NewClientHandshakeInfoContext creates a context with chi. +func NewClientHandshakeInfoContext(ctx context.Context, chi interface{}) context.Context { + return context.WithValue(ctx, clientHandshakeInfoKey{}, chi) +} diff --git a/vendor/google.golang.org/grpc/internal/credentials/spiffe.go b/vendor/google.golang.org/grpc/internal/credentials/spiffe.go index be70b6cdfc3..25ade623058 100644 --- a/vendor/google.golang.org/grpc/internal/credentials/spiffe.go +++ b/vendor/google.golang.org/grpc/internal/credentials/spiffe.go @@ -1,5 +1,3 @@ -// +build !appengine - /* * * Copyright 2020 gRPC authors. diff --git a/vendor/google.golang.org/grpc/internal/credentials/syscallconn.go b/vendor/google.golang.org/grpc/internal/credentials/syscallconn.go index f499a614c20..2919632d657 100644 --- a/vendor/google.golang.org/grpc/internal/credentials/syscallconn.go +++ b/vendor/google.golang.org/grpc/internal/credentials/syscallconn.go @@ -1,5 +1,3 @@ -// +build !appengine - /* * * Copyright 2018 gRPC authors. diff --git a/vendor/google.golang.org/grpc/internal/credentials/util.go b/vendor/google.golang.org/grpc/internal/credentials/util.go index 55664fa46b8..f792fd22caf 100644 --- a/vendor/google.golang.org/grpc/internal/credentials/util.go +++ b/vendor/google.golang.org/grpc/internal/credentials/util.go @@ -18,7 +18,9 @@ package credentials -import "crypto/tls" +import ( + "crypto/tls" +) const alpnProtoStrH2 = "h2" diff --git a/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go b/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go index 73931a94bca..80fd5c7d2a4 100644 --- a/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go +++ b/vendor/google.golang.org/grpc/internal/envconfig/envconfig.go @@ -21,18 +21,46 @@ package envconfig import ( "os" + "strconv" "strings" ) -const ( - prefix = "GRPC_GO_" - retryStr = prefix + "RETRY" - txtErrIgnoreStr = prefix + "IGNORE_TXT_ERRORS" -) - var ( - // Retry is set if retry is explicitly enabled via "GRPC_GO_RETRY=on". - Retry = strings.EqualFold(os.Getenv(retryStr), "on") // TXTErrIgnore is set if TXT errors should be ignored ("GRPC_GO_IGNORE_TXT_ERRORS" is not "false"). - TXTErrIgnore = !strings.EqualFold(os.Getenv(txtErrIgnoreStr), "false") + TXTErrIgnore = boolFromEnv("GRPC_GO_IGNORE_TXT_ERRORS", true) + // AdvertiseCompressors is set if registered compressor should be advertised + // ("GRPC_GO_ADVERTISE_COMPRESSORS" is not "false"). + AdvertiseCompressors = boolFromEnv("GRPC_GO_ADVERTISE_COMPRESSORS", true) + // RingHashCap indicates the maximum ring size which defaults to 4096 + // entries but may be overridden by setting the environment variable + // "GRPC_RING_HASH_CAP". This does not override the default bounds + // checking which NACKs configs specifying ring sizes > 8*1024*1024 (~8M). + RingHashCap = uint64FromEnv("GRPC_RING_HASH_CAP", 4096, 1, 8*1024*1024) + // PickFirstLBConfig is set if we should support configuration of the + // pick_first LB policy, which can be enabled by setting the environment + // variable "GRPC_EXPERIMENTAL_PICKFIRST_LB_CONFIG" to "true". + PickFirstLBConfig = boolFromEnv("GRPC_EXPERIMENTAL_PICKFIRST_LB_CONFIG", false) ) + +func boolFromEnv(envVar string, def bool) bool { + if def { + // The default is true; return true unless the variable is "false". + return !strings.EqualFold(os.Getenv(envVar), "false") + } + // The default is false; return false unless the variable is "true". + return strings.EqualFold(os.Getenv(envVar), "true") +} + +func uint64FromEnv(envVar string, def, min, max uint64) uint64 { + v, err := strconv.ParseUint(os.Getenv(envVar), 10, 64) + if err != nil { + return def + } + if v < min { + return min + } + if v > max { + return max + } + return v +} diff --git a/vendor/google.golang.org/grpc/internal/envconfig/observability.go b/vendor/google.golang.org/grpc/internal/envconfig/observability.go new file mode 100644 index 00000000000..dd314cfb18f --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/envconfig/observability.go @@ -0,0 +1,42 @@ +/* + * + * Copyright 2022 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package envconfig + +import "os" + +const ( + envObservabilityConfig = "GRPC_GCP_OBSERVABILITY_CONFIG" + envObservabilityConfigFile = "GRPC_GCP_OBSERVABILITY_CONFIG_FILE" +) + +var ( + // ObservabilityConfig is the json configuration for the gcp/observability + // package specified directly in the envObservabilityConfig env var. + // + // This is used in the 1.0 release of gcp/observability, and thus must not be + // deleted or changed. + ObservabilityConfig = os.Getenv(envObservabilityConfig) + // ObservabilityConfigFile is the json configuration for the + // gcp/observability specified in a file with the location specified in + // envObservabilityConfigFile env var. + // + // This is used in the 1.0 release of gcp/observability, and thus must not be + // deleted or changed. + ObservabilityConfigFile = os.Getenv(envObservabilityConfigFile) +) diff --git a/vendor/google.golang.org/grpc/internal/envconfig/xds.go b/vendor/google.golang.org/grpc/internal/envconfig/xds.go new file mode 100644 index 00000000000..02b4b6a1c10 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/envconfig/xds.go @@ -0,0 +1,95 @@ +/* + * + * Copyright 2020 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package envconfig + +import ( + "os" +) + +const ( + // XDSBootstrapFileNameEnv is the env variable to set bootstrap file name. + // Do not use this and read from env directly. Its value is read and kept in + // variable XDSBootstrapFileName. + // + // When both bootstrap FileName and FileContent are set, FileName is used. + XDSBootstrapFileNameEnv = "GRPC_XDS_BOOTSTRAP" + // XDSBootstrapFileContentEnv is the env variable to set bootstrap file + // content. Do not use this and read from env directly. Its value is read + // and kept in variable XDSBootstrapFileContent. + // + // When both bootstrap FileName and FileContent are set, FileName is used. + XDSBootstrapFileContentEnv = "GRPC_XDS_BOOTSTRAP_CONFIG" +) + +var ( + // XDSBootstrapFileName holds the name of the file which contains xDS + // bootstrap configuration. Users can specify the location of the bootstrap + // file by setting the environment variable "GRPC_XDS_BOOTSTRAP". + // + // When both bootstrap FileName and FileContent are set, FileName is used. + XDSBootstrapFileName = os.Getenv(XDSBootstrapFileNameEnv) + // XDSBootstrapFileContent holds the content of the xDS bootstrap + // configuration. Users can specify the bootstrap config by setting the + // environment variable "GRPC_XDS_BOOTSTRAP_CONFIG". + // + // When both bootstrap FileName and FileContent are set, FileName is used. + XDSBootstrapFileContent = os.Getenv(XDSBootstrapFileContentEnv) + // XDSRingHash indicates whether ring hash support is enabled, which can be + // disabled by setting the environment variable + // "GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH" to "false". + XDSRingHash = boolFromEnv("GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH", true) + // XDSClientSideSecurity is used to control processing of security + // configuration on the client-side. + // + // Note that there is no env var protection for the server-side because we + // have a brand new API on the server-side and users explicitly need to use + // the new API to get security integration on the server. + XDSClientSideSecurity = boolFromEnv("GRPC_XDS_EXPERIMENTAL_SECURITY_SUPPORT", true) + // XDSAggregateAndDNS indicates whether processing of aggregated cluster and + // DNS cluster is enabled, which can be disabled by setting the environment + // variable "GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER" + // to "false". + XDSAggregateAndDNS = boolFromEnv("GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER", true) + + // XDSRBAC indicates whether xDS configured RBAC HTTP Filter is enabled, + // which can be disabled by setting the environment variable + // "GRPC_XDS_EXPERIMENTAL_RBAC" to "false". + XDSRBAC = boolFromEnv("GRPC_XDS_EXPERIMENTAL_RBAC", true) + // XDSOutlierDetection indicates whether outlier detection support is + // enabled, which can be disabled by setting the environment variable + // "GRPC_EXPERIMENTAL_ENABLE_OUTLIER_DETECTION" to "false". + XDSOutlierDetection = boolFromEnv("GRPC_EXPERIMENTAL_ENABLE_OUTLIER_DETECTION", true) + // XDSFederation indicates whether federation support is enabled, which can + // be enabled by setting the environment variable + // "GRPC_EXPERIMENTAL_XDS_FEDERATION" to "true". + XDSFederation = boolFromEnv("GRPC_EXPERIMENTAL_XDS_FEDERATION", true) + + // XDSRLS indicates whether processing of Cluster Specifier plugins and + // support for the RLS CLuster Specifier is enabled, which can be disabled by + // setting the environment variable "GRPC_EXPERIMENTAL_XDS_RLS_LB" to + // "false". + XDSRLS = boolFromEnv("GRPC_EXPERIMENTAL_XDS_RLS_LB", true) + + // C2PResolverTestOnlyTrafficDirectorURI is the TD URI for testing. + C2PResolverTestOnlyTrafficDirectorURI = os.Getenv("GRPC_TEST_ONLY_GOOGLE_C2P_RESOLVER_TRAFFIC_DIRECTOR_URI") + // XDSCustomLBPolicy indicates whether Custom LB Policies are enabled, which + // can be disabled by setting the environment variable + // "GRPC_EXPERIMENTAL_XDS_CUSTOM_LB_CONFIG" to "false". + XDSCustomLBPolicy = boolFromEnv("GRPC_EXPERIMENTAL_XDS_CUSTOM_LB_CONFIG", true) +) diff --git a/vendor/google.golang.org/grpc/internal/googlecloud/googlecloud.go b/vendor/google.golang.org/grpc/internal/googlecloud/googlecloud.go new file mode 100644 index 00000000000..6717b757f80 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/googlecloud/googlecloud.go @@ -0,0 +1,72 @@ +/* + * + * Copyright 2021 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Package googlecloud contains internal helpful functions for google cloud. +package googlecloud + +import ( + "runtime" + "strings" + "sync" + + "google.golang.org/grpc/grpclog" + internalgrpclog "google.golang.org/grpc/internal/grpclog" +) + +const logPrefix = "[googlecloud]" + +var ( + vmOnGCEOnce sync.Once + vmOnGCE bool + + logger = internalgrpclog.NewPrefixLogger(grpclog.Component("googlecloud"), logPrefix) +) + +// OnGCE returns whether the client is running on GCE. +// +// It provides similar functionality as metadata.OnGCE from the cloud library +// package. We keep this to avoid depending on the cloud library module. +func OnGCE() bool { + vmOnGCEOnce.Do(func() { + mf, err := manufacturer() + if err != nil { + logger.Infof("failed to read manufacturer, setting onGCE=false: %v") + return + } + vmOnGCE = isRunningOnGCE(mf, runtime.GOOS) + }) + return vmOnGCE +} + +// isRunningOnGCE checks whether the local system, without doing a network request, is +// running on GCP. +func isRunningOnGCE(manufacturer []byte, goos string) bool { + name := string(manufacturer) + switch goos { + case "linux": + name = strings.TrimSpace(name) + return name == "Google" || name == "Google Compute Engine" + case "windows": + name = strings.Replace(name, " ", "", -1) + name = strings.Replace(name, "\n", "", -1) + name = strings.Replace(name, "\r", "", -1) + return name == "Google" + default: + return false + } +} diff --git a/vendor/google.golang.org/grpc/internal/credentials/spiffe_appengine.go b/vendor/google.golang.org/grpc/internal/googlecloud/manufacturer.go similarity index 70% rename from vendor/google.golang.org/grpc/internal/credentials/spiffe_appengine.go rename to vendor/google.golang.org/grpc/internal/googlecloud/manufacturer.go index af6f5771976..ffa0f1ddee5 100644 --- a/vendor/google.golang.org/grpc/internal/credentials/spiffe_appengine.go +++ b/vendor/google.golang.org/grpc/internal/googlecloud/manufacturer.go @@ -1,8 +1,9 @@ -// +build appengine +//go:build !(linux || windows) +// +build !linux,!windows /* * - * Copyright 2020 gRPC authors. + * Copyright 2022 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,14 +19,8 @@ * */ -package credentials +package googlecloud -import ( - "crypto/tls" - "net/url" -) - -// SPIFFEIDFromState is a no-op for appengine builds. -func SPIFFEIDFromState(state tls.ConnectionState) *url.URL { - return nil +func manufacturer() ([]byte, error) { + return nil, nil } diff --git a/vendor/google.golang.org/grpc/internal/credentials/syscallconn_appengine.go b/vendor/google.golang.org/grpc/internal/googlecloud/manufacturer_linux.go similarity index 72% rename from vendor/google.golang.org/grpc/internal/credentials/syscallconn_appengine.go rename to vendor/google.golang.org/grpc/internal/googlecloud/manufacturer_linux.go index a6144cd661c..6e455fb0a82 100644 --- a/vendor/google.golang.org/grpc/internal/credentials/syscallconn_appengine.go +++ b/vendor/google.golang.org/grpc/internal/googlecloud/manufacturer_linux.go @@ -1,8 +1,6 @@ -// +build appengine - /* * - * Copyright 2018 gRPC authors. + * Copyright 2022 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,13 +16,12 @@ * */ -package credentials +package googlecloud + +import "os" -import ( - "net" -) +const linuxProductNameFile = "/sys/class/dmi/id/product_name" -// WrapSyscallConn returns newConn on appengine. -func WrapSyscallConn(rawConn, newConn net.Conn) net.Conn { - return newConn +func manufacturer() ([]byte, error) { + return os.ReadFile(linuxProductNameFile) } diff --git a/vendor/google.golang.org/grpc/internal/googlecloud/manufacturer_windows.go b/vendor/google.golang.org/grpc/internal/googlecloud/manufacturer_windows.go new file mode 100644 index 00000000000..2d7aaaaa70f --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/googlecloud/manufacturer_windows.go @@ -0,0 +1,50 @@ +/* + * + * Copyright 2022 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package googlecloud + +import ( + "errors" + "os/exec" + "regexp" + "strings" +) + +const ( + windowsCheckCommand = "powershell.exe" + windowsCheckCommandArgs = "Get-WmiObject -Class Win32_BIOS" + powershellOutputFilter = "Manufacturer" + windowsManufacturerRegex = ":(.*)" +) + +func manufacturer() ([]byte, error) { + cmd := exec.Command(windowsCheckCommand, windowsCheckCommandArgs) + out, err := cmd.Output() + if err != nil { + return nil, err + } + for _, line := range strings.Split(strings.TrimSuffix(string(out), "\n"), "\n") { + if strings.HasPrefix(line, powershellOutputFilter) { + re := regexp.MustCompile(windowsManufacturerRegex) + name := re.FindString(line) + name = strings.TrimLeft(name, ":") + return []byte(name), nil + } + } + return nil, errors.New("cannot determine the machine's manufacturer") +} diff --git a/vendor/google.golang.org/grpc/internal/grpclog/grpclog.go b/vendor/google.golang.org/grpc/internal/grpclog/grpclog.go index e6f975cbf6a..b68e26a3649 100644 --- a/vendor/google.golang.org/grpc/internal/grpclog/grpclog.go +++ b/vendor/google.golang.org/grpc/internal/grpclog/grpclog.go @@ -110,17 +110,17 @@ type LoggerV2 interface { // This is a copy of the DepthLoggerV2 defined in the external grpclog package. // It is defined here to avoid a circular dependency. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. type DepthLoggerV2 interface { - // InfoDepth logs to INFO log at the specified depth. Arguments are handled in the manner of fmt.Print. + // InfoDepth logs to INFO log at the specified depth. Arguments are handled in the manner of fmt.Println. InfoDepth(depth int, args ...interface{}) - // WarningDepth logs to WARNING log at the specified depth. Arguments are handled in the manner of fmt.Print. + // WarningDepth logs to WARNING log at the specified depth. Arguments are handled in the manner of fmt.Println. WarningDepth(depth int, args ...interface{}) - // ErrorDetph logs to ERROR log at the specified depth. Arguments are handled in the manner of fmt.Print. + // ErrorDepth logs to ERROR log at the specified depth. Arguments are handled in the manner of fmt.Println. ErrorDepth(depth int, args ...interface{}) - // FatalDepth logs to FATAL log at the specified depth. Arguments are handled in the manner of fmt.Print. + // FatalDepth logs to FATAL log at the specified depth. Arguments are handled in the manner of fmt.Println. FatalDepth(depth int, args ...interface{}) } diff --git a/vendor/google.golang.org/grpc/internal/grpclog/prefixLogger.go b/vendor/google.golang.org/grpc/internal/grpclog/prefixLogger.go index 82af70e96f1..02224b42ca8 100644 --- a/vendor/google.golang.org/grpc/internal/grpclog/prefixLogger.go +++ b/vendor/google.golang.org/grpc/internal/grpclog/prefixLogger.go @@ -63,6 +63,9 @@ func (pl *PrefixLogger) Errorf(format string, args ...interface{}) { // Debugf does info logging at verbose level 2. func (pl *PrefixLogger) Debugf(format string, args ...interface{}) { + // TODO(6044): Refactor interfaces LoggerV2 and DepthLogger, and maybe + // rewrite PrefixLogger a little to ensure that we don't use the global + // `Logger` here, and instead use the `logger` field. if !Logger.V(2) { return } @@ -73,6 +76,15 @@ func (pl *PrefixLogger) Debugf(format string, args ...interface{}) { return } InfoDepth(1, fmt.Sprintf(format, args...)) + +} + +// V reports whether verbosity level l is at least the requested verbose level. +func (pl *PrefixLogger) V(l int) bool { + // TODO(6044): Refactor interfaces LoggerV2 and DepthLogger, and maybe + // rewrite PrefixLogger a little to ensure that we don't use the global + // `Logger` here, and instead use the `logger` field. + return Logger.V(l) } // NewPrefixLogger creates a prefix logger with the given prefix. diff --git a/vendor/google.golang.org/grpc/internal/grpcrand/grpcrand.go b/vendor/google.golang.org/grpc/internal/grpcrand/grpcrand.go index 200b115ca20..d08e3e90766 100644 --- a/vendor/google.golang.org/grpc/internal/grpcrand/grpcrand.go +++ b/vendor/google.golang.org/grpc/internal/grpcrand/grpcrand.go @@ -31,26 +31,58 @@ var ( mu sync.Mutex ) +// Int implements rand.Int on the grpcrand global source. +func Int() int { + mu.Lock() + defer mu.Unlock() + return r.Int() +} + // Int63n implements rand.Int63n on the grpcrand global source. func Int63n(n int64) int64 { mu.Lock() - res := r.Int63n(n) - mu.Unlock() - return res + defer mu.Unlock() + return r.Int63n(n) } // Intn implements rand.Intn on the grpcrand global source. func Intn(n int) int { mu.Lock() - res := r.Intn(n) - mu.Unlock() - return res + defer mu.Unlock() + return r.Intn(n) +} + +// Int31n implements rand.Int31n on the grpcrand global source. +func Int31n(n int32) int32 { + mu.Lock() + defer mu.Unlock() + return r.Int31n(n) } // Float64 implements rand.Float64 on the grpcrand global source. func Float64() float64 { mu.Lock() - res := r.Float64() - mu.Unlock() - return res + defer mu.Unlock() + return r.Float64() +} + +// Uint64 implements rand.Uint64 on the grpcrand global source. +func Uint64() uint64 { + mu.Lock() + defer mu.Unlock() + return r.Uint64() +} + +// Uint32 implements rand.Uint32 on the grpcrand global source. +func Uint32() uint32 { + mu.Lock() + defer mu.Unlock() + return r.Uint32() +} + +// Shuffle implements rand.Shuffle on the grpcrand global source. +var Shuffle = func(n int, f func(int, int)) { + mu.Lock() + defer mu.Unlock() + r.Shuffle(n, f) } diff --git a/vendor/google.golang.org/grpc/internal/grpcsync/callback_serializer.go b/vendor/google.golang.org/grpc/internal/grpcsync/callback_serializer.go new file mode 100644 index 00000000000..37b8d4117e7 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/grpcsync/callback_serializer.go @@ -0,0 +1,119 @@ +/* + * + * Copyright 2022 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package grpcsync + +import ( + "context" + "sync" + + "google.golang.org/grpc/internal/buffer" +) + +// CallbackSerializer provides a mechanism to schedule callbacks in a +// synchronized manner. It provides a FIFO guarantee on the order of execution +// of scheduled callbacks. New callbacks can be scheduled by invoking the +// Schedule() method. +// +// This type is safe for concurrent access. +type CallbackSerializer struct { + // Done is closed once the serializer is shut down completely, i.e all + // scheduled callbacks are executed and the serializer has deallocated all + // its resources. + Done chan struct{} + + callbacks *buffer.Unbounded + closedMu sync.Mutex + closed bool +} + +// NewCallbackSerializer returns a new CallbackSerializer instance. The provided +// context will be passed to the scheduled callbacks. Users should cancel the +// provided context to shutdown the CallbackSerializer. It is guaranteed that no +// callbacks will be added once this context is canceled, and any pending un-run +// callbacks will be executed before the serializer is shut down. +func NewCallbackSerializer(ctx context.Context) *CallbackSerializer { + t := &CallbackSerializer{ + Done: make(chan struct{}), + callbacks: buffer.NewUnbounded(), + } + go t.run(ctx) + return t +} + +// Schedule adds a callback to be scheduled after existing callbacks are run. +// +// Callbacks are expected to honor the context when performing any blocking +// operations, and should return early when the context is canceled. +// +// Return value indicates if the callback was successfully added to the list of +// callbacks to be executed by the serializer. It is not possible to add +// callbacks once the context passed to NewCallbackSerializer is cancelled. +func (t *CallbackSerializer) Schedule(f func(ctx context.Context)) bool { + t.closedMu.Lock() + defer t.closedMu.Unlock() + + if t.closed { + return false + } + t.callbacks.Put(f) + return true +} + +func (t *CallbackSerializer) run(ctx context.Context) { + var backlog []func(context.Context) + + defer close(t.Done) + for ctx.Err() == nil { + select { + case <-ctx.Done(): + // Do nothing here. Next iteration of the for loop will not happen, + // since ctx.Err() would be non-nil. + case callback, ok := <-t.callbacks.Get(): + if !ok { + return + } + t.callbacks.Load() + callback.(func(ctx context.Context))(ctx) + } + } + + // Fetch pending callbacks if any, and execute them before returning from + // this method and closing t.Done. + t.closedMu.Lock() + t.closed = true + backlog = t.fetchPendingCallbacks() + t.callbacks.Close() + t.closedMu.Unlock() + for _, b := range backlog { + b(ctx) + } +} + +func (t *CallbackSerializer) fetchPendingCallbacks() []func(context.Context) { + var backlog []func(context.Context) + for { + select { + case b := <-t.callbacks.Get(): + backlog = append(backlog, b.(func(context.Context))) + t.callbacks.Load() + default: + return backlog + } + } +} diff --git a/vendor/google.golang.org/grpc/credentials/go12.go b/vendor/google.golang.org/grpc/internal/grpcsync/oncefunc.go similarity index 58% rename from vendor/google.golang.org/grpc/credentials/go12.go rename to vendor/google.golang.org/grpc/internal/grpcsync/oncefunc.go index ccbf35b3312..6635f7bca96 100644 --- a/vendor/google.golang.org/grpc/credentials/go12.go +++ b/vendor/google.golang.org/grpc/internal/grpcsync/oncefunc.go @@ -1,8 +1,6 @@ -// +build go1.12 - /* * - * Copyright 2019 gRPC authors. + * Copyright 2022 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,13 +16,17 @@ * */ -package credentials +package grpcsync -import "crypto/tls" +import ( + "sync" +) -// This init function adds cipher suite constants only defined in Go 1.12. -func init() { - cipherSuiteLookup[tls.TLS_AES_128_GCM_SHA256] = "TLS_AES_128_GCM_SHA256" - cipherSuiteLookup[tls.TLS_AES_256_GCM_SHA384] = "TLS_AES_256_GCM_SHA384" - cipherSuiteLookup[tls.TLS_CHACHA20_POLY1305_SHA256] = "TLS_CHACHA20_POLY1305_SHA256" +// OnceFunc returns a function wrapping f which ensures f is only executed +// once even if the returned function is executed multiple times. +func OnceFunc(f func()) func() { + var once sync.Once + return func() { + once.Do(f) + } } diff --git a/vendor/google.golang.org/grpc/internal/grpcutil/compressor.go b/vendor/google.golang.org/grpc/internal/grpcutil/compressor.go new file mode 100644 index 00000000000..9f409096798 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/grpcutil/compressor.go @@ -0,0 +1,47 @@ +/* + * + * Copyright 2022 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package grpcutil + +import ( + "strings" + + "google.golang.org/grpc/internal/envconfig" +) + +// RegisteredCompressorNames holds names of the registered compressors. +var RegisteredCompressorNames []string + +// IsCompressorNameRegistered returns true when name is available in registry. +func IsCompressorNameRegistered(name string) bool { + for _, compressor := range RegisteredCompressorNames { + if compressor == name { + return true + } + } + return false +} + +// RegisteredCompressors returns a string of registered compressor names +// separated by comma. +func RegisteredCompressors() string { + if !envconfig.AdvertiseCompressors { + return "" + } + return strings.Join(RegisteredCompressorNames, ",") +} diff --git a/vendor/google.golang.org/grpc/internal/resolver/dns/go113.go b/vendor/google.golang.org/grpc/internal/grpcutil/grpcutil.go similarity index 67% rename from vendor/google.golang.org/grpc/internal/resolver/dns/go113.go rename to vendor/google.golang.org/grpc/internal/grpcutil/grpcutil.go index 8783a8cf821..e2f948e8f4f 100644 --- a/vendor/google.golang.org/grpc/internal/resolver/dns/go113.go +++ b/vendor/google.golang.org/grpc/internal/grpcutil/grpcutil.go @@ -1,8 +1,6 @@ -// +build go1.13 - /* * - * Copyright 2019 gRPC authors. + * Copyright 2021 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,16 +16,5 @@ * */ -package dns - -import "net" - -func init() { - filterError = func(err error) error { - if dnsErr, ok := err.(*net.DNSError); ok && dnsErr.IsNotFound { - // The name does not exist; not an error. - return nil - } - return err - } -} +// Package grpcutil provides utility functions used across the gRPC codebase. +package grpcutil diff --git a/vendor/google.golang.org/grpc/internal/grpcutil/method.go b/vendor/google.golang.org/grpc/internal/grpcutil/method.go index 4e7475060c1..ec62b4775e5 100644 --- a/vendor/google.golang.org/grpc/internal/grpcutil/method.go +++ b/vendor/google.golang.org/grpc/internal/grpcutil/method.go @@ -25,7 +25,6 @@ import ( // ParseMethod splits service and method from the input. It expects format // "/service/method". -// func ParseMethod(methodName string) (service, method string, _ error) { if !strings.HasPrefix(methodName, "/") { return "", "", errors.New("invalid method name: should start with /") @@ -39,6 +38,11 @@ func ParseMethod(methodName string) (service, method string, _ error) { return methodName[:pos], methodName[pos+1:], nil } +// baseContentType is the base content-type for gRPC. This is a valid +// content-type on it's own, but can also include a content-subtype such as +// "proto" as a suffix after "+" or ";". See +// https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#requests +// for more details. const baseContentType = "application/grpc" // ContentSubtype returns the content-subtype for the given content-type. The diff --git a/vendor/google.golang.org/grpc/internal/grpcutil/regex.go b/vendor/google.golang.org/grpc/internal/grpcutil/regex.go new file mode 100644 index 00000000000..7a092b2b804 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/grpcutil/regex.go @@ -0,0 +1,31 @@ +/* + * + * Copyright 2021 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package grpcutil + +import "regexp" + +// FullMatchWithRegex returns whether the full text matches the regex provided. +func FullMatchWithRegex(re *regexp.Regexp, text string) bool { + if len(text) == 0 { + return re.MatchString(text) + } + re.Longest() + rem := re.FindString(text) + return len(rem) == len(text) +} diff --git a/vendor/google.golang.org/grpc/internal/grpcutil/target.go b/vendor/google.golang.org/grpc/internal/grpcutil/target.go deleted file mode 100644 index 8833021da02..00000000000 --- a/vendor/google.golang.org/grpc/internal/grpcutil/target.go +++ /dev/null @@ -1,89 +0,0 @@ -/* - * - * Copyright 2020 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -// Package grpcutil provides a bunch of utility functions to be used across the -// gRPC codebase. -package grpcutil - -import ( - "strings" - - "google.golang.org/grpc/resolver" -) - -// split2 returns the values from strings.SplitN(s, sep, 2). -// If sep is not found, it returns ("", "", false) instead. -func split2(s, sep string) (string, string, bool) { - spl := strings.SplitN(s, sep, 2) - if len(spl) < 2 { - return "", "", false - } - return spl[0], spl[1], true -} - -// ParseTarget splits target into a resolver.Target struct containing scheme, -// authority and endpoint. skipUnixColonParsing indicates that the parse should -// not parse "unix:[path]" cases. This should be true in cases where a custom -// dialer is present, to prevent a behavior change. -// -// If target is not a valid scheme://authority/endpoint as specified in -// https://github.com/grpc/grpc/blob/master/doc/naming.md, -// it returns {Endpoint: target}. -func ParseTarget(target string, skipUnixColonParsing bool) (ret resolver.Target) { - var ok bool - if strings.HasPrefix(target, "unix-abstract:") { - if strings.HasPrefix(target, "unix-abstract://") { - // Maybe, with Authority specified, try to parse it - var remain string - ret.Scheme, remain, _ = split2(target, "://") - ret.Authority, ret.Endpoint, ok = split2(remain, "/") - if !ok { - // No Authority, add the "//" back - ret.Endpoint = "//" + remain - } else { - // Found Authority, add the "/" back - ret.Endpoint = "/" + ret.Endpoint - } - } else { - // Without Authority specified, split target on ":" - ret.Scheme, ret.Endpoint, _ = split2(target, ":") - } - return ret - } - ret.Scheme, ret.Endpoint, ok = split2(target, "://") - if !ok { - if strings.HasPrefix(target, "unix:") && !skipUnixColonParsing { - // Handle the "unix:[local/path]" and "unix:[/absolute/path]" cases, - // because splitting on :// only handles the - // "unix://[/absolute/path]" case. Only handle if the dialer is nil, - // to avoid a behavior change with custom dialers. - return resolver.Target{Scheme: "unix", Endpoint: target[len("unix:"):]} - } - return resolver.Target{Endpoint: target} - } - ret.Authority, ret.Endpoint, ok = split2(ret.Endpoint, "/") - if !ok { - return resolver.Target{Endpoint: target} - } - if ret.Scheme == "unix" { - // Add the "/" back in the unix case, so the unix resolver receives the - // actual endpoint in the "unix://[/absolute/path]" case. - ret.Endpoint = "/" + ret.Endpoint - } - return ret -} diff --git a/vendor/google.golang.org/grpc/internal/internal.go b/vendor/google.golang.org/grpc/internal/internal.go index 1e2834c70f6..42ff39c8444 100644 --- a/vendor/google.golang.org/grpc/internal/internal.go +++ b/vendor/google.golang.org/grpc/internal/internal.go @@ -38,17 +38,10 @@ var ( // KeepaliveMinPingTime is the minimum ping interval. This must be 10s by // default, but tests may wish to set it lower for convenience. KeepaliveMinPingTime = 10 * time.Second - // NewRequestInfoContext creates a new context based on the argument context attaching - // the passed in RequestInfo to the new context. - NewRequestInfoContext interface{} // func(context.Context, credentials.RequestInfo) context.Context - // NewClientHandshakeInfoContext returns a copy of the input context with - // the passed in ClientHandshakeInfo struct added to it. - NewClientHandshakeInfoContext interface{} // func(context.Context, credentials.ClientHandshakeInfo) context.Context - // ParseServiceConfigForTesting is for creating a fake - // ClientConn for resolver testing only - ParseServiceConfigForTesting interface{} // func(string) *serviceconfig.ParseResult + // ParseServiceConfig parses a JSON representation of the service config. + ParseServiceConfig interface{} // func(string) *serviceconfig.ParseResult // EqualServiceConfigForTesting is for testing service config generation and - // parsing. Both a and b should be returned by ParseServiceConfigForTesting. + // parsing. Both a and b should be returned by ParseServiceConfig. // This function compares the config without rawJSON stripped, in case the // there's difference in white space. EqualServiceConfigForTesting func(a, b serviceconfig.Config) bool @@ -65,6 +58,112 @@ var ( // gRPC server. An xDS-enabled server needs to know what type of credentials // is configured on the underlying gRPC server. This is set by server.go. GetServerCredentials interface{} // func (*grpc.Server) credentials.TransportCredentials + // CanonicalString returns the canonical string of the code defined here: + // https://github.com/grpc/grpc/blob/master/doc/statuscodes.md. + // + // This is used in the 1.0 release of gcp/observability, and thus must not be + // deleted or changed. + CanonicalString interface{} // func (codes.Code) string + // DrainServerTransports initiates a graceful close of existing connections + // on a gRPC server accepted on the provided listener address. An + // xDS-enabled server invokes this method on a grpc.Server when a particular + // listener moves to "not-serving" mode. + DrainServerTransports interface{} // func(*grpc.Server, string) + // AddGlobalServerOptions adds an array of ServerOption that will be + // effective globally for newly created servers. The priority will be: 1. + // user-provided; 2. this method; 3. default values. + // + // This is used in the 1.0 release of gcp/observability, and thus must not be + // deleted or changed. + AddGlobalServerOptions interface{} // func(opt ...ServerOption) + // ClearGlobalServerOptions clears the array of extra ServerOption. This + // method is useful in testing and benchmarking. + // + // This is used in the 1.0 release of gcp/observability, and thus must not be + // deleted or changed. + ClearGlobalServerOptions func() + // AddGlobalDialOptions adds an array of DialOption that will be effective + // globally for newly created client channels. The priority will be: 1. + // user-provided; 2. this method; 3. default values. + // + // This is used in the 1.0 release of gcp/observability, and thus must not be + // deleted or changed. + AddGlobalDialOptions interface{} // func(opt ...DialOption) + // DisableGlobalDialOptions returns a DialOption that prevents the + // ClientConn from applying the global DialOptions (set via + // AddGlobalDialOptions). + // + // This is used in the 1.0 release of gcp/observability, and thus must not be + // deleted or changed. + DisableGlobalDialOptions interface{} // func() grpc.DialOption + // ClearGlobalDialOptions clears the array of extra DialOption. This + // method is useful in testing and benchmarking. + // + // This is used in the 1.0 release of gcp/observability, and thus must not be + // deleted or changed. + ClearGlobalDialOptions func() + // JoinDialOptions combines the dial options passed as arguments into a + // single dial option. + JoinDialOptions interface{} // func(...grpc.DialOption) grpc.DialOption + // JoinServerOptions combines the server options passed as arguments into a + // single server option. + JoinServerOptions interface{} // func(...grpc.ServerOption) grpc.ServerOption + + // WithBinaryLogger returns a DialOption that specifies the binary logger + // for a ClientConn. + // + // This is used in the 1.0 release of gcp/observability, and thus must not be + // deleted or changed. + WithBinaryLogger interface{} // func(binarylog.Logger) grpc.DialOption + // BinaryLogger returns a ServerOption that can set the binary logger for a + // server. + // + // This is used in the 1.0 release of gcp/observability, and thus must not be + // deleted or changed. + BinaryLogger interface{} // func(binarylog.Logger) grpc.ServerOption + + // NewXDSResolverWithConfigForTesting creates a new xds resolver builder using + // the provided xds bootstrap config instead of the global configuration from + // the supported environment variables. The resolver.Builder is meant to be + // used in conjunction with the grpc.WithResolvers DialOption. + // + // Testing Only + // + // This function should ONLY be used for testing and may not work with some + // other features, including the CSDS service. + NewXDSResolverWithConfigForTesting interface{} // func([]byte) (resolver.Builder, error) + + // RegisterRLSClusterSpecifierPluginForTesting registers the RLS Cluster + // Specifier Plugin for testing purposes, regardless of the XDSRLS environment + // variable. + // + // TODO: Remove this function once the RLS env var is removed. + RegisterRLSClusterSpecifierPluginForTesting func() + + // UnregisterRLSClusterSpecifierPluginForTesting unregisters the RLS Cluster + // Specifier Plugin for testing purposes. This is needed because there is no way + // to unregister the RLS Cluster Specifier Plugin after registering it solely + // for testing purposes using RegisterRLSClusterSpecifierPluginForTesting(). + // + // TODO: Remove this function once the RLS env var is removed. + UnregisterRLSClusterSpecifierPluginForTesting func() + + // RegisterRBACHTTPFilterForTesting registers the RBAC HTTP Filter for testing + // purposes, regardless of the RBAC environment variable. + // + // TODO: Remove this function once the RBAC env var is removed. + RegisterRBACHTTPFilterForTesting func() + + // UnregisterRBACHTTPFilterForTesting unregisters the RBAC HTTP Filter for + // testing purposes. This is needed because there is no way to unregister the + // HTTP Filter after registering it solely for testing purposes using + // RegisterRBACHTTPFilterForTesting(). + // + // TODO: Remove this function once the RBAC env var is removed. + UnregisterRBACHTTPFilterForTesting func() + + // ORCAAllowAnyMinReportingInterval is for examples/orca use ONLY. + ORCAAllowAnyMinReportingInterval interface{} // func(so *orca.ServiceOptions) ) // HealthChecker defines the signature of the client-side LB channel health checking function. @@ -87,3 +186,9 @@ const ( // that supports backend returned by grpclb balancer. CredsBundleModeBackendFromBalancer = "backend-from-balancer" ) + +// RLSLoadBalancingPolicyName is the name of the RLS LB policy. +// +// It currently has an experimental suffix which would be removed once +// end-to-end testing of the policy is completed. +const RLSLoadBalancingPolicyName = "rls_experimental" diff --git a/vendor/google.golang.org/grpc/internal/metadata/metadata.go b/vendor/google.golang.org/grpc/internal/metadata/metadata.go index 302262613a0..c82e608e077 100644 --- a/vendor/google.golang.org/grpc/internal/metadata/metadata.go +++ b/vendor/google.golang.org/grpc/internal/metadata/metadata.go @@ -22,6 +22,9 @@ package metadata import ( + "fmt" + "strings" + "google.golang.org/grpc/metadata" "google.golang.org/grpc/resolver" ) @@ -30,14 +33,38 @@ type mdKeyType string const mdKey = mdKeyType("grpc.internal.address.metadata") +type mdValue metadata.MD + +func (m mdValue) Equal(o interface{}) bool { + om, ok := o.(mdValue) + if !ok { + return false + } + if len(m) != len(om) { + return false + } + for k, v := range m { + ov := om[k] + if len(ov) != len(v) { + return false + } + for i, ve := range v { + if ov[i] != ve { + return false + } + } + } + return true +} + // Get returns the metadata of addr. func Get(addr resolver.Address) metadata.MD { attrs := addr.Attributes if attrs == nil { return nil } - md, _ := attrs.Value(mdKey).(metadata.MD) - return md + md, _ := attrs.Value(mdKey).(mdValue) + return metadata.MD(md) } // Set sets (overrides) the metadata in addr. @@ -45,6 +72,61 @@ func Get(addr resolver.Address) metadata.MD { // When a SubConn is created with this address, the RPCs sent on it will all // have this metadata. func Set(addr resolver.Address, md metadata.MD) resolver.Address { - addr.Attributes = addr.Attributes.WithValues(mdKey, md) + addr.Attributes = addr.Attributes.WithValue(mdKey, mdValue(md)) return addr } + +// Validate validates every pair in md with ValidatePair. +func Validate(md metadata.MD) error { + for k, vals := range md { + if err := ValidatePair(k, vals...); err != nil { + return err + } + } + return nil +} + +// hasNotPrintable return true if msg contains any characters which are not in %x20-%x7E +func hasNotPrintable(msg string) bool { + // for i that saving a conversion if not using for range + for i := 0; i < len(msg); i++ { + if msg[i] < 0x20 || msg[i] > 0x7E { + return true + } + } + return false +} + +// ValidatePair validate a key-value pair with the following rules (the pseudo-header will be skipped) : +// +// - key must contain one or more characters. +// - the characters in the key must be contained in [0-9 a-z _ - .]. +// - if the key ends with a "-bin" suffix, no validation of the corresponding value is performed. +// - the characters in the every value must be printable (in [%x20-%x7E]). +func ValidatePair(key string, vals ...string) error { + // key should not be empty + if key == "" { + return fmt.Errorf("there is an empty key in the header") + } + // pseudo-header will be ignored + if key[0] == ':' { + return nil + } + // check key, for i that saving a conversion if not using for range + for i := 0; i < len(key); i++ { + r := key[i] + if !(r >= 'a' && r <= 'z') && !(r >= '0' && r <= '9') && r != '.' && r != '-' && r != '_' { + return fmt.Errorf("header key %q contains illegal characters not in [0-9a-z-_.]", key) + } + } + if strings.HasSuffix(key, "-bin") { + return nil + } + // check value + for _, val := range vals { + if hasNotPrintable(val) { + return fmt.Errorf("header key %q contains value with non-printable ASCII characters", key) + } + } + return nil +} diff --git a/vendor/google.golang.org/grpc/internal/pretty/pretty.go b/vendor/google.golang.org/grpc/internal/pretty/pretty.go new file mode 100644 index 00000000000..0177af4b511 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/pretty/pretty.go @@ -0,0 +1,82 @@ +/* + * + * Copyright 2021 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Package pretty defines helper functions to pretty-print structs for logging. +package pretty + +import ( + "bytes" + "encoding/json" + "fmt" + + "github.com/golang/protobuf/jsonpb" + protov1 "github.com/golang/protobuf/proto" + "google.golang.org/protobuf/encoding/protojson" + protov2 "google.golang.org/protobuf/proto" +) + +const jsonIndent = " " + +// ToJSON marshals the input into a json string. +// +// If marshal fails, it falls back to fmt.Sprintf("%+v"). +func ToJSON(e interface{}) string { + switch ee := e.(type) { + case protov1.Message: + mm := jsonpb.Marshaler{Indent: jsonIndent} + ret, err := mm.MarshalToString(ee) + if err != nil { + // This may fail for proto.Anys, e.g. for xDS v2, LDS, the v2 + // messages are not imported, and this will fail because the message + // is not found. + return fmt.Sprintf("%+v", ee) + } + return ret + case protov2.Message: + mm := protojson.MarshalOptions{ + Multiline: true, + Indent: jsonIndent, + } + ret, err := mm.Marshal(ee) + if err != nil { + // This may fail for proto.Anys, e.g. for xDS v2, LDS, the v2 + // messages are not imported, and this will fail because the message + // is not found. + return fmt.Sprintf("%+v", ee) + } + return string(ret) + default: + ret, err := json.MarshalIndent(ee, "", jsonIndent) + if err != nil { + return fmt.Sprintf("%+v", ee) + } + return string(ret) + } +} + +// FormatJSON formats the input json bytes with indentation. +// +// If Indent fails, it returns the unchanged input as string. +func FormatJSON(b []byte) string { + var out bytes.Buffer + err := json.Indent(&out, b, "", jsonIndent) + if err != nil { + return string(b) + } + return out.String() +} diff --git a/vendor/google.golang.org/grpc/internal/resolver/config_selector.go b/vendor/google.golang.org/grpc/internal/resolver/config_selector.go index e6990040056..c7a18a948ad 100644 --- a/vendor/google.golang.org/grpc/internal/resolver/config_selector.go +++ b/vendor/google.golang.org/grpc/internal/resolver/config_selector.go @@ -24,6 +24,7 @@ import ( "sync" "google.golang.org/grpc/internal/serviceconfig" + "google.golang.org/grpc/metadata" "google.golang.org/grpc/resolver" ) @@ -51,6 +52,77 @@ type RPCConfig struct { Context context.Context MethodConfig serviceconfig.MethodConfig // configuration to use for this RPC OnCommitted func() // Called when the RPC has been committed (retries no longer possible) + Interceptor ClientInterceptor +} + +// ClientStream is the same as grpc.ClientStream, but defined here for circular +// dependency reasons. +type ClientStream interface { + // Header returns the header metadata received from the server if there + // is any. It blocks if the metadata is not ready to read. + Header() (metadata.MD, error) + // Trailer returns the trailer metadata from the server, if there is any. + // It must only be called after stream.CloseAndRecv has returned, or + // stream.Recv has returned a non-nil error (including io.EOF). + Trailer() metadata.MD + // CloseSend closes the send direction of the stream. It closes the stream + // when non-nil error is met. It is also not safe to call CloseSend + // concurrently with SendMsg. + CloseSend() error + // Context returns the context for this stream. + // + // It should not be called until after Header or RecvMsg has returned. Once + // called, subsequent client-side retries are disabled. + Context() context.Context + // SendMsg is generally called by generated code. On error, SendMsg aborts + // the stream. If the error was generated by the client, the status is + // returned directly; otherwise, io.EOF is returned and the status of + // the stream may be discovered using RecvMsg. + // + // SendMsg blocks until: + // - There is sufficient flow control to schedule m with the transport, or + // - The stream is done, or + // - The stream breaks. + // + // SendMsg does not wait until the message is received by the server. An + // untimely stream closure may result in lost messages. To ensure delivery, + // users should ensure the RPC completed successfully using RecvMsg. + // + // It is safe to have a goroutine calling SendMsg and another goroutine + // calling RecvMsg on the same stream at the same time, but it is not safe + // to call SendMsg on the same stream in different goroutines. It is also + // not safe to call CloseSend concurrently with SendMsg. + SendMsg(m interface{}) error + // RecvMsg blocks until it receives a message into m or the stream is + // done. It returns io.EOF when the stream completes successfully. On + // any other error, the stream is aborted and the error contains the RPC + // status. + // + // It is safe to have a goroutine calling SendMsg and another goroutine + // calling RecvMsg on the same stream at the same time, but it is not + // safe to call RecvMsg on the same stream in different goroutines. + RecvMsg(m interface{}) error +} + +// ClientInterceptor is an interceptor for gRPC client streams. +type ClientInterceptor interface { + // NewStream produces a ClientStream for an RPC which may optionally use + // the provided function to produce a stream for delegation. Note: + // RPCInfo.Context should not be used (will be nil). + // + // done is invoked when the RPC is finished using its connection, or could + // not be assigned a connection. RPC operations may still occur on + // ClientStream after done is called, since the interceptor is invoked by + // application-layer operations. done must never be nil when called. + NewStream(ctx context.Context, ri RPCInfo, done func(), newStream func(ctx context.Context, done func()) (ClientStream, error)) (ClientStream, error) +} + +// ServerInterceptor is an interceptor for incoming RPC's on gRPC server side. +type ServerInterceptor interface { + // AllowRPC checks if an incoming RPC is allowed to proceed based on + // information about connection RPC was received on, and HTTP Headers. This + // information will be piped into context. + AllowRPC(ctx context.Context) error // TODO: Make this a real interceptor for filters such as rate limiting. } type csKeyType string @@ -60,7 +132,7 @@ const csKey = csKeyType("grpc.internal.resolver.configSelector") // SetConfigSelector sets the config selector in state and returns the new // state. func SetConfigSelector(state resolver.State, cs ConfigSelector) resolver.State { - state.Attributes = state.Attributes.WithValues(csKey, cs) + state.Attributes = state.Attributes.WithValue(csKey, cs) return state } diff --git a/vendor/google.golang.org/grpc/internal/resolver/dns/dns_resolver.go b/vendor/google.golang.org/grpc/internal/resolver/dns/dns_resolver.go index 30423556658..09a667f33cb 100644 --- a/vendor/google.golang.org/grpc/internal/resolver/dns/dns_resolver.go +++ b/vendor/google.golang.org/grpc/internal/resolver/dns/dns_resolver.go @@ -34,6 +34,7 @@ import ( grpclbstate "google.golang.org/grpc/balancer/grpclb/state" "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/internal/backoff" "google.golang.org/grpc/internal/envconfig" "google.golang.org/grpc/internal/grpcrand" "google.golang.org/grpc/resolver" @@ -46,6 +47,13 @@ var EnableSRVLookups = false var logger = grpclog.Component("dns") +// Globals to stub out in tests. TODO: Perhaps these two can be combined into a +// single variable for testing the resolver? +var ( + newTimer = time.NewTimer + newTimerDNSResRate = time.NewTimer +) + func init() { resolver.Register(NewBuilder()) } @@ -108,7 +116,7 @@ type dnsBuilder struct{} // Build creates and starts a DNS resolver that watches the name resolution of the target. func (b *dnsBuilder) Build(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions) (resolver.Resolver, error) { - host, port, err := parseTarget(target.Endpoint, defaultPort) + host, port, err := parseTarget(target.Endpoint(), defaultPort) if err != nil { return nil, err } @@ -132,10 +140,10 @@ func (b *dnsBuilder) Build(target resolver.Target, cc resolver.ClientConn, opts disableServiceConfig: opts.DisableServiceConfig, } - if target.Authority == "" { + if target.URL.Host == "" { d.resolver = defaultResolver } else { - d.resolver, err = customAuthorityResolver(target.Authority) + d.resolver, err = customAuthorityResolver(target.URL.Host) if err != nil { return nil, err } @@ -143,7 +151,6 @@ func (b *dnsBuilder) Build(target resolver.Target, cc resolver.ClientConn, opts d.wg.Add(1) go d.watcher() - d.ResolveNow(resolver.ResolveNowOptions{}) return d, nil } @@ -201,28 +208,38 @@ func (d *dnsResolver) Close() { func (d *dnsResolver) watcher() { defer d.wg.Done() + backoffIndex := 1 for { - select { - case <-d.ctx.Done(): - return - case <-d.rn: - } - state, err := d.lookup() if err != nil { + // Report error to the underlying grpc.ClientConn. d.cc.ReportError(err) } else { - d.cc.UpdateState(*state) + err = d.cc.UpdateState(*state) } - // Sleep to prevent excessive re-resolutions. Incoming resolution requests - // will be queued in d.rn. - t := time.NewTimer(minDNSResRate) + var timer *time.Timer + if err == nil { + // Success resolving, wait for the next ResolveNow. However, also wait 30 seconds at the very least + // to prevent constantly re-resolving. + backoffIndex = 1 + timer = newTimerDNSResRate(minDNSResRate) + select { + case <-d.ctx.Done(): + timer.Stop() + return + case <-d.rn: + } + } else { + // Poll on an error found in DNS Resolver or an error received from ClientConn. + timer = newTimer(backoff.DefaultExponential.Backoff(backoffIndex)) + backoffIndex++ + } select { - case <-t.C: case <-d.ctx.Done(): - t.Stop() + timer.Stop() return + case <-timer.C: } } } @@ -260,18 +277,13 @@ func (d *dnsResolver) lookupSRV() ([]resolver.Address, error) { return newAddrs, nil } -var filterError = func(err error) error { +func handleDNSError(err error, lookupType string) error { if dnsErr, ok := err.(*net.DNSError); ok && !dnsErr.IsTimeout && !dnsErr.IsTemporary { // Timeouts and temporary errors should be communicated to gRPC to // attempt another DNS query (with backoff). Other errors should be // suppressed (they may represent the absence of a TXT record). return nil } - return err -} - -func handleDNSError(err error, lookupType string) error { - err = filterError(err) if err != nil { err = fmt.Errorf("dns: %v record lookup error: %v", lookupType, err) logger.Info(err) @@ -306,12 +318,12 @@ func (d *dnsResolver) lookupTXT() *serviceconfig.ParseResult { } func (d *dnsResolver) lookupHost() ([]resolver.Address, error) { - var newAddrs []resolver.Address addrs, err := d.resolver.LookupHost(d.ctx, d.host) if err != nil { err = handleDNSError(err, "A") return nil, err } + newAddrs := make([]resolver.Address, 0, len(addrs)) for _, a := range addrs { ip, ok := formatIP(a) if !ok { diff --git a/vendor/google.golang.org/grpc/internal/resolver/passthrough/passthrough.go b/vendor/google.golang.org/grpc/internal/resolver/passthrough/passthrough.go index 520d9229e1e..afac56572ad 100644 --- a/vendor/google.golang.org/grpc/internal/resolver/passthrough/passthrough.go +++ b/vendor/google.golang.org/grpc/internal/resolver/passthrough/passthrough.go @@ -20,13 +20,20 @@ // name without scheme back to gRPC as resolved address. package passthrough -import "google.golang.org/grpc/resolver" +import ( + "errors" + + "google.golang.org/grpc/resolver" +) const scheme = "passthrough" type passthroughBuilder struct{} func (*passthroughBuilder) Build(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions) (resolver.Resolver, error) { + if target.Endpoint() == "" && opts.Dialer == nil { + return nil, errors.New("passthrough: received empty target in Build()") + } r := &passthroughResolver{ target: target, cc: cc, @@ -45,7 +52,7 @@ type passthroughResolver struct { } func (r *passthroughResolver) start() { - r.cc.UpdateState(resolver.State{Addresses: []resolver.Address{{Addr: r.target.Endpoint}}}) + r.cc.UpdateState(resolver.State{Addresses: []resolver.Address{{Addr: r.target.Endpoint()}}}) } func (*passthroughResolver) ResolveNow(o resolver.ResolveNowOptions) {} diff --git a/vendor/google.golang.org/grpc/internal/resolver/unix/unix.go b/vendor/google.golang.org/grpc/internal/resolver/unix/unix.go index 0d5a811ddfa..16091168773 100644 --- a/vendor/google.golang.org/grpc/internal/resolver/unix/unix.go +++ b/vendor/google.golang.org/grpc/internal/resolver/unix/unix.go @@ -34,13 +34,24 @@ type builder struct { } func (b *builder) Build(target resolver.Target, cc resolver.ClientConn, _ resolver.BuildOptions) (resolver.Resolver, error) { - if target.Authority != "" { - return nil, fmt.Errorf("invalid (non-empty) authority: %v", target.Authority) + if target.URL.Host != "" { + return nil, fmt.Errorf("invalid (non-empty) authority: %v", target.URL.Host) } - addr := resolver.Address{Addr: target.Endpoint} + + // gRPC was parsing the dial target manually before PR #4817, and we + // switched to using url.Parse() in that PR. To avoid breaking existing + // resolver implementations we ended up stripping the leading "/" from the + // endpoint. This obviously does not work for the "unix" scheme. Hence we + // end up using the parsed URL instead. + endpoint := target.URL.Path + if endpoint == "" { + endpoint = target.URL.Opaque + } + addr := resolver.Address{Addr: endpoint} if b.scheme == unixAbstractScheme { - // prepend "\x00" to address for unix-abstract - addr.Addr = "\x00" + addr.Addr + // We can not prepend \0 as c++ gRPC does, as in Golang '@' is used to signify we do + // not want trailing \0 in address. + addr.Addr = "@" + addr.Addr } cc.UpdateState(resolver.State{Addresses: []resolver.Address{networktype.Set(addr, "unix")}}) return &nopResolver{}, nil diff --git a/vendor/google.golang.org/grpc/internal/serviceconfig/duration.go b/vendor/google.golang.org/grpc/internal/serviceconfig/duration.go new file mode 100644 index 00000000000..11d82afcc7e --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/serviceconfig/duration.go @@ -0,0 +1,130 @@ +/* + * + * Copyright 2023 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package serviceconfig + +import ( + "encoding/json" + "fmt" + "math" + "strconv" + "strings" + "time" +) + +// Duration defines JSON marshal and unmarshal methods to conform to the +// protobuf JSON spec defined [here]. +// +// [here]: https://protobuf.dev/reference/protobuf/google.protobuf/#duration +type Duration time.Duration + +func (d Duration) String() string { + return fmt.Sprint(time.Duration(d)) +} + +// MarshalJSON converts from d to a JSON string output. +func (d Duration) MarshalJSON() ([]byte, error) { + ns := time.Duration(d).Nanoseconds() + sec := ns / int64(time.Second) + ns = ns % int64(time.Second) + + var sign string + if sec < 0 || ns < 0 { + sign, sec, ns = "-", -1*sec, -1*ns + } + + // Generated output always contains 0, 3, 6, or 9 fractional digits, + // depending on required precision. + str := fmt.Sprintf("%s%d.%09d", sign, sec, ns) + str = strings.TrimSuffix(str, "000") + str = strings.TrimSuffix(str, "000") + str = strings.TrimSuffix(str, ".000") + return []byte(fmt.Sprintf("\"%ss\"", str)), nil +} + +// UnmarshalJSON unmarshals b as a duration JSON string into d. +func (d *Duration) UnmarshalJSON(b []byte) error { + var s string + if err := json.Unmarshal(b, &s); err != nil { + return err + } + if !strings.HasSuffix(s, "s") { + return fmt.Errorf("malformed duration %q: missing seconds unit", s) + } + neg := false + if s[0] == '-' { + neg = true + s = s[1:] + } + ss := strings.SplitN(s[:len(s)-1], ".", 3) + if len(ss) > 2 { + return fmt.Errorf("malformed duration %q: too many decimals", s) + } + // hasDigits is set if either the whole or fractional part of the number is + // present, since both are optional but one is required. + hasDigits := false + var sec, ns int64 + if len(ss[0]) > 0 { + var err error + if sec, err = strconv.ParseInt(ss[0], 10, 64); err != nil { + return fmt.Errorf("malformed duration %q: %v", s, err) + } + // Maximum seconds value per the durationpb spec. + const maxProtoSeconds = 315_576_000_000 + if sec > maxProtoSeconds { + return fmt.Errorf("out of range: %q", s) + } + hasDigits = true + } + if len(ss) == 2 && len(ss[1]) > 0 { + if len(ss[1]) > 9 { + return fmt.Errorf("malformed duration %q: too many digits after decimal", s) + } + var err error + if ns, err = strconv.ParseInt(ss[1], 10, 64); err != nil { + return fmt.Errorf("malformed duration %q: %v", s, err) + } + for i := 9; i > len(ss[1]); i-- { + ns *= 10 + } + hasDigits = true + } + if !hasDigits { + return fmt.Errorf("malformed duration %q: contains no numbers", s) + } + + if neg { + sec *= -1 + ns *= -1 + } + + // Maximum/minimum seconds/nanoseconds representable by Go's time.Duration. + const maxSeconds = math.MaxInt64 / int64(time.Second) + const maxNanosAtMaxSeconds = math.MaxInt64 % int64(time.Second) + const minSeconds = math.MinInt64 / int64(time.Second) + const minNanosAtMinSeconds = math.MinInt64 % int64(time.Second) + + if sec > maxSeconds || (sec == maxSeconds && ns >= maxNanosAtMaxSeconds) { + *d = Duration(math.MaxInt64) + } else if sec < minSeconds || (sec == minSeconds && ns <= minNanosAtMinSeconds) { + *d = Duration(math.MinInt64) + } else { + *d = Duration(sec*int64(time.Second) + ns) + } + return nil +} diff --git a/vendor/google.golang.org/grpc/internal/serviceconfig/serviceconfig.go b/vendor/google.golang.org/grpc/internal/serviceconfig/serviceconfig.go index bd4b8875f1a..51e733e495a 100644 --- a/vendor/google.golang.org/grpc/internal/serviceconfig/serviceconfig.go +++ b/vendor/google.golang.org/grpc/internal/serviceconfig/serviceconfig.go @@ -46,15 +46,31 @@ type BalancerConfig struct { type intermediateBalancerConfig []map[string]json.RawMessage +// MarshalJSON implements the json.Marshaler interface. +// +// It marshals the balancer and config into a length-1 slice +// ([]map[string]config). +func (bc *BalancerConfig) MarshalJSON() ([]byte, error) { + if bc.Config == nil { + // If config is nil, return empty config `{}`. + return []byte(fmt.Sprintf(`[{%q: %v}]`, bc.Name, "{}")), nil + } + c, err := json.Marshal(bc.Config) + if err != nil { + return nil, err + } + return []byte(fmt.Sprintf(`[{%q: %s}]`, bc.Name, c)), nil +} + // UnmarshalJSON implements the json.Unmarshaler interface. // // ServiceConfig contains a list of loadBalancingConfigs, each with a name and // config. This method iterates through that list in order, and stops at the // first policy that is supported. -// - If the config for the first supported policy is invalid, the whole service -// config is invalid. -// - If the list doesn't contain any supported policy, the whole service config -// is invalid. +// - If the config for the first supported policy is invalid, the whole service +// config is invalid. +// - If the list doesn't contain any supported policy, the whole service config +// is invalid. func (bc *BalancerConfig) UnmarshalJSON(b []byte) error { var ir intermediateBalancerConfig err := json.Unmarshal(b, &ir) @@ -62,6 +78,7 @@ func (bc *BalancerConfig) UnmarshalJSON(b []byte) error { return err } + var names []string for i, lbcfg := range ir { if len(lbcfg) != 1 { return fmt.Errorf("invalid loadBalancingConfig: entry %v does not contain exactly 1 policy/config pair: %q", i, lbcfg) @@ -76,6 +93,7 @@ func (bc *BalancerConfig) UnmarshalJSON(b []byte) error { for name, jsonCfg = range lbcfg { } + names = append(names, name) builder := balancer.Get(name) if builder == nil { // If the balancer is not registered, move on to the next config. @@ -104,7 +122,7 @@ func (bc *BalancerConfig) UnmarshalJSON(b []byte) error { // return. This means we had a loadBalancingConfig slice but did not // encounter a registered policy. The config is considered invalid in this // case. - return fmt.Errorf("invalid loadBalancingConfig: no supported policies found") + return fmt.Errorf("invalid loadBalancingConfig: no supported policies found in %v", names) } // MethodConfig defines the configuration recommended by the service providers for a diff --git a/vendor/google.golang.org/grpc/internal/status/status.go b/vendor/google.golang.org/grpc/internal/status/status.go index 710223b8ded..b0ead4f54f8 100644 --- a/vendor/google.golang.org/grpc/internal/status/status.go +++ b/vendor/google.golang.org/grpc/internal/status/status.go @@ -97,7 +97,7 @@ func (s *Status) Err() error { if s.Code() == codes.OK { return nil } - return &Error{e: s.Proto()} + return &Error{s: s} } // WithDetails returns a new status with the provided details messages appended to the status. @@ -136,19 +136,23 @@ func (s *Status) Details() []interface{} { return details } +func (s *Status) String() string { + return fmt.Sprintf("rpc error: code = %s desc = %s", s.Code(), s.Message()) +} + // Error wraps a pointer of a status proto. It implements error and Status, // and a nil *Error should never be returned by this package. type Error struct { - e *spb.Status + s *Status } func (e *Error) Error() string { - return fmt.Sprintf("rpc error: code = %s desc = %s", codes.Code(e.e.GetCode()), e.e.GetMessage()) + return e.s.String() } // GRPCStatus returns the Status represented by se. func (e *Error) GRPCStatus() *Status { - return FromProto(e.e) + return e.s } // Is implements future error.Is functionality. @@ -158,5 +162,15 @@ func (e *Error) Is(target error) bool { if !ok { return false } - return proto.Equal(e.e, tse.e) + return proto.Equal(e.s.s, tse.s.s) +} + +// IsRestrictedControlPlaneCode returns whether the status includes a code +// restricted for control plane usage as defined by gRFC A54. +func IsRestrictedControlPlaneCode(s *Status) bool { + switch s.Code() { + case codes.InvalidArgument, codes.NotFound, codes.AlreadyExists, codes.FailedPrecondition, codes.Aborted, codes.OutOfRange, codes.DataLoss: + return true + } + return false } diff --git a/vendor/google.golang.org/grpc/internal/syscall/syscall_linux.go b/vendor/google.golang.org/grpc/internal/syscall/syscall_linux.go index 4b2964f2a1e..b3a72276dee 100644 --- a/vendor/google.golang.org/grpc/internal/syscall/syscall_linux.go +++ b/vendor/google.golang.org/grpc/internal/syscall/syscall_linux.go @@ -1,5 +1,3 @@ -// +build !appengine - /* * * Copyright 2018 gRPC authors. diff --git a/vendor/google.golang.org/grpc/internal/syscall/syscall_nonlinux.go b/vendor/google.golang.org/grpc/internal/syscall/syscall_nonlinux.go index 7913ef1dbfb..999f52cd75b 100644 --- a/vendor/google.golang.org/grpc/internal/syscall/syscall_nonlinux.go +++ b/vendor/google.golang.org/grpc/internal/syscall/syscall_nonlinux.go @@ -1,4 +1,5 @@ -// +build !linux appengine +//go:build !linux +// +build !linux /* * @@ -35,41 +36,41 @@ var logger = grpclog.Component("core") func log() { once.Do(func() { - logger.Info("CPU time info is unavailable on non-linux or appengine environment.") + logger.Info("CPU time info is unavailable on non-linux environments.") }) } -// GetCPUTime returns the how much CPU time has passed since the start of this process. -// It always returns 0 under non-linux or appengine environment. +// GetCPUTime returns the how much CPU time has passed since the start of this +// process. It always returns 0 under non-linux environments. func GetCPUTime() int64 { log() return 0 } -// Rusage is an empty struct under non-linux or appengine environment. +// Rusage is an empty struct under non-linux environments. type Rusage struct{} -// GetRusage is a no-op function under non-linux or appengine environment. +// GetRusage is a no-op function under non-linux environments. func GetRusage() *Rusage { log() return nil } // CPUTimeDiff returns the differences of user CPU time and system CPU time used -// between two Rusage structs. It a no-op function for non-linux or appengine environment. +// between two Rusage structs. It a no-op function for non-linux environments. func CPUTimeDiff(first *Rusage, latest *Rusage) (float64, float64) { log() return 0, 0 } -// SetTCPUserTimeout is a no-op function under non-linux or appengine environments +// SetTCPUserTimeout is a no-op function under non-linux environments. func SetTCPUserTimeout(conn net.Conn, timeout time.Duration) error { log() return nil } -// GetTCPUserTimeout is a no-op function under non-linux or appengine environments -// a negative return value indicates the operation is not supported +// GetTCPUserTimeout is a no-op function under non-linux environments. +// A negative return value indicates the operation is not supported func GetTCPUserTimeout(conn net.Conn) (int, error) { log() return -1, nil diff --git a/vendor/google.golang.org/grpc/internal/transport/controlbuf.go b/vendor/google.golang.org/grpc/internal/transport/controlbuf.go index 40ef23923fd..be5a9c81eb9 100644 --- a/vendor/google.golang.org/grpc/internal/transport/controlbuf.go +++ b/vendor/google.golang.org/grpc/internal/transport/controlbuf.go @@ -20,13 +20,19 @@ package transport import ( "bytes" + "errors" "fmt" + "net" "runtime" + "strconv" "sync" "sync/atomic" "golang.org/x/net/http2" "golang.org/x/net/http2/hpack" + "google.golang.org/grpc/internal/grpclog" + "google.golang.org/grpc/internal/grpcutil" + "google.golang.org/grpc/status" ) var updateHeaderTblSize = func(e *hpack.Encoder, v uint32) { @@ -128,6 +134,16 @@ type cleanupStream struct { func (c *cleanupStream) isTransportResponseFrame() bool { return c.rst } // Results in a RST_STREAM +type earlyAbortStream struct { + httpStatus uint32 + streamID uint32 + contentSubtype string + status *status.Status + rst bool +} + +func (*earlyAbortStream) isTransportResponseFrame() bool { return false } + type dataFrame struct { streamID uint32 endStream bool @@ -177,7 +193,7 @@ type goAway struct { code http2.ErrCode debugData []byte headsUp bool - closeConn bool + closeConn error // if set, loopyWriter will exit, resulting in conn closure } func (*goAway) isTransportResponseFrame() bool { return false } @@ -195,6 +211,14 @@ type outFlowControlSizeRequest struct { func (*outFlowControlSizeRequest) isTransportResponseFrame() bool { return false } +// closeConnection is an instruction to tell the loopy writer to flush the +// framer and exit, which will cause the transport's connection to be closed +// (by the client or server). The transport itself will close after the reader +// encounters the EOF caused by the connection closure. +type closeConnection struct{} + +func (closeConnection) isTransportResponseFrame() bool { return false } + type outStreamState int const ( @@ -284,7 +308,7 @@ type controlBuffer struct { // closed and nilled when transportResponseFrames drops below the // threshold. Both fields are protected by mu. transportResponseFrames int - trfChan atomic.Value // *chan struct{} + trfChan atomic.Value // chan struct{} } func newControlBuffer(done <-chan struct{}) *controlBuffer { @@ -298,10 +322,10 @@ func newControlBuffer(done <-chan struct{}) *controlBuffer { // throttle blocks if there are too many incomingSettings/cleanupStreams in the // controlbuf. func (c *controlBuffer) throttle() { - ch, _ := c.trfChan.Load().(*chan struct{}) + ch, _ := c.trfChan.Load().(chan struct{}) if ch != nil { select { - case <-*ch: + case <-ch: case <-c.done: } } @@ -335,8 +359,7 @@ func (c *controlBuffer) executeAndPut(f func(it interface{}) bool, it cbItem) (b if c.transportResponseFrames == maxQueuedTransportResponseFrames { // We are adding the frame that puts us over the threshold; create // a throttling channel. - ch := make(chan struct{}) - c.trfChan.Store(&ch) + c.trfChan.Store(make(chan struct{})) } } c.mu.Unlock() @@ -377,9 +400,9 @@ func (c *controlBuffer) get(block bool) (interface{}, error) { if c.transportResponseFrames == maxQueuedTransportResponseFrames { // We are removing the frame that put us over the // threshold; close and clear the throttling channel. - ch := c.trfChan.Load().(*chan struct{}) - close(*ch) - c.trfChan.Store((*chan struct{})(nil)) + ch := c.trfChan.Load().(chan struct{}) + close(ch) + c.trfChan.Store((chan struct{})(nil)) } c.transportResponseFrames-- } @@ -395,8 +418,7 @@ func (c *controlBuffer) get(block bool) (interface{}, error) { select { case <-c.ch: case <-c.done: - c.finish() - return nil, ErrConnClosing + return nil, errors.New("transport closed by client") } } } @@ -420,6 +442,14 @@ func (c *controlBuffer) finish() { hdr.onOrphaned(ErrConnClosing) } } + // In case throttle() is currently in flight, it needs to be unblocked. + // Otherwise, the transport may not close, since the transport is closed by + // the reader encountering the connection error. + ch, _ := c.trfChan.Load().(chan struct{}) + if ch != nil { + close(ch) + } + c.trfChan.Store((chan struct{})(nil)) c.mu.Unlock() } @@ -458,12 +488,14 @@ type loopyWriter struct { hEnc *hpack.Encoder // HPACK encoder. bdpEst *bdpEstimator draining bool + conn net.Conn + logger *grpclog.PrefixLogger // Side-specific handlers ssGoAwayHandler func(*goAway) (bool, error) } -func newLoopyWriter(s side, fr *framer, cbuf *controlBuffer, bdpEst *bdpEstimator) *loopyWriter { +func newLoopyWriter(s side, fr *framer, cbuf *controlBuffer, bdpEst *bdpEstimator, conn net.Conn, logger *grpclog.PrefixLogger) *loopyWriter { var buf bytes.Buffer l := &loopyWriter{ side: s, @@ -476,6 +508,8 @@ func newLoopyWriter(s side, fr *framer, cbuf *controlBuffer, bdpEst *bdpEstimato hBuf: &buf, hEnc: hpack.NewEncoder(&buf), bdpEst: bdpEst, + conn: conn, + logger: logger, } return l } @@ -493,23 +527,26 @@ const minBatchSize = 1000 // 2. Stream level flow control quota available. // // In each iteration of run loop, other than processing the incoming control -// frame, loopy calls processData, which processes one node from the activeStreams linked-list. -// This results in writing of HTTP2 frames into an underlying write buffer. -// When there's no more control frames to read from controlBuf, loopy flushes the write buffer. -// As an optimization, to increase the batch size for each flush, loopy yields the processor, once -// if the batch size is too low to give stream goroutines a chance to fill it up. +// frame, loopy calls processData, which processes one node from the +// activeStreams linked-list. This results in writing of HTTP2 frames into an +// underlying write buffer. When there's no more control frames to read from +// controlBuf, loopy flushes the write buffer. As an optimization, to increase +// the batch size for each flush, loopy yields the processor, once if the batch +// size is too low to give stream goroutines a chance to fill it up. +// +// Upon exiting, if the error causing the exit is not an I/O error, run() +// flushes and closes the underlying connection. Otherwise, the connection is +// left open to allow the I/O error to be encountered by the reader instead. func (l *loopyWriter) run() (err error) { defer func() { - if err == ErrConnClosing { - // Don't log ErrConnClosing as error since it happens - // 1. When the connection is closed by some other known issue. - // 2. User closed the connection. - // 3. A graceful close of connection. - if logger.V(logLevel) { - logger.Infof("transport: loopyWriter.run returning. %v", err) - } - err = nil + if l.logger.V(logLevel) { + l.logger.Infof("loopyWriter exiting with error: %v", err) } + if !isIOError(err) { + l.framer.writer.Flush() + l.conn.Close() + } + l.cbuf.finish() }() for { it, err := l.cbuf.get(true) @@ -554,7 +591,6 @@ func (l *loopyWriter) run() (err error) { } l.framer.writer.Flush() break hasdata - } } } @@ -563,11 +599,11 @@ func (l *loopyWriter) outgoingWindowUpdateHandler(w *outgoingWindowUpdate) error return l.framer.fr.WriteWindowUpdate(w.streamID, w.increment) } -func (l *loopyWriter) incomingWindowUpdateHandler(w *incomingWindowUpdate) error { +func (l *loopyWriter) incomingWindowUpdateHandler(w *incomingWindowUpdate) { // Otherwise update the quota. if w.streamID == 0 { l.sendQuota += w.increment - return nil + return } // Find the stream and update it. if str, ok := l.estdStreams[w.streamID]; ok { @@ -575,10 +611,9 @@ func (l *loopyWriter) incomingWindowUpdateHandler(w *incomingWindowUpdate) error if strQuota := int(l.oiws) - str.bytesOutStanding; strQuota > 0 && str.state == waitingOnStreamQuota { str.state = active l.activeStreams.enqueue(str) - return nil + return } } - return nil } func (l *loopyWriter) outgoingSettingsHandler(s *outgoingSettings) error { @@ -586,13 +621,11 @@ func (l *loopyWriter) outgoingSettingsHandler(s *outgoingSettings) error { } func (l *loopyWriter) incomingSettingsHandler(s *incomingSettings) error { - if err := l.applySettings(s.ss); err != nil { - return err - } + l.applySettings(s.ss) return l.framer.fr.WriteSettingsAck() } -func (l *loopyWriter) registerStreamHandler(h *registerStream) error { +func (l *loopyWriter) registerStreamHandler(h *registerStream) { str := &outStream{ id: h.streamID, state: empty, @@ -600,15 +633,14 @@ func (l *loopyWriter) registerStreamHandler(h *registerStream) error { wq: h.wq, } l.estdStreams[h.streamID] = str - return nil } func (l *loopyWriter) headerHandler(h *headerFrame) error { if l.side == serverSide { str, ok := l.estdStreams[h.streamID] if !ok { - if logger.V(logLevel) { - logger.Warningf("transport: loopy doesn't recognize the stream: %d", h.streamID) + if l.logger.V(logLevel) { + l.logger.Infof("Unrecognized streamID %d in loopyWriter", h.streamID) } return nil } @@ -635,19 +667,20 @@ func (l *loopyWriter) headerHandler(h *headerFrame) error { itl: &itemList{}, wq: h.wq, } - str.itl.enqueue(h) - return l.originateStream(str) + return l.originateStream(str, h) } -func (l *loopyWriter) originateStream(str *outStream) error { - hdr := str.itl.dequeue().(*headerFrame) - if err := hdr.initStream(str.id); err != nil { - if err == ErrConnClosing { - return err - } - // Other errors(errStreamDrain) need not close transport. +func (l *loopyWriter) originateStream(str *outStream, hdr *headerFrame) error { + // l.draining is set when handling GoAway. In which case, we want to avoid + // creating new streams. + if l.draining { + // TODO: provide a better error with the reason we are in draining. + hdr.onOrphaned(errStreamDrain) return nil } + if err := hdr.initStream(str.id); err != nil { + return err + } if err := l.writeHeader(str.id, hdr.endStream, hdr.hf, hdr.onWrite); err != nil { return err } @@ -662,8 +695,8 @@ func (l *loopyWriter) writeHeader(streamID uint32, endStream bool, hf []hpack.He l.hBuf.Reset() for _, f := range hf { if err := l.hEnc.WriteField(f); err != nil { - if logger.V(logLevel) { - logger.Warningf("transport: loopyWriter.writeHeader encountered error while encoding headers: %v", err) + if l.logger.V(logLevel) { + l.logger.Warningf("Encountered error while encoding headers: %v", err) } } } @@ -701,10 +734,10 @@ func (l *loopyWriter) writeHeader(streamID uint32, endStream bool, hf []hpack.He return nil } -func (l *loopyWriter) preprocessData(df *dataFrame) error { +func (l *loopyWriter) preprocessData(df *dataFrame) { str, ok := l.estdStreams[df.streamID] if !ok { - return nil + return } // If we got data for a stream it means that // stream was originated and the headers were sent out. @@ -713,7 +746,6 @@ func (l *loopyWriter) preprocessData(df *dataFrame) error { str.state = active l.activeStreams.enqueue(str) } - return nil } func (l *loopyWriter) pingHandler(p *ping) error { @@ -724,9 +756,8 @@ func (l *loopyWriter) pingHandler(p *ping) error { } -func (l *loopyWriter) outFlowControlSizeRequestHandler(o *outFlowControlSizeRequest) error { +func (l *loopyWriter) outFlowControlSizeRequestHandler(o *outFlowControlSizeRequest) { o.resp <- l.sendQuota - return nil } func (l *loopyWriter) cleanupStreamHandler(c *cleanupStream) error { @@ -743,8 +774,35 @@ func (l *loopyWriter) cleanupStreamHandler(c *cleanupStream) error { return err } } - if l.side == clientSide && l.draining && len(l.estdStreams) == 0 { - return ErrConnClosing + if l.draining && len(l.estdStreams) == 0 { + // Flush and close the connection; we are done with it. + return errors.New("finished processing active streams while in draining mode") + } + return nil +} + +func (l *loopyWriter) earlyAbortStreamHandler(eas *earlyAbortStream) error { + if l.side == clientSide { + return errors.New("earlyAbortStream not handled on client") + } + // In case the caller forgets to set the http status, default to 200. + if eas.httpStatus == 0 { + eas.httpStatus = 200 + } + headerFields := []hpack.HeaderField{ + {Name: ":status", Value: strconv.Itoa(int(eas.httpStatus))}, + {Name: "content-type", Value: grpcutil.ContentType(eas.contentSubtype)}, + {Name: "grpc-status", Value: strconv.Itoa(int(eas.status.Code()))}, + {Name: "grpc-message", Value: encodeGrpcMessage(eas.status.Message())}, + } + + if err := l.writeHeader(eas.streamID, true, headerFields, nil); err != nil { + return err + } + if eas.rst { + if err := l.framer.fr.WriteRSTStream(eas.streamID, http2.ErrCodeNo); err != nil { + return err + } } return nil } @@ -753,7 +811,8 @@ func (l *loopyWriter) incomingGoAwayHandler(*incomingGoAway) error { if l.side == clientSide { l.draining = true if len(l.estdStreams) == 0 { - return ErrConnClosing + // Flush and close the connection; we are done with it. + return errors.New("received GOAWAY with no active streams") } } return nil @@ -774,7 +833,7 @@ func (l *loopyWriter) goAwayHandler(g *goAway) error { func (l *loopyWriter) handle(i interface{}) error { switch i := i.(type) { case *incomingWindowUpdate: - return l.incomingWindowUpdateHandler(i) + l.incomingWindowUpdateHandler(i) case *outgoingWindowUpdate: return l.outgoingWindowUpdateHandler(i) case *incomingSettings: @@ -784,25 +843,32 @@ func (l *loopyWriter) handle(i interface{}) error { case *headerFrame: return l.headerHandler(i) case *registerStream: - return l.registerStreamHandler(i) + l.registerStreamHandler(i) case *cleanupStream: return l.cleanupStreamHandler(i) + case *earlyAbortStream: + return l.earlyAbortStreamHandler(i) case *incomingGoAway: return l.incomingGoAwayHandler(i) case *dataFrame: - return l.preprocessData(i) + l.preprocessData(i) case *ping: return l.pingHandler(i) case *goAway: return l.goAwayHandler(i) case *outFlowControlSizeRequest: - return l.outFlowControlSizeRequestHandler(i) + l.outFlowControlSizeRequestHandler(i) + case closeConnection: + // Just return a non-I/O error and run() will flush and close the + // connection. + return ErrConnClosing default: return fmt.Errorf("transport: unknown control message type %T", i) } + return nil } -func (l *loopyWriter) applySettings(ss []http2.Setting) error { +func (l *loopyWriter) applySettings(ss []http2.Setting) { for _, s := range ss { switch s.ID { case http2.SettingInitialWindowSize: @@ -821,7 +887,6 @@ func (l *loopyWriter) applySettings(ss []http2.Setting) error { updateHeaderTblSize(l.hEnc, s.Val) } } - return nil } // processData removes the first stream from active streams, writes out at most 16KB @@ -838,9 +903,9 @@ func (l *loopyWriter) processData() (bool, error) { dataItem := str.itl.peek().(*dataFrame) // Peek at the first data item this stream. // A data item is represented by a dataFrame, since it later translates into // multiple HTTP2 data frames. - // Every dataFrame has two buffers; h that keeps grpc-message header and d that is acutal data. + // Every dataFrame has two buffers; h that keeps grpc-message header and d that is actual data. // As an optimization to keep wire traffic low, data from d is copied to h to make as big as the - // maximum possilbe HTTP2 frame size. + // maximum possible HTTP2 frame size. if len(dataItem.h) == 0 && len(dataItem.d) == 0 { // Empty data frame // Client sends out empty data frame with endStream = true @@ -855,7 +920,7 @@ func (l *loopyWriter) processData() (bool, error) { return false, err } if err := l.cleanupStreamHandler(trailer.cleanup); err != nil { - return false, nil + return false, err } } else { l.activeStreams.enqueue(str) diff --git a/vendor/google.golang.org/grpc/internal/transport/defaults.go b/vendor/google.golang.org/grpc/internal/transport/defaults.go index 9fa306b2e07..bc8ee074749 100644 --- a/vendor/google.golang.org/grpc/internal/transport/defaults.go +++ b/vendor/google.golang.org/grpc/internal/transport/defaults.go @@ -47,3 +47,9 @@ const ( defaultClientMaxHeaderListSize = uint32(16 << 20) defaultServerMaxHeaderListSize = uint32(16 << 20) ) + +// MaxStreamID is the upper bound for the stream ID before the current +// transport gracefully closes and new transport is created for subsequent RPCs. +// This is set to 75% of 2^31-1. Streams are identified with an unsigned 31-bit +// integer. It's exported so that tests can override it. +var MaxStreamID = uint32(math.MaxInt32 * 3 / 4) diff --git a/vendor/google.golang.org/grpc/internal/transport/flowcontrol.go b/vendor/google.golang.org/grpc/internal/transport/flowcontrol.go index f262edd8ecd..97198c51588 100644 --- a/vendor/google.golang.org/grpc/internal/transport/flowcontrol.go +++ b/vendor/google.golang.org/grpc/internal/transport/flowcontrol.go @@ -136,12 +136,10 @@ type inFlow struct { // newLimit updates the inflow window to a new value n. // It assumes that n is always greater than the old limit. -func (f *inFlow) newLimit(n uint32) uint32 { +func (f *inFlow) newLimit(n uint32) { f.mu.Lock() - d := n - f.limit f.limit = n f.mu.Unlock() - return d } func (f *inFlow) maybeAdjust(n uint32) uint32 { diff --git a/vendor/google.golang.org/grpc/internal/transport/handler_server.go b/vendor/google.golang.org/grpc/internal/transport/handler_server.go index 05d3871e628..98f80e3fa00 100644 --- a/vendor/google.golang.org/grpc/internal/transport/handler_server.go +++ b/vendor/google.golang.org/grpc/internal/transport/handler_server.go @@ -39,6 +39,7 @@ import ( "golang.org/x/net/http2" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" + "google.golang.org/grpc/internal/grpclog" "google.golang.org/grpc/internal/grpcutil" "google.golang.org/grpc/metadata" "google.golang.org/grpc/peer" @@ -46,24 +47,32 @@ import ( "google.golang.org/grpc/status" ) -// NewServerHandlerTransport returns a ServerTransport handling gRPC -// from inside an http.Handler. It requires that the http Server -// supports HTTP/2. -func NewServerHandlerTransport(w http.ResponseWriter, r *http.Request, stats stats.Handler) (ServerTransport, error) { +// NewServerHandlerTransport returns a ServerTransport handling gRPC from +// inside an http.Handler, or writes an HTTP error to w and returns an error. +// It requires that the http Server supports HTTP/2. +func NewServerHandlerTransport(w http.ResponseWriter, r *http.Request, stats []stats.Handler) (ServerTransport, error) { if r.ProtoMajor != 2 { - return nil, errors.New("gRPC requires HTTP/2") + msg := "gRPC requires HTTP/2" + http.Error(w, msg, http.StatusBadRequest) + return nil, errors.New(msg) } if r.Method != "POST" { - return nil, errors.New("invalid gRPC request method") + msg := fmt.Sprintf("invalid gRPC request method %q", r.Method) + http.Error(w, msg, http.StatusBadRequest) + return nil, errors.New(msg) } contentType := r.Header.Get("Content-Type") // TODO: do we assume contentType is lowercase? we did before contentSubtype, validContentType := grpcutil.ContentSubtype(contentType) if !validContentType { - return nil, errors.New("invalid gRPC request content-type") + msg := fmt.Sprintf("invalid gRPC request content-type %q", contentType) + http.Error(w, msg, http.StatusUnsupportedMediaType) + return nil, errors.New(msg) } if _, ok := w.(http.Flusher); !ok { - return nil, errors.New("gRPC requires a ResponseWriter supporting http.Flusher") + msg := "gRPC requires a ResponseWriter supporting http.Flusher" + http.Error(w, msg, http.StatusInternalServerError) + return nil, errors.New(msg) } st := &serverHandlerTransport{ @@ -75,11 +84,14 @@ func NewServerHandlerTransport(w http.ResponseWriter, r *http.Request, stats sta contentSubtype: contentSubtype, stats: stats, } + st.logger = prefixLoggerForServerHandlerTransport(st) if v := r.Header.Get("grpc-timeout"); v != "" { to, err := decodeTimeout(v) if err != nil { - return nil, status.Errorf(codes.Internal, "malformed time-out: %v", err) + msg := fmt.Sprintf("malformed grpc-timeout: %v", err) + http.Error(w, msg, http.StatusBadRequest) + return nil, status.Error(codes.Internal, msg) } st.timeoutSet = true st.timeout = to @@ -97,7 +109,9 @@ func NewServerHandlerTransport(w http.ResponseWriter, r *http.Request, stats sta for _, v := range vv { v, err := decodeMetadataHeader(k, v) if err != nil { - return nil, status.Errorf(codes.Internal, "malformed binary metadata: %v", err) + msg := fmt.Sprintf("malformed binary metadata %q in header %q: %v", v, k, err) + http.Error(w, msg, http.StatusBadRequest) + return nil, status.Error(codes.Internal, msg) } metakv = append(metakv, k, v) } @@ -138,16 +152,19 @@ type serverHandlerTransport struct { // TODO make sure this is consistent across handler_server and http2_server contentSubtype string - stats stats.Handler + stats []stats.Handler + logger *grpclog.PrefixLogger } -func (ht *serverHandlerTransport) Close() error { - ht.closeOnce.Do(ht.closeCloseChanOnce) - return nil +func (ht *serverHandlerTransport) Close(err error) { + ht.closeOnce.Do(func() { + if ht.logger.V(logLevel) { + ht.logger.Infof("Closing: %v", err) + } + close(ht.closedCh) + }) } -func (ht *serverHandlerTransport) closeCloseChanOnce() { close(ht.closedCh) } - func (ht *serverHandlerTransport) RemoteAddr() net.Addr { return strAddr(ht.req.RemoteAddr) } // strAddr is a net.Addr backed by either a TCP "ip:port" string, or @@ -229,15 +246,15 @@ func (ht *serverHandlerTransport) WriteStatus(s *Stream, st *status.Status) erro }) if err == nil { // transport has not been closed - if ht.stats != nil { - // Note: The trailer fields are compressed with hpack after this call returns. - // No WireLength field is set here. - ht.stats.HandleRPC(s.Context(), &stats.OutTrailer{ + // Note: The trailer fields are compressed with hpack after this call returns. + // No WireLength field is set here. + for _, sh := range ht.stats { + sh.HandleRPC(s.Context(), &stats.OutTrailer{ Trailer: s.trailer.Copy(), }) } } - ht.Close() + ht.Close(errors.New("finished writing status")) return err } @@ -315,10 +332,10 @@ func (ht *serverHandlerTransport) WriteHeader(s *Stream, md metadata.MD) error { }) if err == nil { - if ht.stats != nil { + for _, sh := range ht.stats { // Note: The header fields are compressed with hpack after this call returns. // No WireLength field is set here. - ht.stats.HandleRPC(s.Context(), &stats.OutHeader{ + sh.HandleRPC(s.Context(), &stats.OutHeader{ Header: md.Copy(), Compression: s.sendCompress, }) @@ -347,7 +364,7 @@ func (ht *serverHandlerTransport) HandleStreams(startStream func(*Stream), trace case <-ht.req.Context().Done(): } cancel() - ht.Close() + ht.Close(errors.New("request is done processing")) }() req := ht.req @@ -370,14 +387,14 @@ func (ht *serverHandlerTransport) HandleStreams(startStream func(*Stream), trace } ctx = metadata.NewIncomingContext(ctx, ht.headerMD) s.ctx = peer.NewContext(ctx, pr) - if ht.stats != nil { - s.ctx = ht.stats.TagRPC(s.ctx, &stats.RPCTagInfo{FullMethodName: s.method}) + for _, sh := range ht.stats { + s.ctx = sh.TagRPC(s.ctx, &stats.RPCTagInfo{FullMethodName: s.method}) inHeader := &stats.InHeader{ FullMethod: s.method, RemoteAddr: ht.RemoteAddr(), Compression: s.recvCompress, } - ht.stats.HandleRPC(s.ctx, inHeader) + sh.HandleRPC(s.ctx, inHeader) } s.trReader = &transportReader{ reader: &recvBufferReader{ctx: s.ctx, ctxDone: s.ctx.Done(), recv: s.buf, freeBuffer: func(*bytes.Buffer) {}}, @@ -436,17 +453,17 @@ func (ht *serverHandlerTransport) IncrMsgSent() {} func (ht *serverHandlerTransport) IncrMsgRecv() {} -func (ht *serverHandlerTransport) Drain() { +func (ht *serverHandlerTransport) Drain(debugData string) { panic("Drain() is not implemented") } // mapRecvMsgError returns the non-nil err into the appropriate // error value as expected by callers of *grpc.parser.recvMsg. // In particular, in can only be: -// * io.EOF -// * io.ErrUnexpectedEOF -// * of type transport.ConnectionError -// * an error from the status package +// - io.EOF +// - io.ErrUnexpectedEOF +// - of type transport.ConnectionError +// - an error from the status package func mapRecvMsgError(err error) error { if err == io.EOF || err == io.ErrUnexpectedEOF { return err diff --git a/vendor/google.golang.org/grpc/internal/transport/http2_client.go b/vendor/google.golang.org/grpc/internal/transport/http2_client.go index 8902b7f90d9..326bf084800 100644 --- a/vendor/google.golang.org/grpc/internal/transport/http2_client.go +++ b/vendor/google.golang.org/grpc/internal/transport/http2_client.go @@ -24,6 +24,8 @@ import ( "io" "math" "net" + "net/http" + "path/filepath" "strconv" "strings" "sync" @@ -32,15 +34,17 @@ import ( "golang.org/x/net/http2" "golang.org/x/net/http2/hpack" - "google.golang.org/grpc/internal/grpcutil" - imetadata "google.golang.org/grpc/internal/metadata" - "google.golang.org/grpc/internal/transport/networktype" - "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" - "google.golang.org/grpc/internal" "google.golang.org/grpc/internal/channelz" + icredentials "google.golang.org/grpc/internal/credentials" + "google.golang.org/grpc/internal/grpclog" + "google.golang.org/grpc/internal/grpcsync" + "google.golang.org/grpc/internal/grpcutil" + imetadata "google.golang.org/grpc/internal/metadata" + istatus "google.golang.org/grpc/internal/status" "google.golang.org/grpc/internal/syscall" + "google.golang.org/grpc/internal/transport/networktype" "google.golang.org/grpc/keepalive" "google.golang.org/grpc/metadata" "google.golang.org/grpc/peer" @@ -56,11 +60,15 @@ var clientConnectionCounter uint64 // http2Client implements the ClientTransport interface with HTTP2. type http2Client struct { - lastRead int64 // Keep this field 64-bit aligned. Accessed atomically. - ctx context.Context - cancel context.CancelFunc - ctxDone <-chan struct{} // Cache the ctx.Done() chan. - userAgent string + lastRead int64 // Keep this field 64-bit aligned. Accessed atomically. + ctx context.Context + cancel context.CancelFunc + ctxDone <-chan struct{} // Cache the ctx.Done() chan. + userAgent string + // address contains the resolver returned address for this transport. + // If the `ServerName` field is set, it takes precedence over `CallHdr.Host` + // passed to `NewStream`, when determining the :authority header. + address resolver.Address md metadata.MD conn net.Conn // underlying communication channel loopy *loopyWriter @@ -77,6 +85,7 @@ type http2Client struct { framer *framer // controlBuf delivers all the control related tasks (e.g., window // updates, reset streams, and various settings) to the controller. + // Do not access controlBuf with mu held. controlBuf *controlBuffer fc *trInFlow // The scheme used: https if TLS is on, http otherwise. @@ -89,7 +98,7 @@ type http2Client struct { kp keepalive.ClientParameters keepaliveEnabled bool - statsHandler stats.Handler + statsHandlers []stats.Handler initialWindowSize int32 @@ -97,17 +106,15 @@ type http2Client struct { maxSendHeaderListSize *uint32 bdpEst *bdpEstimator - // onPrefaceReceipt is a callback that client transport calls upon - // receiving server preface to signal that a succefull HTTP2 - // connection was established. - onPrefaceReceipt func() maxConcurrentStreams uint32 streamQuota int64 streamsQuotaAvailable chan struct{} waitingStreams uint32 nextID uint32 + registeredCompressors string + // Do not access controlBuf with mu held. mu sync.Mutex // guard the following variables state transportState activeStreams map[uint32]*Stream @@ -116,6 +123,9 @@ type http2Client struct { // goAwayReason records the http2.ErrCode and debug data received with the // GoAway frame. goAwayReason GoAwayReason + // goAwayDebugMessage contains a detailed human readable string about a + // GoAway frame, useful for error messages. + goAwayDebugMessage string // A condition variable used to signal when the keepalive goroutine should // go dormant. The condition for dormancy is based on the number of active // streams and the `PermitWithoutStream` keepalive client parameter. And @@ -128,28 +138,35 @@ type http2Client struct { kpDormant bool // Fields below are for channelz metric collection. - channelzID int64 // channelz unique identification number + channelzID *channelz.Identifier czData *channelzData - onGoAway func(GoAwayReason) - onClose func() + onClose func(GoAwayReason) bufferPool *bufferPool connectionID uint64 + logger *grpclog.PrefixLogger } func dial(ctx context.Context, fn func(context.Context, string) (net.Conn, error), addr resolver.Address, useProxy bool, grpcUA string) (net.Conn, error) { address := addr.Addr networkType, ok := networktype.Get(addr) if fn != nil { + // Special handling for unix scheme with custom dialer. Back in the day, + // we did not have a unix resolver and therefore targets with a unix + // scheme would end up using the passthrough resolver. So, user's used a + // custom dialer in this case and expected the original dial target to + // be passed to the custom dialer. Now, we have a unix resolver. But if + // a custom dialer is specified, we want to retain the old behavior in + // terms of the address being passed to the custom dialer. if networkType == "unix" && !strings.HasPrefix(address, "\x00") { - // For backward compatibility, if the user dialed "unix:///path", - // the passthrough resolver would be used and the user's custom - // dialer would see "unix:///path". Since the unix resolver is used - // and the address is now "/path", prepend "unix://" so the user's - // custom dialer sees the same address. - return fn(ctx, "unix://"+address) + // Supported unix targets are either "unix://absolute-path" or + // "unix:relative-path". + if filepath.IsAbs(address) { + return fn(ctx, "unix://"+address) + } + return fn(ctx, "unix:"+address) } return fn(ctx, address) } @@ -181,7 +198,7 @@ func isTemporary(err error) bool { // newHTTP2Client constructs a connected ClientTransport to addr based on HTTP2 // and starts to receive messages on it. Non-nil error returns if construction // fails. -func newHTTP2Client(connectCtx, ctx context.Context, addr resolver.Address, opts ConnectOptions, onPrefaceReceipt func(), onGoAway func(GoAwayReason), onClose func()) (_ *http2Client, err error) { +func newHTTP2Client(connectCtx, ctx context.Context, addr resolver.Address, opts ConnectOptions, onClose func(GoAwayReason)) (_ *http2Client, err error) { scheme := "http" ctx, cancel := context.WithCancel(ctx) defer func() { @@ -190,19 +207,51 @@ func newHTTP2Client(connectCtx, ctx context.Context, addr resolver.Address, opts } }() + // gRPC, resolver, balancer etc. can specify arbitrary data in the + // Attributes field of resolver.Address, which is shoved into connectCtx + // and passed to the dialer and credential handshaker. This makes it possible for + // address specific arbitrary data to reach custom dialers and credential handshakers. + connectCtx = icredentials.NewClientHandshakeInfoContext(connectCtx, credentials.ClientHandshakeInfo{Attributes: addr.Attributes}) + conn, err := dial(connectCtx, opts.Dialer, addr, opts.UseProxy, opts.UserAgent) if err != nil { if opts.FailOnNonTempDialError { return nil, connectionErrorf(isTemporary(err), err, "transport: error while dialing: %v", err) } - return nil, connectionErrorf(true, err, "transport: Error while dialing %v", err) + return nil, connectionErrorf(true, err, "transport: Error while dialing: %v", err) } + // Any further errors will close the underlying connection defer func(conn net.Conn) { if err != nil { conn.Close() } }(conn) + + // The following defer and goroutine monitor the connectCtx for cancelation + // and deadline. On context expiration, the connection is hard closed and + // this function will naturally fail as a result. Otherwise, the defer + // waits for the goroutine to exit to prevent the context from being + // monitored (and to prevent the connection from ever being closed) after + // returning from this function. + ctxMonitorDone := grpcsync.NewEvent() + newClientCtx, newClientDone := context.WithCancel(connectCtx) + defer func() { + newClientDone() // Awaken the goroutine below if connectCtx hasn't expired. + <-ctxMonitorDone.Done() // Wait for the goroutine below to exit. + }() + go func(conn net.Conn) { + defer ctxMonitorDone.Fire() // Signal this goroutine has exited. + <-newClientCtx.Done() // Block until connectCtx expires or the defer above executes. + if err := connectCtx.Err(); err != nil { + // connectCtx expired before exiting the function. Hard close the connection. + if logger.V(logLevel) { + logger.Infof("Aborting due to connect deadline expiring: %v", err) + } + conn.Close() + } + }(conn) + kp := opts.KeepaliveParams // Validate keepalive parameters. if kp.Time == 0 { @@ -234,12 +283,6 @@ func newHTTP2Client(connectCtx, ctx context.Context, addr resolver.Address, opts } } if transportCreds != nil { - // gRPC, resolver, balancer etc. can specify arbitrary data in the - // Attributes field of resolver.Address, which is shoved into connectCtx - // and passed to the credential handshaker. This makes it possible for - // address specific arbitrary data to reach the credential handshaker. - contextWithHandshakeInfo := internal.NewClientHandshakeInfoContext.(func(context.Context, credentials.ClientHandshakeInfo) context.Context) - connectCtx = contextWithHandshakeInfo(connectCtx, credentials.ClientHandshakeInfo{Attributes: addr.Attributes}) conn, authInfo, err = transportCreds.ClientHandshake(connectCtx, addr.ServerName, conn) if err != nil { return nil, connectionErrorf(isTemporary(err), err, "transport: authentication handshake failed: %v", err) @@ -278,6 +321,8 @@ func newHTTP2Client(connectCtx, ctx context.Context, addr resolver.Address, opts ctxDone: ctx.Done(), // Cache Done chan. cancel: cancel, userAgent: opts.UserAgent, + registeredCompressors: grpcutil.RegisteredCompressors(), + address: addr, conn: conn, remoteAddr: conn.RemoteAddr(), localAddr: conn.LocalAddr(), @@ -292,19 +337,20 @@ func newHTTP2Client(connectCtx, ctx context.Context, addr resolver.Address, opts isSecure: isSecure, perRPCCreds: perRPCCreds, kp: kp, - statsHandler: opts.StatsHandler, + statsHandlers: opts.StatsHandlers, initialWindowSize: initialWindowSize, - onPrefaceReceipt: onPrefaceReceipt, nextID: 1, maxConcurrentStreams: defaultMaxStreamsClient, streamQuota: defaultMaxStreamsClient, streamsQuotaAvailable: make(chan struct{}, 1), czData: new(channelzData), - onGoAway: onGoAway, - onClose: onClose, keepaliveEnabled: keepaliveEnabled, bufferPool: newBufferPool(), + onClose: onClose, } + t.logger = prefixLoggerForClientTransport(t) + // Add peer information to the http2client context. + t.ctx = peer.NewContext(t.ctx, t.getPeer()) if md, ok := addr.Metadata.(*metadata.MD); ok { t.md = *md @@ -322,37 +368,51 @@ func newHTTP2Client(connectCtx, ctx context.Context, addr resolver.Address, opts updateFlowControl: t.updateFlowControl, } } - if t.statsHandler != nil { - t.ctx = t.statsHandler.TagConn(t.ctx, &stats.ConnTagInfo{ + for _, sh := range t.statsHandlers { + t.ctx = sh.TagConn(t.ctx, &stats.ConnTagInfo{ RemoteAddr: t.remoteAddr, LocalAddr: t.localAddr, }) connBegin := &stats.ConnBegin{ Client: true, } - t.statsHandler.HandleConn(t.ctx, connBegin) + sh.HandleConn(t.ctx, connBegin) } - if channelz.IsOn() { - t.channelzID = channelz.RegisterNormalSocket(t, opts.ChannelzParentID, fmt.Sprintf("%s -> %s", t.localAddr, t.remoteAddr)) + t.channelzID, err = channelz.RegisterNormalSocket(t, opts.ChannelzParentID, fmt.Sprintf("%s -> %s", t.localAddr, t.remoteAddr)) + if err != nil { + return nil, err } if t.keepaliveEnabled { t.kpDormancyCond = sync.NewCond(&t.mu) go t.keepalive() } - // Start the reader goroutine for incoming message. Each transport has - // a dedicated goroutine which reads HTTP2 frame from network. Then it - // dispatches the frame to the corresponding stream entity. - go t.reader() + + // Start the reader goroutine for incoming messages. Each transport has a + // dedicated goroutine which reads HTTP2 frames from the network. Then it + // dispatches the frame to the corresponding stream entity. When the + // server preface is received, readerErrCh is closed. If an error occurs + // first, an error is pushed to the channel. This must be checked before + // returning from this function. + readerErrCh := make(chan error, 1) + go t.reader(readerErrCh) + defer func() { + if err == nil { + err = <-readerErrCh + } + if err != nil { + t.Close(err) + } + }() // Send connection preface to server. n, err := t.conn.Write(clientPreface) if err != nil { - t.Close() - return nil, connectionErrorf(true, err, "transport: failed to write client preface: %v", err) + err = connectionErrorf(true, err, "transport: failed to write client preface: %v", err) + return nil, err } if n != len(clientPreface) { - t.Close() - return nil, connectionErrorf(true, err, "transport: preface mismatch, wrote %d bytes; want %d", n, len(clientPreface)) + err = connectionErrorf(true, nil, "transport: preface mismatch, wrote %d bytes; want %d", n, len(clientPreface)) + return nil, err } var ss []http2.Setting @@ -370,14 +430,14 @@ func newHTTP2Client(connectCtx, ctx context.Context, addr resolver.Address, opts } err = t.framer.fr.WriteSettings(ss...) if err != nil { - t.Close() - return nil, connectionErrorf(true, err, "transport: failed to write initial settings frame: %v", err) + err = connectionErrorf(true, err, "transport: failed to write initial settings frame: %v", err) + return nil, err } // Adjust the connection flow control window if needed. if delta := uint32(icwz - defaultWindowSize); delta > 0 { if err := t.framer.fr.WriteWindowUpdate(0, delta); err != nil { - t.Close() - return nil, connectionErrorf(true, err, "transport: failed to write window update: %v", err) + err = connectionErrorf(true, err, "transport: failed to write window update: %v", err) + return nil, err } } @@ -387,18 +447,8 @@ func newHTTP2Client(connectCtx, ctx context.Context, addr resolver.Address, opts return nil, err } go func() { - t.loopy = newLoopyWriter(clientSide, t.framer, t.controlBuf, t.bdpEst) - err := t.loopy.run() - if err != nil { - if logger.V(logLevel) { - logger.Errorf("transport: loopyWriter.run returning. Err: %v", err) - } - } - // If it's a connection error, let reader goroutine handle it - // since there might be data in the buffers. - if _, ok := err.(net.Error); !ok { - t.conn.Close() - } + t.loopy = newLoopyWriter(clientSide, t.framer, t.controlBuf, t.bdpEst, t.conn, t.logger) + t.loopy.run() close(t.writerDone) }() return t, nil @@ -414,6 +464,7 @@ func (t *http2Client) newStream(ctx context.Context, callHdr *CallHdr) *Stream { buf: newRecvBuffer(), headerChan: make(chan struct{}), contentSubtype: callHdr.ContentSubtype, + doneFunc: callHdr.DoneFunc, } s.wq = newWriteQuota(defaultWriteQuota, s.done) s.requestRead = func(n int) { @@ -443,7 +494,7 @@ func (t *http2Client) newStream(ctx context.Context, callHdr *CallHdr) *Stream { func (t *http2Client) getPeer() *peer.Peer { return &peer.Peer{ Addr: t.remoteAddr, - AuthInfo: t.authInfo, + AuthInfo: t.authInfo, // Can be nil } } @@ -453,7 +504,7 @@ func (t *http2Client) createHeaderFields(ctx context.Context, callHdr *CallHdr) Method: callHdr.Method, AuthInfo: t.authInfo, } - ctxWithRequestInfo := internal.NewRequestInfoContext.(func(context.Context, credentials.RequestInfo) context.Context)(ctx, ri) + ctxWithRequestInfo := icredentials.NewRequestInfoContext(ctx, ri) authData, err := t.getTrAuthData(ctxWithRequestInfo, aud) if err != nil { return nil, err @@ -479,9 +530,22 @@ func (t *http2Client) createHeaderFields(ctx context.Context, callHdr *CallHdr) headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-previous-rpc-attempts", Value: strconv.Itoa(callHdr.PreviousAttempts)}) } + registeredCompressors := t.registeredCompressors if callHdr.SendCompress != "" { headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-encoding", Value: callHdr.SendCompress}) - headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-accept-encoding", Value: callHdr.SendCompress}) + // Include the outgoing compressor name when compressor is not registered + // via encoding.RegisterCompressor. This is possible when client uses + // WithCompressor dial option. + if !grpcutil.IsCompressorNameRegistered(callHdr.SendCompress) { + if registeredCompressors != "" { + registeredCompressors += "," + } + registeredCompressors += callHdr.SendCompress + } + } + + if registeredCompressors != "" { + headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-accept-encoding", Value: registeredCompressors}) } if dl, ok := ctx.Deadline(); ok { // Send out timeout regardless its value. The server can detect timeout context by itself. @@ -561,11 +625,15 @@ func (t *http2Client) getTrAuthData(ctx context.Context, audience string) (map[s for _, c := range t.perRPCCreds { data, err := c.GetRequestMetadata(ctx, audience) if err != nil { - if _, ok := status.FromError(err); ok { + if st, ok := status.FromError(err); ok { + // Restrict the code to the list allowed by gRFC A54. + if istatus.IsRestrictedControlPlaneCode(st) { + err = status.Errorf(codes.Internal, "transport: received per-RPC creds error with illegal status: %v", err) + } return nil, err } - return nil, status.Errorf(codes.Unauthenticated, "transport: %v", err) + return nil, status.Errorf(codes.Unauthenticated, "transport: per-RPC creds failed due to error: %v", err) } for k, v := range data { // Capital header names are illegal in HTTP/2. @@ -590,7 +658,14 @@ func (t *http2Client) getCallAuthData(ctx context.Context, audience string, call } data, err := callCreds.GetRequestMetadata(ctx, audience) if err != nil { - return nil, status.Errorf(codes.Internal, "transport: %v", err) + if st, ok := status.FromError(err); ok { + // Restrict the code to the list allowed by gRFC A54. + if istatus.IsRestrictedControlPlaneCode(st) { + err = status.Errorf(codes.Internal, "transport: received per-RPC creds error with illegal status: %v", err) + } + return nil, err + } + return nil, status.Errorf(codes.Internal, "transport: per-RPC creds failed due to error: %v", err) } callAuthData = make(map[string]string, len(data)) for k, v := range data { @@ -602,26 +677,46 @@ func (t *http2Client) getCallAuthData(ctx context.Context, audience string, call return callAuthData, nil } -// PerformedIOError wraps an error to indicate IO may have been performed -// before the error occurred. -type PerformedIOError struct { +// NewStreamError wraps an error and reports additional information. Typically +// NewStream errors result in transparent retry, as they mean nothing went onto +// the wire. However, there are two notable exceptions: +// +// 1. If the stream headers violate the max header list size allowed by the +// server. It's possible this could succeed on another transport, even if +// it's unlikely, but do not transparently retry. +// 2. If the credentials errored when requesting their headers. In this case, +// it's possible a retry can fix the problem, but indefinitely transparently +// retrying is not appropriate as it is likely the credentials, if they can +// eventually succeed, would need I/O to do so. +type NewStreamError struct { Err error + + AllowTransparentRetry bool } -// Error implements error. -func (p PerformedIOError) Error() string { - return p.Err.Error() +func (e NewStreamError) Error() string { + return e.Err.Error() } // NewStream creates a stream and registers it into the transport as "active" -// streams. -func (t *http2Client) NewStream(ctx context.Context, callHdr *CallHdr) (_ *Stream, err error) { +// streams. All non-nil errors returned will be *NewStreamError. +func (t *http2Client) NewStream(ctx context.Context, callHdr *CallHdr) (*Stream, error) { ctx = peer.NewContext(ctx, t.getPeer()) + + // ServerName field of the resolver returned address takes precedence over + // Host field of CallHdr to determine the :authority header. This is because, + // the ServerName field takes precedence for server authentication during + // TLS handshake, and the :authority header should match the value used + // for server authentication. + if t.address.ServerName != "" { + newCallHdr := *callHdr + newCallHdr.Host = t.address.ServerName + callHdr = &newCallHdr + } + headerFields, err := t.createHeaderFields(ctx, callHdr) if err != nil { - // We may have performed I/O in the per-RPC creds callback, so do not - // allow transparent retry. - return nil, PerformedIOError{err} + return nil, &NewStreamError{Err: err, AllowTransparentRetry: false} } s := t.newStream(ctx, callHdr) cleanup := func(err error) { @@ -643,17 +738,13 @@ func (t *http2Client) NewStream(ctx context.Context, callHdr *CallHdr) (_ *Strea endStream: false, initStream: func(id uint32) error { t.mu.Lock() - if state := t.state; state != reachable { + // TODO: handle transport closure in loopy instead and remove this + // initStream is never called when transport is draining. + if t.state == closing { t.mu.Unlock() - // Do a quick cleanup. - err := error(errStreamDrain) - if state == closing { - err = ErrConnClosing - } - cleanup(err) - return err + cleanup(ErrConnClosing) + return ErrConnClosing } - t.activeStreams[id] = s if channelz.IsOn() { atomic.AddInt64(&t.czData.streamsStarted, 1) atomic.StoreInt64(&t.czData.lastStreamCreatedTime, time.Now().UnixNano()) @@ -670,6 +761,7 @@ func (t *http2Client) NewStream(ctx context.Context, callHdr *CallHdr) (_ *Strea } firstTry := true var ch chan struct{} + transportDrainRequired := false checkForStreamQuota := func(it interface{}) bool { if t.streamQuota <= 0 { // Can go negative if server decreases it. if firstTry { @@ -685,8 +777,20 @@ func (t *http2Client) NewStream(ctx context.Context, callHdr *CallHdr) (_ *Strea h := it.(*headerFrame) h.streamID = t.nextID t.nextID += 2 + + // Drain client transport if nextID > MaxStreamID which signals gRPC that + // the connection is closed and a new one must be created for subsequent RPCs. + transportDrainRequired = t.nextID > MaxStreamID + s.id = h.streamID s.fc = &inFlow{limit: uint32(t.initialWindowSize)} + t.mu.Lock() + if t.state == draining || t.activeStreams == nil { // Can be niled from Close(). + t.mu.Unlock() + return false // Don't create a stream if the transport is already closed. + } + t.activeStreams[s.id] = s + t.mu.Unlock() if t.streamQuota > 0 && t.waitingStreams > 0 { select { case t.streamsQuotaAvailable <- struct{}{}: @@ -712,52 +816,56 @@ func (t *http2Client) NewStream(ctx context.Context, callHdr *CallHdr) (_ *Strea } for { success, err := t.controlBuf.executeAndPut(func(it interface{}) bool { - if !checkForStreamQuota(it) { - return false - } - if !checkForHeaderListSize(it) { - return false - } - return true + return checkForHeaderListSize(it) && checkForStreamQuota(it) }, hdr) if err != nil { - return nil, err + // Connection closed. + return nil, &NewStreamError{Err: err, AllowTransparentRetry: true} } if success { break } if hdrListSizeErr != nil { - return nil, hdrListSizeErr + return nil, &NewStreamError{Err: hdrListSizeErr} } firstTry = false select { case <-ch: - case <-s.ctx.Done(): - return nil, ContextErr(s.ctx.Err()) + case <-ctx.Done(): + return nil, &NewStreamError{Err: ContextErr(ctx.Err())} case <-t.goAway: - return nil, errStreamDrain + return nil, &NewStreamError{Err: errStreamDrain, AllowTransparentRetry: true} case <-t.ctx.Done(): - return nil, ErrConnClosing + return nil, &NewStreamError{Err: ErrConnClosing, AllowTransparentRetry: true} } } - if t.statsHandler != nil { + if len(t.statsHandlers) != 0 { header, ok := metadata.FromOutgoingContext(ctx) if ok { header.Set("user-agent", t.userAgent) } else { header = metadata.Pairs("user-agent", t.userAgent) } - // Note: The header fields are compressed with hpack after this call returns. - // No WireLength field is set here. - outHeader := &stats.OutHeader{ - Client: true, - FullMethod: callHdr.Method, - RemoteAddr: t.remoteAddr, - LocalAddr: t.localAddr, - Compression: callHdr.SendCompress, - Header: header, + for _, sh := range t.statsHandlers { + // Note: The header fields are compressed with hpack after this call returns. + // No WireLength field is set here. + // Note: Creating a new stats object to prevent pollution. + outHeader := &stats.OutHeader{ + Client: true, + FullMethod: callHdr.Method, + RemoteAddr: t.remoteAddr, + LocalAddr: t.localAddr, + Compression: callHdr.SendCompress, + Header: header, + } + sh.HandleRPC(s.ctx, outHeader) + } + } + if transportDrainRequired { + if t.logger.V(logLevel) { + t.logger.Infof("Draining transport: t.nextID > MaxStreamID") } - t.statsHandler.HandleRPC(s.ctx, outHeader) + t.GracefulClose() } return s, nil } @@ -832,25 +940,29 @@ func (t *http2Client) closeStream(s *Stream, err error, rst bool, rstCode http2. t.controlBuf.executeAndPut(addBackStreamQuota, cleanup) // This will unblock write. close(s.done) + if s.doneFunc != nil { + s.doneFunc() + } } // Close kicks off the shutdown process of the transport. This should be called // only once on a transport. Once it is called, the transport should not be // accessed any more. -// -// This method blocks until the addrConn that initiated this transport is -// re-connected. This happens because t.onClose() begins reconnect logic at the -// addrConn level and blocks until the addrConn is successfully connected. -func (t *http2Client) Close() error { +func (t *http2Client) Close(err error) { t.mu.Lock() - // Make sure we only Close once. + // Make sure we only close once. if t.state == closing { t.mu.Unlock() - return nil + return + } + if t.logger.V(logLevel) { + t.logger.Infof("Closing: %v", err) + } + // Call t.onClose ASAP to prevent the client from attempting to create new + // streams. + if t.state != draining { + t.onClose(GoAwayInvalid) } - // Call t.onClose before setting the state to closing to prevent the client - // from attempting to create new streams ASAP. - t.onClose() t.state = closing streams := t.activeStreams t.activeStreams = nil @@ -862,21 +974,30 @@ func (t *http2Client) Close() error { t.mu.Unlock() t.controlBuf.finish() t.cancel() - err := t.conn.Close() - if channelz.IsOn() { - channelz.RemoveEntry(t.channelzID) + t.conn.Close() + channelz.RemoveEntry(t.channelzID) + // Append info about previous goaways if there were any, since this may be important + // for understanding the root cause for this connection to be closed. + _, goAwayDebugMessage := t.GetGoAwayReason() + + var st *status.Status + if len(goAwayDebugMessage) > 0 { + st = status.Newf(codes.Unavailable, "closing transport due to: %v, received prior goaway: %v", err, goAwayDebugMessage) + err = st.Err() + } else { + st = status.New(codes.Unavailable, err.Error()) } + // Notify all active streams. for _, s := range streams { - t.closeStream(s, ErrConnClosing, false, http2.ErrCodeNo, status.New(codes.Unavailable, ErrConnClosing.Desc), nil, false) + t.closeStream(s, err, false, http2.ErrCodeNo, st, nil, false) } - if t.statsHandler != nil { + for _, sh := range t.statsHandlers { connEnd := &stats.ConnEnd{ Client: true, } - t.statsHandler.HandleConn(t.ctx, connEnd) + sh.HandleConn(t.ctx, connEnd) } - return err } // GracefulClose sets the state to draining, which prevents new streams from @@ -891,11 +1012,15 @@ func (t *http2Client) GracefulClose() { t.mu.Unlock() return } + if t.logger.V(logLevel) { + t.logger.Infof("GracefulClose called") + } + t.onClose(GoAwayInvalid) t.state = draining active := len(t.activeStreams) t.mu.Unlock() if active == 0 { - t.Close() + t.Close(connectionErrorf(true, nil, "no active streams left to process while draining")) return } t.controlBuf.put(&incomingGoAway{}) @@ -955,13 +1080,13 @@ func (t *http2Client) updateWindow(s *Stream, n uint32) { // for the transport and the stream based on the current bdp // estimation. func (t *http2Client) updateFlowControl(n uint32) { - t.mu.Lock() - for _, s := range t.activeStreams { - s.fc.newLimit(n) - } - t.mu.Unlock() updateIWS := func(interface{}) bool { t.initialWindowSize = int32(n) + t.mu.Lock() + for _, s := range t.activeStreams { + s.fc.newLimit(n) + } + t.mu.Unlock() return true } t.controlBuf.executeAndPut(updateIWS, &outgoingWindowUpdate{streamID: 0, increment: t.fc.newLimit(n)}) @@ -1036,7 +1161,7 @@ func (t *http2Client) handleData(f *http2.DataFrame) { } // The server has closed the stream without sending trailers. Record that // the read direction is closed, and set the status appropriately. - if f.FrameHeader.Flags.Has(http2.FlagDataEndStream) { + if f.StreamEnded() { t.closeStream(s, io.EOF, false, http2.ErrCodeNo, status.New(codes.Internal, "server closed the stream without sending trailers"), nil, true) } } @@ -1052,8 +1177,8 @@ func (t *http2Client) handleRSTStream(f *http2.RSTStreamFrame) { } statusCode, ok := http2ErrConvTab[f.ErrCode] if !ok { - if logger.V(logLevel) { - logger.Warningf("transport: http2Client.handleRSTStream found no mapped gRPC status for the received http2 error %v", f.ErrCode) + if t.logger.V(logLevel) { + t.logger.Infof("Received a RST_STREAM frame with code %q, but found no mapped gRPC status", f.ErrCode) } statusCode = codes.Unknown } @@ -1135,15 +1260,17 @@ func (t *http2Client) handleGoAway(f *http2.GoAwayFrame) { t.mu.Unlock() return } - if f.ErrCode == http2.ErrCodeEnhanceYourCalm { - if logger.V(logLevel) { - logger.Infof("Client received GoAway with http2.ErrCodeEnhanceYourCalm.") - } + if f.ErrCode == http2.ErrCodeEnhanceYourCalm && string(f.DebugData()) == "too_many_pings" { + // When a client receives a GOAWAY with error code ENHANCE_YOUR_CALM and debug + // data equal to ASCII "too_many_pings", it should log the occurrence at a log level that is + // enabled by default and double the configure KEEPALIVE_TIME used for new connections + // on that channel. + logger.Errorf("Client received GoAway with error code ENHANCE_YOUR_CALM and debug data equal to ASCII \"too_many_pings\".") } id := f.LastStreamID - if id > 0 && id%2 != 1 { + if id > 0 && id%2 == 0 { t.mu.Unlock() - t.Close() + t.Close(connectionErrorf(true, nil, "received goaway with non-zero even-numbered numbered stream id: %v", id)) return } // A client can receive multiple GoAways from the server (see @@ -1161,18 +1288,20 @@ func (t *http2Client) handleGoAway(f *http2.GoAwayFrame) { // If there are multiple GoAways the first one should always have an ID greater than the following ones. if id > t.prevGoAwayID { t.mu.Unlock() - t.Close() + t.Close(connectionErrorf(true, nil, "received goaway with stream id: %v, which exceeds stream id of previous goaway: %v", id, t.prevGoAwayID)) return } default: t.setGoAwayReason(f) close(t.goAway) - t.controlBuf.put(&incomingGoAway{}) + defer t.controlBuf.put(&incomingGoAway{}) // Defer as t.mu is currently held. // Notify the clientconn about the GOAWAY before we set the state to // draining, to allow the client to stop attempting to create streams // before disallowing new streams on this connection. - t.onGoAway(t.goAwayReason) - t.state = draining + if t.state != draining { + t.onClose(t.goAwayReason) + t.state = draining + } } // All streams with IDs greater than the GoAwayId // and smaller than the previous GoAway ID should be killed. @@ -1180,24 +1309,35 @@ func (t *http2Client) handleGoAway(f *http2.GoAwayFrame) { if upperLimit == 0 { // This is the first GoAway Frame. upperLimit = math.MaxUint32 // Kill all streams after the GoAway ID. } + + t.prevGoAwayID = id + if len(t.activeStreams) == 0 { + t.mu.Unlock() + t.Close(connectionErrorf(true, nil, "received goaway and there are no active streams")) + return + } + + streamsToClose := make([]*Stream, 0) for streamID, stream := range t.activeStreams { if streamID > id && streamID <= upperLimit { // The stream was unprocessed by the server. - atomic.StoreUint32(&stream.unprocessed, 1) - t.closeStream(stream, errStreamDrain, false, http2.ErrCodeNo, statusGoAway, nil, false) + if streamID > id && streamID <= upperLimit { + atomic.StoreUint32(&stream.unprocessed, 1) + streamsToClose = append(streamsToClose, stream) + } } } - t.prevGoAwayID = id - active := len(t.activeStreams) t.mu.Unlock() - if active == 0 { - t.Close() + // Called outside t.mu because closeStream can take controlBuf's mu, which + // could induce deadlock and is not allowed. + for _, stream := range streamsToClose { + t.closeStream(stream, errStreamDrain, false, http2.ErrCodeNo, statusGoAway, nil, false) } } // setGoAwayReason sets the value of t.goAwayReason based // on the GoAway frame received. -// It expects a lock on transport's mutext to be held by +// It expects a lock on transport's mutex to be held by // the caller. func (t *http2Client) setGoAwayReason(f *http2.GoAwayFrame) { t.goAwayReason = GoAwayNoReason @@ -1207,12 +1347,17 @@ func (t *http2Client) setGoAwayReason(f *http2.GoAwayFrame) { t.goAwayReason = GoAwayTooManyPings } } + if len(f.DebugData()) == 0 { + t.goAwayDebugMessage = fmt.Sprintf("code: %s", f.ErrCode) + } else { + t.goAwayDebugMessage = fmt.Sprintf("code: %s, debug data: %q", f.ErrCode, string(f.DebugData())) + } } -func (t *http2Client) GetGoAwayReason() GoAwayReason { +func (t *http2Client) GetGoAwayReason() (GoAwayReason, string) { t.mu.Lock() defer t.mu.Unlock() - return t.goAwayReason + return t.goAwayReason, t.goAwayDebugMessage } func (t *http2Client) handleWindowUpdate(f *http2.WindowUpdateFrame) { @@ -1239,35 +1384,128 @@ func (t *http2Client) operateHeaders(frame *http2.MetaHeadersFrame) { return } - state := &decodeState{} - // Initialize isGRPC value to be !initialHeader, since if a gRPC Response-Headers has already been received, then it means that the peer is speaking gRPC and we are in gRPC mode. - state.data.isGRPC = !initialHeader - if h2code, err := state.decodeHeader(frame); err != nil { - t.closeStream(s, err, true, h2code, status.Convert(err), nil, endStream) + // frame.Truncated is set to true when framer detects that the current header + // list size hits MaxHeaderListSize limit. + if frame.Truncated { + se := status.New(codes.Internal, "peer header list size exceeded limit") + t.closeStream(s, se.Err(), true, http2.ErrCodeFrameSize, se, nil, endStream) return } - isHeader := false - defer func() { - if t.statsHandler != nil { - if isHeader { - inHeader := &stats.InHeader{ - Client: true, - WireLength: int(frame.Header().Length), - Header: s.header.Copy(), - Compression: s.recvCompress, - } - t.statsHandler.HandleRPC(s.ctx, inHeader) - } else { - inTrailer := &stats.InTrailer{ - Client: true, - WireLength: int(frame.Header().Length), - Trailer: s.trailer.Copy(), - } - t.statsHandler.HandleRPC(s.ctx, inTrailer) + var ( + // If a gRPC Response-Headers has already been received, then it means + // that the peer is speaking gRPC and we are in gRPC mode. + isGRPC = !initialHeader + mdata = make(map[string][]string) + contentTypeErr = "malformed header: missing HTTP content-type" + grpcMessage string + statusGen *status.Status + recvCompress string + httpStatusCode *int + httpStatusErr string + rawStatusCode = codes.Unknown + // headerError is set if an error is encountered while parsing the headers + headerError string + ) + + if initialHeader { + httpStatusErr = "malformed header: missing HTTP status" + } + + for _, hf := range frame.Fields { + switch hf.Name { + case "content-type": + if _, validContentType := grpcutil.ContentSubtype(hf.Value); !validContentType { + contentTypeErr = fmt.Sprintf("transport: received unexpected content-type %q", hf.Value) + break + } + contentTypeErr = "" + mdata[hf.Name] = append(mdata[hf.Name], hf.Value) + isGRPC = true + case "grpc-encoding": + recvCompress = hf.Value + case "grpc-status": + code, err := strconv.ParseInt(hf.Value, 10, 32) + if err != nil { + se := status.New(codes.Internal, fmt.Sprintf("transport: malformed grpc-status: %v", err)) + t.closeStream(s, se.Err(), true, http2.ErrCodeProtocol, se, nil, endStream) + return + } + rawStatusCode = codes.Code(uint32(code)) + case "grpc-message": + grpcMessage = decodeGrpcMessage(hf.Value) + case "grpc-status-details-bin": + var err error + statusGen, err = decodeGRPCStatusDetails(hf.Value) + if err != nil { + headerError = fmt.Sprintf("transport: malformed grpc-status-details-bin: %v", err) + } + case ":status": + if hf.Value == "200" { + httpStatusErr = "" + statusCode := 200 + httpStatusCode = &statusCode + break } + + c, err := strconv.ParseInt(hf.Value, 10, 32) + if err != nil { + se := status.New(codes.Internal, fmt.Sprintf("transport: malformed http-status: %v", err)) + t.closeStream(s, se.Err(), true, http2.ErrCodeProtocol, se, nil, endStream) + return + } + statusCode := int(c) + httpStatusCode = &statusCode + + httpStatusErr = fmt.Sprintf( + "unexpected HTTP status code received from server: %d (%s)", + statusCode, + http.StatusText(statusCode), + ) + default: + if isReservedHeader(hf.Name) && !isWhitelistedHeader(hf.Name) { + break + } + v, err := decodeMetadataHeader(hf.Name, hf.Value) + if err != nil { + headerError = fmt.Sprintf("transport: malformed %s: %v", hf.Name, err) + logger.Warningf("Failed to decode metadata header (%q, %q): %v", hf.Name, hf.Value, err) + break + } + mdata[hf.Name] = append(mdata[hf.Name], v) } - }() + } + + if !isGRPC || httpStatusErr != "" { + var code = codes.Internal // when header does not include HTTP status, return INTERNAL + + if httpStatusCode != nil { + var ok bool + code, ok = HTTPStatusConvTab[*httpStatusCode] + if !ok { + code = codes.Unknown + } + } + var errs []string + if httpStatusErr != "" { + errs = append(errs, httpStatusErr) + } + if contentTypeErr != "" { + errs = append(errs, contentTypeErr) + } + // Verify the HTTP response is a 200. + se := status.New(code, strings.Join(errs, "; ")) + t.closeStream(s, se.Err(), true, http2.ErrCodeProtocol, se, nil, endStream) + return + } + + if headerError != "" { + se := status.New(codes.Internal, headerError) + t.closeStream(s, se.Err(), true, http2.ErrCodeProtocol, se, nil, endStream) + return + } + + isHeader := false // If headerChan hasn't been closed yet if atomic.CompareAndSwapUint32(&s.headerChanClosed, 0, 1) { @@ -1278,9 +1516,9 @@ func (t *http2Client) operateHeaders(frame *http2.MetaHeadersFrame) { // These values can be set without any synchronization because // stream goroutine will read it only after seeing a closed // headerChan which we'll close after setting this. - s.recvCompress = state.data.encoding - if len(state.data.mdata) > 0 { - s.header = state.data.mdata + s.recvCompress = recvCompress + if len(mdata) > 0 { + s.header = mdata } } else { // HEADERS frame block carries a Trailers-Only. @@ -1289,40 +1527,67 @@ func (t *http2Client) operateHeaders(frame *http2.MetaHeadersFrame) { close(s.headerChan) } + for _, sh := range t.statsHandlers { + if isHeader { + inHeader := &stats.InHeader{ + Client: true, + WireLength: int(frame.Header().Length), + Header: metadata.MD(mdata).Copy(), + Compression: s.recvCompress, + } + sh.HandleRPC(s.ctx, inHeader) + } else { + inTrailer := &stats.InTrailer{ + Client: true, + WireLength: int(frame.Header().Length), + Trailer: metadata.MD(mdata).Copy(), + } + sh.HandleRPC(s.ctx, inTrailer) + } + } + if !endStream { return } + if statusGen == nil { + statusGen = status.New(rawStatusCode, grpcMessage) + } + // if client received END_STREAM from server while stream was still active, send RST_STREAM rst := s.getState() == streamActive - t.closeStream(s, io.EOF, rst, http2.ErrCodeNo, state.status(), state.data.mdata, true) + t.closeStream(s, io.EOF, rst, http2.ErrCodeNo, statusGen, mdata, true) } -// reader runs as a separate goroutine in charge of reading data from network -// connection. -// -// TODO(zhaoq): currently one reader per transport. Investigate whether this is -// optimal. -// TODO(zhaoq): Check the validity of the incoming frame sequence. -func (t *http2Client) reader() { - defer close(t.readerDone) - // Check the validity of server preface. +// readServerPreface reads and handles the initial settings frame from the +// server. +func (t *http2Client) readServerPreface() error { frame, err := t.framer.fr.ReadFrame() if err != nil { - t.Close() // this kicks off resetTransport, so must be last before return - return - } - t.conn.SetReadDeadline(time.Time{}) // reset deadline once we get the settings frame (we didn't time out, yay!) - if t.keepaliveEnabled { - atomic.StoreInt64(&t.lastRead, time.Now().UnixNano()) + return connectionErrorf(true, err, "error reading server preface: %v", err) } sf, ok := frame.(*http2.SettingsFrame) if !ok { - t.Close() // this kicks off resetTransport, so must be last before return - return + return connectionErrorf(true, nil, "initial http2 frame from server is not a settings frame: %T", frame) } - t.onPrefaceReceipt() t.handleSettings(sf, true) + return nil +} + +// reader verifies the server preface and reads all subsequent data from +// network connection. If the server preface is not read successfully, an +// error is pushed to errCh; otherwise errCh is closed with no error. +func (t *http2Client) reader(errCh chan<- error) { + defer close(t.readerDone) + + if err := t.readServerPreface(); err != nil { + errCh <- err + return + } + close(errCh) + if t.keepaliveEnabled { + atomic.StoreInt64(&t.lastRead, time.Now().UnixNano()) + } // loop to keep reading incoming messages on this transport. for { @@ -1354,7 +1619,7 @@ func (t *http2Client) reader() { continue } else { // Transport error. - t.Close() + t.Close(connectionErrorf(true, err, "error reading from server: %v", err)) return } } @@ -1388,7 +1653,7 @@ func minTime(a, b time.Duration) time.Duration { return b } -// keepalive running in a separate goroutune makes sure the connection is alive by sending pings. +// keepalive running in a separate goroutine makes sure the connection is alive by sending pings. func (t *http2Client) keepalive() { p := &ping{data: [8]byte{}} // True iff a ping has been sent, and no data has been received since then. @@ -1413,7 +1678,7 @@ func (t *http2Client) keepalive() { continue } if outstandingPing && timeoutLeft <= 0 { - t.Close() + t.Close(connectionErrorf(true, nil, "keepalive ping failed to receive ACK within timeout")) return } t.mu.Lock() @@ -1525,3 +1790,9 @@ func (t *http2Client) getOutFlowWindow() int64 { return -2 } } + +func (t *http2Client) stateForTesting() transportState { + t.mu.Lock() + defer t.mu.Unlock() + return t.state +} diff --git a/vendor/google.golang.org/grpc/internal/transport/http2_server.go b/vendor/google.golang.org/grpc/internal/transport/http2_server.go index 0cf1cc320bb..ec4eef21342 100644 --- a/vendor/google.golang.org/grpc/internal/transport/http2_server.go +++ b/vendor/google.golang.org/grpc/internal/transport/http2_server.go @@ -26,6 +26,7 @@ import ( "io" "math" "net" + "net/http" "strconv" "sync" "sync/atomic" @@ -34,12 +35,16 @@ import ( "github.com/golang/protobuf/proto" "golang.org/x/net/http2" "golang.org/x/net/http2/hpack" + "google.golang.org/grpc/internal/grpclog" "google.golang.org/grpc/internal/grpcutil" + "google.golang.org/grpc/internal/pretty" + "google.golang.org/grpc/internal/syscall" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" "google.golang.org/grpc/internal/channelz" "google.golang.org/grpc/internal/grpcrand" + "google.golang.org/grpc/internal/grpcsync" "google.golang.org/grpc/keepalive" "google.golang.org/grpc/metadata" "google.golang.org/grpc/peer" @@ -51,10 +56,10 @@ import ( var ( // ErrIllegalHeaderWrite indicates that setting header is illegal because of // the stream's state. - ErrIllegalHeaderWrite = errors.New("transport: the stream is done or WriteHeader was already called") + ErrIllegalHeaderWrite = status.Error(codes.Internal, "transport: SendHeader called multiple times") // ErrHeaderListSizeLimitViolation indicates that the header list size is larger // than the limit set by peer. - ErrHeaderListSizeLimitViolation = errors.New("transport: trying to send header list size larger than the limit set by peer") + ErrHeaderListSizeLimitViolation = status.Error(codes.Internal, "transport: trying to send header list size larger than the limit set by peer") ) // serverConnectionCounter counts the number of connections a server has seen @@ -72,7 +77,6 @@ type http2Server struct { writerDone chan struct{} // sync point to enable testing. remoteAddr net.Addr localAddr net.Addr - maxStreamID uint32 // max stream ID ever seen authInfo credentials.AuthInfo // auth info about the connection inTapHandle tap.ServerInHandle framer *framer @@ -82,7 +86,7 @@ type http2Server struct { // updates, reset streams, and various settings) to the controller. controlBuf *controlBuffer fc *trInFlow - stats stats.Handler + stats []stats.Handler // Keepalive and max-age parameters for the server. kp keepalive.ServerParameters // Keepalive enforcement policy. @@ -101,13 +105,13 @@ type http2Server struct { mu sync.Mutex // guard the following - // drainChan is initialized when drain(...) is called the first time. - // After which the server writes out the first GoAway(with ID 2^31-1) frame. - // Then an independent goroutine will be launched to later send the second GoAway. - // During this time we don't want to write another first GoAway(with ID 2^31 -1) frame. - // Thus call to drain(...) will be a no-op if drainChan is already initialized since draining is - // already underway. - drainChan chan struct{} + // drainEvent is initialized when Drain() is called the first time. After + // which the server writes out the first GoAway(with ID 2^31-1) frame. Then + // an independent goroutine will be launched to later send the second + // GoAway. During this time we don't want to write another first GoAway(with + // ID 2^31 -1) frame. Thus call to Drain() will be a no-op if drainEvent is + // already initialized since draining is already underway. + drainEvent *grpcsync.Event state transportState activeStreams map[uint32]*Stream // idle is the time instant when the connection went idle. @@ -117,16 +121,44 @@ type http2Server struct { idle time.Time // Fields below are for channelz metric collection. - channelzID int64 // channelz unique identification number + channelzID *channelz.Identifier czData *channelzData bufferPool *bufferPool connectionID uint64 + + // maxStreamMu guards the maximum stream ID + // This lock may not be taken if mu is already held. + maxStreamMu sync.Mutex + maxStreamID uint32 // max stream ID ever seen + + logger *grpclog.PrefixLogger } -// newHTTP2Server constructs a ServerTransport based on HTTP2. ConnectionError is -// returned if something goes wrong. -func newHTTP2Server(conn net.Conn, config *ServerConfig) (_ ServerTransport, err error) { +// NewServerTransport creates a http2 transport with conn and configuration +// options from config. +// +// It returns a non-nil transport and a nil error on success. On failure, it +// returns a nil transport and a non-nil error. For a special case where the +// underlying conn gets closed before the client preface could be read, it +// returns a nil transport and a nil error. +func NewServerTransport(conn net.Conn, config *ServerConfig) (_ ServerTransport, err error) { + var authInfo credentials.AuthInfo + rawConn := conn + if config.Credentials != nil { + var err error + conn, authInfo, err = config.Credentials.ServerHandshake(rawConn) + if err != nil { + // ErrConnDispatched means that the connection was dispatched away + // from gRPC; those connections should be left open. io.EOF means + // the connection was closed before handshaking completed, which can + // happen naturally from probers. Return these errors directly. + if err == credentials.ErrConnDispatched || err == io.EOF { + return nil, err + } + return nil, connectionErrorf(false, err, "ServerHandshake(%q) failed: %v", rawConn.RemoteAddr(), err) + } + } writeBufSize := config.WriteBufferSize readBufSize := config.ReadBufferSize maxHeaderListSize := defaultServerMaxHeaderListSize @@ -139,15 +171,10 @@ func newHTTP2Server(conn net.Conn, config *ServerConfig) (_ ServerTransport, err ID: http2.SettingMaxFrameSize, Val: http2MaxFrameLen, }} - // TODO(zhaoq): Have a better way to signal "no limit" because 0 is - // permitted in the HTTP2 spec. - maxStreams := config.MaxStreams - if maxStreams == 0 { - maxStreams = math.MaxUint32 - } else { + if config.MaxStreams != math.MaxUint32 { isettings = append(isettings, http2.Setting{ ID: http2.SettingMaxConcurrentStreams, - Val: maxStreams, + Val: config.MaxStreams, }) } dynamicWindow := true @@ -205,27 +232,33 @@ func newHTTP2Server(conn net.Conn, config *ServerConfig) (_ ServerTransport, err if kp.Timeout == 0 { kp.Timeout = defaultServerKeepaliveTimeout } + if kp.Time != infinity { + if err = syscall.SetTCPUserTimeout(conn, kp.Timeout); err != nil { + return nil, connectionErrorf(false, err, "transport: failed to set TCP_USER_TIMEOUT: %v", err) + } + } kep := config.KeepalivePolicy if kep.MinTime == 0 { kep.MinTime = defaultKeepalivePolicyMinTime } + done := make(chan struct{}) t := &http2Server{ - ctx: context.Background(), + ctx: setConnection(context.Background(), rawConn), done: done, conn: conn, remoteAddr: conn.RemoteAddr(), localAddr: conn.LocalAddr(), - authInfo: config.AuthInfo, + authInfo: authInfo, framer: framer, readerDone: make(chan struct{}), writerDone: make(chan struct{}), - maxStreams: maxStreams, + maxStreams: config.MaxStreams, inTapHandle: config.InTapHandle, fc: &trInFlow{limit: uint32(icwz)}, state: reachable, activeStreams: make(map[uint32]*Stream), - stats: config.StatsHandler, + stats: config.StatsHandlers, kp: kp, idle: time.Now(), kep: kep, @@ -233,6 +266,10 @@ func newHTTP2Server(conn net.Conn, config *ServerConfig) (_ ServerTransport, err czData: new(channelzData), bufferPool: newBufferPool(), } + t.logger = prefixLoggerForServerTransport(t) + // Add peer information to the http2server context. + t.ctx = peer.NewContext(t.ctx, t.getPeer()) + t.controlBuf = newControlBuffer(t.done) if dynamicWindow { t.bdpEst = &bdpEstimator{ @@ -240,31 +277,39 @@ func newHTTP2Server(conn net.Conn, config *ServerConfig) (_ ServerTransport, err updateFlowControl: t.updateFlowControl, } } - if t.stats != nil { - t.ctx = t.stats.TagConn(t.ctx, &stats.ConnTagInfo{ + for _, sh := range t.stats { + t.ctx = sh.TagConn(t.ctx, &stats.ConnTagInfo{ RemoteAddr: t.remoteAddr, LocalAddr: t.localAddr, }) connBegin := &stats.ConnBegin{} - t.stats.HandleConn(t.ctx, connBegin) + sh.HandleConn(t.ctx, connBegin) } - if channelz.IsOn() { - t.channelzID = channelz.RegisterNormalSocket(t, config.ChannelzParentID, fmt.Sprintf("%s -> %s", t.remoteAddr, t.localAddr)) + t.channelzID, err = channelz.RegisterNormalSocket(t, config.ChannelzParentID, fmt.Sprintf("%s -> %s", t.remoteAddr, t.localAddr)) + if err != nil { + return nil, err } t.connectionID = atomic.AddUint64(&serverConnectionCounter, 1) - t.framer.writer.Flush() defer func() { if err != nil { - t.Close() + t.Close(err) } }() // Check the validity of client preface. preface := make([]byte, len(clientPreface)) if _, err := io.ReadFull(t.conn, preface); err != nil { + // In deployments where a gRPC server runs behind a cloud load balancer + // which performs regular TCP level health checks, the connection is + // closed immediately by the latter. Returning io.EOF here allows the + // grpc server implementation to recognize this scenario and suppress + // logging to reduce spam. + if err == io.EOF { + return nil, io.EOF + } return nil, connectionErrorf(false, err, "transport: http2Server.HandleStreams failed to receive the preface from client: %v", err) } if !bytes.Equal(preface, clientPreface) { @@ -286,100 +331,206 @@ func newHTTP2Server(conn net.Conn, config *ServerConfig) (_ ServerTransport, err t.handleSettings(sf) go func() { - t.loopy = newLoopyWriter(serverSide, t.framer, t.controlBuf, t.bdpEst) + t.loopy = newLoopyWriter(serverSide, t.framer, t.controlBuf, t.bdpEst, t.conn, t.logger) t.loopy.ssGoAwayHandler = t.outgoingGoAwayHandler - if err := t.loopy.run(); err != nil { - if logger.V(logLevel) { - logger.Errorf("transport: loopyWriter.run returning. Err: %v", err) - } - } - t.conn.Close() + t.loopy.run() close(t.writerDone) }() go t.keepalive() return t, nil } -// operateHeader takes action on the decoded headers. -func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func(*Stream), traceCtx func(context.Context, string) context.Context) (fatal bool) { +// operateHeaders takes action on the decoded headers. Returns an error if fatal +// error encountered and transport needs to close, otherwise returns nil. +func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func(*Stream), traceCtx func(context.Context, string) context.Context) error { + // Acquire max stream ID lock for entire duration + t.maxStreamMu.Lock() + defer t.maxStreamMu.Unlock() + streamID := frame.Header().StreamID - state := &decodeState{ - serverSide: true, - } - if h2code, err := state.decodeHeader(frame); err != nil { - if _, ok := status.FromError(err); ok { - t.controlBuf.put(&cleanupStream{ - streamID: streamID, - rst: true, - rstCode: h2code, - onWrite: func() {}, - }) - } - return false + + // frame.Truncated is set to true when framer detects that the current header + // list size hits MaxHeaderListSize limit. + if frame.Truncated { + t.controlBuf.put(&cleanupStream{ + streamID: streamID, + rst: true, + rstCode: http2.ErrCodeFrameSize, + onWrite: func() {}, + }) + return nil + } + + if streamID%2 != 1 || streamID <= t.maxStreamID { + // illegal gRPC stream id. + return fmt.Errorf("received an illegal stream id: %v. headers frame: %+v", streamID, frame) } + t.maxStreamID = streamID buf := newRecvBuffer() s := &Stream{ - id: streamID, - st: t, - buf: buf, - fc: &inFlow{limit: uint32(t.initialWindowSize)}, - recvCompress: state.data.encoding, - method: state.data.method, - contentSubtype: state.data.contentSubtype, + id: streamID, + st: t, + buf: buf, + fc: &inFlow{limit: uint32(t.initialWindowSize)}, + } + var ( + // if false, content-type was missing or invalid + isGRPC = false + contentType = "" + mdata = make(metadata.MD, len(frame.Fields)) + httpMethod string + // these are set if an error is encountered while parsing the headers + protocolError bool + headerError *status.Status + + timeoutSet bool + timeout time.Duration + ) + + for _, hf := range frame.Fields { + switch hf.Name { + case "content-type": + contentSubtype, validContentType := grpcutil.ContentSubtype(hf.Value) + if !validContentType { + contentType = hf.Value + break + } + mdata[hf.Name] = append(mdata[hf.Name], hf.Value) + s.contentSubtype = contentSubtype + isGRPC = true + + case "grpc-accept-encoding": + mdata[hf.Name] = append(mdata[hf.Name], hf.Value) + if hf.Value == "" { + continue + } + compressors := hf.Value + if s.clientAdvertisedCompressors != "" { + compressors = s.clientAdvertisedCompressors + "," + compressors + } + s.clientAdvertisedCompressors = compressors + case "grpc-encoding": + s.recvCompress = hf.Value + case ":method": + httpMethod = hf.Value + case ":path": + s.method = hf.Value + case "grpc-timeout": + timeoutSet = true + var err error + if timeout, err = decodeTimeout(hf.Value); err != nil { + headerError = status.Newf(codes.Internal, "malformed grpc-timeout: %v", err) + } + // "Transports must consider requests containing the Connection header + // as malformed." - A41 + case "connection": + if t.logger.V(logLevel) { + t.logger.Infof("Received a HEADERS frame with a :connection header which makes the request malformed, as per the HTTP/2 spec") + } + protocolError = true + default: + if isReservedHeader(hf.Name) && !isWhitelistedHeader(hf.Name) { + break + } + v, err := decodeMetadataHeader(hf.Name, hf.Value) + if err != nil { + headerError = status.Newf(codes.Internal, "malformed binary metadata %q in header %q: %v", hf.Value, hf.Name, err) + t.logger.Warningf("Failed to decode metadata header (%q, %q): %v", hf.Name, hf.Value, err) + break + } + mdata[hf.Name] = append(mdata[hf.Name], v) + } + } + + // "If multiple Host headers or multiple :authority headers are present, the + // request must be rejected with an HTTP status code 400 as required by Host + // validation in RFC 7230 §5.4, gRPC status code INTERNAL, or RST_STREAM + // with HTTP/2 error code PROTOCOL_ERROR." - A41. Since this is a HTTP/2 + // error, this takes precedence over a client not speaking gRPC. + if len(mdata[":authority"]) > 1 || len(mdata["host"]) > 1 { + errMsg := fmt.Sprintf("num values of :authority: %v, num values of host: %v, both must only have 1 value as per HTTP/2 spec", len(mdata[":authority"]), len(mdata["host"])) + if t.logger.V(logLevel) { + t.logger.Infof("Aborting the stream early: %v", errMsg) + } + t.controlBuf.put(&earlyAbortStream{ + httpStatus: http.StatusBadRequest, + streamID: streamID, + contentSubtype: s.contentSubtype, + status: status.New(codes.Internal, errMsg), + rst: !frame.StreamEnded(), + }) + return nil } + + if protocolError { + t.controlBuf.put(&cleanupStream{ + streamID: streamID, + rst: true, + rstCode: http2.ErrCodeProtocol, + onWrite: func() {}, + }) + return nil + } + if !isGRPC { + t.controlBuf.put(&earlyAbortStream{ + httpStatus: http.StatusUnsupportedMediaType, + streamID: streamID, + contentSubtype: s.contentSubtype, + status: status.Newf(codes.InvalidArgument, "invalid gRPC request content-type %q", contentType), + rst: !frame.StreamEnded(), + }) + return nil + } + if headerError != nil { + t.controlBuf.put(&earlyAbortStream{ + httpStatus: http.StatusBadRequest, + streamID: streamID, + contentSubtype: s.contentSubtype, + status: headerError, + rst: !frame.StreamEnded(), + }) + return nil + } + + // "If :authority is missing, Host must be renamed to :authority." - A41 + if len(mdata[":authority"]) == 0 { + // No-op if host isn't present, no eventual :authority header is a valid + // RPC. + if host, ok := mdata["host"]; ok { + mdata[":authority"] = host + delete(mdata, "host") + } + } else { + // "If :authority is present, Host must be discarded" - A41 + delete(mdata, "host") + } + if frame.StreamEnded() { // s is just created by the caller. No lock needed. s.state = streamReadDone } - if state.data.timeoutSet { - s.ctx, s.cancel = context.WithTimeout(t.ctx, state.data.timeout) + if timeoutSet { + s.ctx, s.cancel = context.WithTimeout(t.ctx, timeout) } else { s.ctx, s.cancel = context.WithCancel(t.ctx) } - pr := &peer.Peer{ - Addr: t.remoteAddr, - } - // Attach Auth info if there is any. - if t.authInfo != nil { - pr.AuthInfo = t.authInfo - } - s.ctx = peer.NewContext(s.ctx, pr) + // Attach the received metadata to the context. - if len(state.data.mdata) > 0 { - s.ctx = metadata.NewIncomingContext(s.ctx, state.data.mdata) - } - if state.data.statsTags != nil { - s.ctx = stats.SetIncomingTags(s.ctx, state.data.statsTags) - } - if state.data.statsTrace != nil { - s.ctx = stats.SetIncomingTrace(s.ctx, state.data.statsTrace) - } - if t.inTapHandle != nil { - var err error - info := &tap.Info{ - FullMethodName: state.data.method, + if len(mdata) > 0 { + s.ctx = metadata.NewIncomingContext(s.ctx, mdata) + if statsTags := mdata["grpc-tags-bin"]; len(statsTags) > 0 { + s.ctx = stats.SetIncomingTags(s.ctx, []byte(statsTags[len(statsTags)-1])) } - s.ctx, err = t.inTapHandle(s.ctx, info) - if err != nil { - if logger.V(logLevel) { - logger.Warningf("transport: http2Server.operateHeaders got an error from InTapHandle: %v", err) - } - t.controlBuf.put(&cleanupStream{ - streamID: s.id, - rst: true, - rstCode: http2.ErrCodeRefusedStream, - onWrite: func() {}, - }) - s.cancel() - return false + if statsTrace := mdata["grpc-trace-bin"]; len(statsTrace) > 0 { + s.ctx = stats.SetIncomingTrace(s.ctx, []byte(statsTrace[len(statsTrace)-1])) } } t.mu.Lock() if t.state != reachable { t.mu.Unlock() s.cancel() - return false + return nil } if uint32(len(t.activeStreams)) >= t.maxStreams { t.mu.Unlock() @@ -390,18 +541,45 @@ func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func( onWrite: func() {}, }) s.cancel() - return false + return nil } - if streamID%2 != 1 || streamID <= t.maxStreamID { + if httpMethod != http.MethodPost { t.mu.Unlock() - // illegal gRPC stream id. - if logger.V(logLevel) { - logger.Errorf("transport: http2Server.HandleStreams received an illegal stream id: %v", streamID) + errMsg := fmt.Sprintf("Received a HEADERS frame with :method %q which should be POST", httpMethod) + if t.logger.V(logLevel) { + t.logger.Infof("Aborting the stream early: %v", errMsg) } + t.controlBuf.put(&earlyAbortStream{ + httpStatus: 405, + streamID: streamID, + contentSubtype: s.contentSubtype, + status: status.New(codes.Internal, errMsg), + rst: !frame.StreamEnded(), + }) s.cancel() - return true + return nil + } + if t.inTapHandle != nil { + var err error + if s.ctx, err = t.inTapHandle(s.ctx, &tap.Info{FullMethodName: s.method}); err != nil { + t.mu.Unlock() + if t.logger.V(logLevel) { + t.logger.Infof("Aborting the stream early due to InTapHandle failure: %v", err) + } + stat, ok := status.FromError(err) + if !ok { + stat = status.New(codes.PermissionDenied, err.Error()) + } + t.controlBuf.put(&earlyAbortStream{ + httpStatus: 200, + streamID: s.id, + contentSubtype: s.contentSubtype, + status: stat, + rst: !frame.StreamEnded(), + }) + return nil + } } - t.maxStreamID = streamID t.activeStreams[streamID] = s if len(t.activeStreams) == 1 { t.idle = time.Time{} @@ -415,17 +593,17 @@ func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func( t.adjustWindow(s, uint32(n)) } s.ctx = traceCtx(s.ctx, s.method) - if t.stats != nil { - s.ctx = t.stats.TagRPC(s.ctx, &stats.RPCTagInfo{FullMethodName: s.method}) + for _, sh := range t.stats { + s.ctx = sh.TagRPC(s.ctx, &stats.RPCTagInfo{FullMethodName: s.method}) inHeader := &stats.InHeader{ FullMethod: s.method, RemoteAddr: t.remoteAddr, LocalAddr: t.localAddr, Compression: s.recvCompress, WireLength: int(frame.Header().Length), - Header: metadata.MD(state.data.mdata).Copy(), + Header: mdata.Copy(), } - t.stats.HandleRPC(s.ctx, inHeader) + sh.HandleRPC(s.ctx, inHeader) } s.ctxDone = s.ctx.Done() s.wq = newWriteQuota(defaultWriteQuota, s.ctxDone) @@ -446,7 +624,7 @@ func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func( wq: s.wq, }) handle(s) - return false + return nil } // HandleStreams receives incoming streams using the given handler. This is @@ -460,8 +638,8 @@ func (t *http2Server) HandleStreams(handle func(*Stream), traceCtx func(context. atomic.StoreInt64(&t.lastRead, time.Now().UnixNano()) if err != nil { if se, ok := err.(http2.StreamError); ok { - if logger.V(logLevel) { - logger.Warningf("transport: http2Server.HandleStreams encountered http2.StreamError: %v", se) + if t.logger.V(logLevel) { + t.logger.Warningf("Encountered http2.StreamError: %v", se) } t.mu.Lock() s := t.activeStreams[se.StreamID] @@ -479,19 +657,16 @@ func (t *http2Server) HandleStreams(handle func(*Stream), traceCtx func(context. continue } if err == io.EOF || err == io.ErrUnexpectedEOF { - t.Close() + t.Close(err) return } - if logger.V(logLevel) { - logger.Warningf("transport: http2Server.HandleStreams failed to read frame: %v", err) - } - t.Close() + t.Close(err) return } switch frame := frame.(type) { case *http2.MetaHeadersFrame: - if t.operateHeaders(frame, handle, traceCtx) { - t.Close() + if err := t.operateHeaders(frame, handle, traceCtx); err != nil { + t.Close(err) break } case *http2.DataFrame: @@ -507,8 +682,8 @@ func (t *http2Server) HandleStreams(handle func(*Stream), traceCtx func(context. case *http2.GoAwayFrame: // TODO: Handle GoAway from the client appropriately. default: - if logger.V(logLevel) { - logger.Errorf("transport: http2Server.HandleStreams found unhandled frame type %v.", frame) + if t.logger.V(logLevel) { + t.logger.Infof("Received unsupported frame type %T", frame) } } } @@ -635,7 +810,7 @@ func (t *http2Server) handleData(f *http2.DataFrame) { s.write(recvMsg{buffer: buffer}) } } - if f.Header().Flags.Has(http2.FlagDataEndStream) { + if f.StreamEnded() { // Received the end of stream from the client. s.compareAndSwapState(streamActive, streamReadDone) s.write(recvMsg{err: io.EOF}) @@ -692,8 +867,8 @@ const ( func (t *http2Server) handlePing(f *http2.PingFrame) { if f.IsAck() { - if f.Data == goAwayPing.data && t.drainChan != nil { - close(t.drainChan) + if f.Data == goAwayPing.data && t.drainEvent != nil { + t.drainEvent.Fire() return } // Maybe it's a BDP ping. @@ -735,10 +910,7 @@ func (t *http2Server) handlePing(f *http2.PingFrame) { if t.pingStrikes > maxPingStrikes { // Send goaway and close the connection. - if logger.V(logLevel) { - logger.Errorf("transport: Got too many pings from the client, closing the connection.") - } - t.controlBuf.put(&goAway{code: http2.ErrCodeEnhanceYourCalm, debugData: []byte("too_many_pings"), closeConn: true}) + t.controlBuf.put(&goAway{code: http2.ErrCodeEnhanceYourCalm, debugData: []byte("too_many_pings"), closeConn: errors.New("got too many pings from the client")}) } } @@ -770,8 +942,8 @@ func (t *http2Server) checkForHeaderListSize(it interface{}) bool { var sz int64 for _, f := range hdrFrame.hf { if sz += int64(f.Size()); sz > int64(*t.maxSendHeaderListSize) { - if logger.V(logLevel) { - logger.Errorf("header list size to send violates the maximum size (%d bytes) set by client", *t.maxSendHeaderListSize) + if t.logger.V(logLevel) { + t.logger.Infof("Header list size to send violates the maximum size (%d bytes) set by client", *t.maxSendHeaderListSize) } return false } @@ -779,12 +951,27 @@ func (t *http2Server) checkForHeaderListSize(it interface{}) bool { return true } +func (t *http2Server) streamContextErr(s *Stream) error { + select { + case <-t.done: + return ErrConnClosing + default: + } + return ContextErr(s.ctx.Err()) +} + // WriteHeader sends the header metadata md back to the client. func (t *http2Server) WriteHeader(s *Stream, md metadata.MD) error { - if s.updateHeaderSent() || s.getState() == streamDone { + s.hdrMu.Lock() + defer s.hdrMu.Unlock() + if s.getState() == streamDone { + return t.streamContextErr(s) + } + + if s.updateHeaderSent() { return ErrIllegalHeaderWrite } - s.hdrMu.Lock() + if md.Len() > 0 { if s.header.Len() > 0 { s.header = metadata.Join(s.header, md) @@ -793,10 +980,8 @@ func (t *http2Server) WriteHeader(s *Stream, md metadata.MD) error { } } if err := t.writeHeaderLocked(s); err != nil { - s.hdrMu.Unlock() - return err + return status.Convert(err).Err() } - s.hdrMu.Unlock() return nil } @@ -827,14 +1012,14 @@ func (t *http2Server) writeHeaderLocked(s *Stream) error { t.closeStream(s, true, http2.ErrCodeInternal, false) return ErrHeaderListSizeLimitViolation } - if t.stats != nil { + for _, sh := range t.stats { // Note: Headers are compressed with hpack after this call returns. // No WireLength field is set here. outHeader := &stats.OutHeader{ Header: s.header.Copy(), Compression: s.sendCompress, } - t.stats.HandleRPC(s.Context(), outHeader) + sh.HandleRPC(s.Context(), outHeader) } return nil } @@ -844,17 +1029,19 @@ func (t *http2Server) writeHeaderLocked(s *Stream) error { // TODO(zhaoq): Now it indicates the end of entire stream. Revisit if early // OK is adopted. func (t *http2Server) WriteStatus(s *Stream, st *status.Status) error { + s.hdrMu.Lock() + defer s.hdrMu.Unlock() + if s.getState() == streamDone { return nil } - s.hdrMu.Lock() + // TODO(mmukhi): Benchmark if the performance gets better if count the metadata and other header fields // first and create a slice of that exact size. headerFields := make([]hpack.HeaderField, 0, 2) // grpc-status and grpc-message will be there if none else. if !s.updateHeaderSent() { // No headers have been sent. if len(s.header) > 0 { // Send a separate header frame. if err := t.writeHeaderLocked(s); err != nil { - s.hdrMu.Unlock() return err } } else { // Send a trailer only response. @@ -869,7 +1056,7 @@ func (t *http2Server) WriteStatus(s *Stream, st *status.Status) error { stBytes, err := proto.Marshal(p) if err != nil { // TODO: return error instead, when callers are able to handle it. - logger.Errorf("transport: failed to marshal rpc status: %v, error: %v", p, err) + t.logger.Errorf("Failed to marshal rpc status: %s, error: %v", pretty.ToJSON(p), err) } else { headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-status-details-bin", Value: encodeBinHeader(stBytes)}) } @@ -883,7 +1070,7 @@ func (t *http2Server) WriteStatus(s *Stream, st *status.Status) error { endStream: true, onWrite: t.setResetPingStrikes, } - s.hdrMu.Unlock() + success, err := t.controlBuf.execute(t.checkForHeaderListSize, trailingHeader) if !success { if err != nil { @@ -895,10 +1082,10 @@ func (t *http2Server) WriteStatus(s *Stream, st *status.Status) error { // Send a RST_STREAM after the trailers if the client has not already half-closed. rst := s.getState() == streamActive t.finishStream(s, rst, http2.ErrCodeNo, trailingHeader, true) - if t.stats != nil { + for _, sh := range t.stats { // Note: The trailer fields are compressed with hpack after this call returns. // No WireLength field is set here. - t.stats.HandleRPC(s.Context(), &stats.OutTrailer{ + sh.HandleRPC(s.Context(), &stats.OutTrailer{ Trailer: s.trailer.Copy(), }) } @@ -910,23 +1097,12 @@ func (t *http2Server) WriteStatus(s *Stream, st *status.Status) error { func (t *http2Server) Write(s *Stream, hdr []byte, data []byte, opts *Options) error { if !s.isHeaderSent() { // Headers haven't been written yet. if err := t.WriteHeader(s, nil); err != nil { - if _, ok := err.(ConnectionError); ok { - return err - } - // TODO(mmukhi, dfawley): Make sure this is the right code to return. - return status.Errorf(codes.Internal, "transport: %v", err) + return err } } else { // Writing headers checks for this condition. if s.getState() == streamDone { - // TODO(mmukhi, dfawley): Should the server write also return io.EOF? - s.cancel() - select { - case <-t.done: - return ErrConnClosing - default: - } - return ContextErr(s.ctx.Err()) + return t.streamContextErr(s) } } df := &dataFrame{ @@ -936,12 +1112,7 @@ func (t *http2Server) Write(s *Stream, hdr []byte, data []byte, opts *Options) e onEachWrite: t.setResetPingStrikes, } if err := s.wq.get(int32(len(hdr) + len(data))); err != nil { - select { - case <-t.done: - return ErrConnClosing - default: - } - return ContextErr(s.ctx.Err()) + return t.streamContextErr(s) } return t.controlBuf.put(df) } @@ -990,20 +1161,20 @@ func (t *http2Server) keepalive() { if val <= 0 { // The connection has been idle for a duration of keepalive.MaxConnectionIdle or more. // Gracefully close the connection. - t.drain(http2.ErrCodeNo, []byte{}) + t.Drain("max_idle") return } idleTimer.Reset(val) case <-ageTimer.C: - t.drain(http2.ErrCodeNo, []byte{}) + t.Drain("max_age") ageTimer.Reset(t.kp.MaxConnectionAgeGrace) select { case <-ageTimer.C: // Close the connection after grace period. - if logger.V(logLevel) { - logger.Infof("transport: closing server transport due to maximum connection age.") + if t.logger.V(logLevel) { + t.logger.Infof("Closing server transport due to maximum connection age") } - t.Close() + t.controlBuf.put(closeConnection{}) case <-t.done: } return @@ -1019,10 +1190,7 @@ func (t *http2Server) keepalive() { continue } if outstandingPing && kpTimeoutLeft <= 0 { - if logger.V(logLevel) { - logger.Infof("transport: closing server transport due to idleness.") - } - t.Close() + t.Close(fmt.Errorf("keepalive ping not acked within timeout %s", t.kp.Time)) return } if !outstandingPing { @@ -1049,11 +1217,14 @@ func (t *http2Server) keepalive() { // Close starts shutting down the http2Server transport. // TODO(zhaoq): Now the destruction is not blocked on any pending streams. This // could cause some resource issue. Revisit this later. -func (t *http2Server) Close() error { +func (t *http2Server) Close(err error) { t.mu.Lock() if t.state == closing { t.mu.Unlock() - return errors.New("transport: Close() was already called") + return + } + if t.logger.V(logLevel) { + t.logger.Infof("Closing: %v", err) } t.state = closing streams := t.activeStreams @@ -1061,27 +1232,22 @@ func (t *http2Server) Close() error { t.mu.Unlock() t.controlBuf.finish() close(t.done) - err := t.conn.Close() - if channelz.IsOn() { - channelz.RemoveEntry(t.channelzID) + if err := t.conn.Close(); err != nil && t.logger.V(logLevel) { + t.logger.Infof("Error closing underlying net.Conn during Close: %v", err) } + channelz.RemoveEntry(t.channelzID) // Cancel all active streams. for _, s := range streams { s.cancel() } - if t.stats != nil { + for _, sh := range t.stats { connEnd := &stats.ConnEnd{} - t.stats.HandleConn(t.ctx, connEnd) + sh.HandleConn(t.ctx, connEnd) } - return err } // deleteStream deletes the stream s from transport's active streams. func (t *http2Server) deleteStream(s *Stream, eosReceived bool) { - // In case stream sending and receiving are invoked in separate - // goroutines (e.g., bi-directional streaming), cancel needs to be - // called to interrupt the potential blocking on other goroutines. - s.cancel() t.mu.Lock() if _, ok := t.activeStreams[s.id]; ok { @@ -1103,6 +1269,11 @@ func (t *http2Server) deleteStream(s *Stream, eosReceived bool) { // finishStream closes the stream and puts the trailing headerFrame into controlbuf. func (t *http2Server) finishStream(s *Stream, rst bool, rstCode http2.ErrCode, hdr *headerFrame, eosReceived bool) { + // In case stream sending and receiving are invoked in separate + // goroutines (e.g., bi-directional streaming), cancel needs to be + // called to interrupt the potential blocking on other goroutines. + s.cancel() + oldState := s.swapState(streamDone) if oldState == streamDone { // If the stream was already done, return. @@ -1122,6 +1293,11 @@ func (t *http2Server) finishStream(s *Stream, rst bool, rstCode http2.ErrCode, h // closeStream clears the footprint of a stream when the stream is not needed any more. func (t *http2Server) closeStream(s *Stream, rst bool, rstCode http2.ErrCode, eosReceived bool) { + // In case stream sending and receiving are invoked in separate + // goroutines (e.g., bi-directional streaming), cancel needs to be + // called to interrupt the potential blocking on other goroutines. + s.cancel() + s.swapState(streamDone) t.deleteStream(s, eosReceived) @@ -1137,18 +1313,14 @@ func (t *http2Server) RemoteAddr() net.Addr { return t.remoteAddr } -func (t *http2Server) Drain() { - t.drain(http2.ErrCodeNo, []byte{}) -} - -func (t *http2Server) drain(code http2.ErrCode, debugData []byte) { +func (t *http2Server) Drain(debugData string) { t.mu.Lock() defer t.mu.Unlock() - if t.drainChan != nil { + if t.drainEvent != nil { return } - t.drainChan = make(chan struct{}) - t.controlBuf.put(&goAway{code: code, debugData: debugData, headsUp: true}) + t.drainEvent = grpcsync.NewEvent() + t.controlBuf.put(&goAway{code: http2.ErrCodeNo, debugData: []byte(debugData), headsUp: true}) } var goAwayPing = &ping{data: [8]byte{1, 6, 1, 8, 0, 3, 3, 9}} @@ -1156,39 +1328,41 @@ var goAwayPing = &ping{data: [8]byte{1, 6, 1, 8, 0, 3, 3, 9}} // Handles outgoing GoAway and returns true if loopy needs to put itself // in draining mode. func (t *http2Server) outgoingGoAwayHandler(g *goAway) (bool, error) { + t.maxStreamMu.Lock() t.mu.Lock() if t.state == closing { // TODO(mmukhi): This seems unnecessary. t.mu.Unlock() + t.maxStreamMu.Unlock() // The transport is closing. return false, ErrConnClosing } - sid := t.maxStreamID if !g.headsUp { // Stop accepting more streams now. t.state = draining + sid := t.maxStreamID + retErr := g.closeConn if len(t.activeStreams) == 0 { - g.closeConn = true + retErr = errors.New("second GOAWAY written and no active streams left to process") } t.mu.Unlock() + t.maxStreamMu.Unlock() if err := t.framer.fr.WriteGoAway(sid, g.code, g.debugData); err != nil { return false, err } - if g.closeConn { - // Abruptly close the connection following the GoAway (via - // loopywriter). But flush out what's inside the buffer first. - t.framer.writer.Flush() - return false, fmt.Errorf("transport: Connection closing") + if retErr != nil { + return false, retErr } return true, nil } t.mu.Unlock() + t.maxStreamMu.Unlock() // For a graceful close, send out a GoAway with stream ID of MaxUInt32, // Follow that with a ping and wait for the ack to come back or a timer // to expire. During this time accept new streams since they might have // originated before the GoAway reaches the client. // After getting the ack or timer expiration send out another GoAway this // time with an ID of the max stream server intends to process. - if err := t.framer.fr.WriteGoAway(math.MaxUint32, http2.ErrCodeNo, []byte{}); err != nil { + if err := t.framer.fr.WriteGoAway(math.MaxUint32, http2.ErrCodeNo, g.debugData); err != nil { return false, err } if err := t.framer.fr.WritePing(false, goAwayPing.data); err != nil { @@ -1198,7 +1372,7 @@ func (t *http2Server) outgoingGoAwayHandler(g *goAway) (bool, error) { timer := time.NewTimer(time.Minute) defer timer.Stop() select { - case <-t.drainChan: + case <-t.drainEvent.Done(): case <-timer.C: case <-t.done: return @@ -1257,6 +1431,13 @@ func (t *http2Server) getOutFlowWindow() int64 { } } +func (t *http2Server) getPeer() *peer.Peer { + return &peer.Peer{ + Addr: t.remoteAddr, + AuthInfo: t.authInfo, // Can be nil + } +} + func getJitter(v time.Duration) time.Duration { if v == infinity { return 0 @@ -1266,3 +1447,18 @@ func getJitter(v time.Duration) time.Duration { j := grpcrand.Int63n(2*r) - r return time.Duration(j) } + +type connectionKey struct{} + +// GetConnection gets the connection from the context. +func GetConnection(ctx context.Context) net.Conn { + conn, _ := ctx.Value(connectionKey{}).(net.Conn) + return conn +} + +// SetConnection adds the connection to the context to be able to get +// information about the destination ip and port for an incoming RPC. This also +// allows any unary or streaming interceptors to see the connection. +func setConnection(ctx context.Context, conn net.Conn) context.Context { + return context.WithValue(ctx, connectionKey{}, conn) +} diff --git a/vendor/google.golang.org/grpc/internal/transport/http_util.go b/vendor/google.golang.org/grpc/internal/transport/http_util.go index 7e41d1183f9..19cbb18f5ab 100644 --- a/vendor/google.golang.org/grpc/internal/transport/http_util.go +++ b/vendor/google.golang.org/grpc/internal/transport/http_util.go @@ -20,8 +20,8 @@ package transport import ( "bufio" - "bytes" "encoding/base64" + "errors" "fmt" "io" "math" @@ -38,22 +38,14 @@ import ( "golang.org/x/net/http2/hpack" spb "google.golang.org/genproto/googleapis/rpc/status" "google.golang.org/grpc/codes" - "google.golang.org/grpc/grpclog" - "google.golang.org/grpc/internal/grpcutil" "google.golang.org/grpc/status" ) const ( // http2MaxFrameLen specifies the max length of a HTTP2 frame. http2MaxFrameLen = 16384 // 16KB frame - // http://http2.github.io/http2-spec/#SettingValues + // https://httpwg.org/specs/rfc7540.html#SettingValues http2InitHeaderTableSize = 4096 - // baseContentType is the base content-type for gRPC. This is a valid - // content-type on it's own, but can also include a content-subtype such as - // "proto" as a suffix after "+" or ";". See - // https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#requests - // for more details. - ) var ( @@ -93,55 +85,8 @@ var ( // 504 Gateway timeout - UNAVAILABLE. http.StatusGatewayTimeout: codes.Unavailable, } - logger = grpclog.Component("transport") ) -type parsedHeaderData struct { - encoding string - // statusGen caches the stream status received from the trailer the server - // sent. Client side only. Do not access directly. After all trailers are - // parsed, use the status method to retrieve the status. - statusGen *status.Status - // rawStatusCode and rawStatusMsg are set from the raw trailer fields and are not - // intended for direct access outside of parsing. - rawStatusCode *int - rawStatusMsg string - httpStatus *int - // Server side only fields. - timeoutSet bool - timeout time.Duration - method string - // key-value metadata map from the peer. - mdata map[string][]string - statsTags []byte - statsTrace []byte - contentSubtype string - - // isGRPC field indicates whether the peer is speaking gRPC (otherwise HTTP). - // - // We are in gRPC mode (peer speaking gRPC) if: - // * We are client side and have already received a HEADER frame that indicates gRPC peer. - // * The header contains valid a content-type, i.e. a string starts with "application/grpc" - // And we should handle error specific to gRPC. - // - // Otherwise (i.e. a content-type string starts without "application/grpc", or does not exist), we - // are in HTTP fallback mode, and should handle error specific to HTTP. - isGRPC bool - grpcErr error - httpErr error - contentTypeErr string -} - -// decodeState configures decoding criteria and records the decoded data. -type decodeState struct { - // whether decoding on server side or not - serverSide bool - - // Records the states during HPACK decoding. It will be filled with info parsed from HTTP HEADERS - // frame once decodeHeader function has been invoked and returned. - data parsedHeaderData -} - // isReservedHeader checks whether hdr belongs to HTTP2 headers // reserved by gRPC protocol. Any other headers are classified as the // user-specified metadata. @@ -179,14 +124,6 @@ func isWhitelistedHeader(hdr string) bool { } } -func (d *decodeState) status() *status.Status { - if d.data.statusGen == nil { - // No status-details were provided; generate status using code/msg. - d.data.statusGen = status.New(codes.Code(int32(*(d.data.rawStatusCode))), d.data.rawStatusMsg) - } - return d.data.statusGen -} - const binHdrSuffix = "-bin" func encodeBinHeader(v []byte) string { @@ -216,166 +153,16 @@ func decodeMetadataHeader(k, v string) (string, error) { return v, nil } -func (d *decodeState) decodeHeader(frame *http2.MetaHeadersFrame) (http2.ErrCode, error) { - // frame.Truncated is set to true when framer detects that the current header - // list size hits MaxHeaderListSize limit. - if frame.Truncated { - return http2.ErrCodeFrameSize, status.Error(codes.Internal, "peer header list size exceeded limit") - } - - for _, hf := range frame.Fields { - d.processHeaderField(hf) - } - - if d.data.isGRPC { - if d.data.grpcErr != nil { - return http2.ErrCodeProtocol, d.data.grpcErr - } - if d.serverSide { - return http2.ErrCodeNo, nil - } - if d.data.rawStatusCode == nil && d.data.statusGen == nil { - // gRPC status doesn't exist. - // Set rawStatusCode to be unknown and return nil error. - // So that, if the stream has ended this Unknown status - // will be propagated to the user. - // Otherwise, it will be ignored. In which case, status from - // a later trailer, that has StreamEnded flag set, is propagated. - code := int(codes.Unknown) - d.data.rawStatusCode = &code - } - return http2.ErrCodeNo, nil - } - - // HTTP fallback mode - if d.data.httpErr != nil { - return http2.ErrCodeProtocol, d.data.httpErr - } - - var ( - code = codes.Internal // when header does not include HTTP status, return INTERNAL - ok bool - ) - - if d.data.httpStatus != nil { - code, ok = HTTPStatusConvTab[*(d.data.httpStatus)] - if !ok { - code = codes.Unknown - } - } - - return http2.ErrCodeProtocol, status.Error(code, d.constructHTTPErrMsg()) -} - -// constructErrMsg constructs error message to be returned in HTTP fallback mode. -// Format: HTTP status code and its corresponding message + content-type error message. -func (d *decodeState) constructHTTPErrMsg() string { - var errMsgs []string - - if d.data.httpStatus == nil { - errMsgs = append(errMsgs, "malformed header: missing HTTP status") - } else { - errMsgs = append(errMsgs, fmt.Sprintf("%s: HTTP status code %d", http.StatusText(*(d.data.httpStatus)), *d.data.httpStatus)) - } - - if d.data.contentTypeErr == "" { - errMsgs = append(errMsgs, "transport: missing content-type field") - } else { - errMsgs = append(errMsgs, d.data.contentTypeErr) - } - - return strings.Join(errMsgs, "; ") -} - -func (d *decodeState) addMetadata(k, v string) { - if d.data.mdata == nil { - d.data.mdata = make(map[string][]string) +func decodeGRPCStatusDetails(rawDetails string) (*status.Status, error) { + v, err := decodeBinHeader(rawDetails) + if err != nil { + return nil, err } - d.data.mdata[k] = append(d.data.mdata[k], v) -} - -func (d *decodeState) processHeaderField(f hpack.HeaderField) { - switch f.Name { - case "content-type": - contentSubtype, validContentType := grpcutil.ContentSubtype(f.Value) - if !validContentType { - d.data.contentTypeErr = fmt.Sprintf("transport: received the unexpected content-type %q", f.Value) - return - } - d.data.contentSubtype = contentSubtype - // TODO: do we want to propagate the whole content-type in the metadata, - // or come up with a way to just propagate the content-subtype if it was set? - // ie {"content-type": "application/grpc+proto"} or {"content-subtype": "proto"} - // in the metadata? - d.addMetadata(f.Name, f.Value) - d.data.isGRPC = true - case "grpc-encoding": - d.data.encoding = f.Value - case "grpc-status": - code, err := strconv.Atoi(f.Value) - if err != nil { - d.data.grpcErr = status.Errorf(codes.Internal, "transport: malformed grpc-status: %v", err) - return - } - d.data.rawStatusCode = &code - case "grpc-message": - d.data.rawStatusMsg = decodeGrpcMessage(f.Value) - case "grpc-status-details-bin": - v, err := decodeBinHeader(f.Value) - if err != nil { - d.data.grpcErr = status.Errorf(codes.Internal, "transport: malformed grpc-status-details-bin: %v", err) - return - } - s := &spb.Status{} - if err := proto.Unmarshal(v, s); err != nil { - d.data.grpcErr = status.Errorf(codes.Internal, "transport: malformed grpc-status-details-bin: %v", err) - return - } - d.data.statusGen = status.FromProto(s) - case "grpc-timeout": - d.data.timeoutSet = true - var err error - if d.data.timeout, err = decodeTimeout(f.Value); err != nil { - d.data.grpcErr = status.Errorf(codes.Internal, "transport: malformed time-out: %v", err) - } - case ":path": - d.data.method = f.Value - case ":status": - code, err := strconv.Atoi(f.Value) - if err != nil { - d.data.httpErr = status.Errorf(codes.Internal, "transport: malformed http-status: %v", err) - return - } - d.data.httpStatus = &code - case "grpc-tags-bin": - v, err := decodeBinHeader(f.Value) - if err != nil { - d.data.grpcErr = status.Errorf(codes.Internal, "transport: malformed grpc-tags-bin: %v", err) - return - } - d.data.statsTags = v - d.addMetadata(f.Name, string(v)) - case "grpc-trace-bin": - v, err := decodeBinHeader(f.Value) - if err != nil { - d.data.grpcErr = status.Errorf(codes.Internal, "transport: malformed grpc-trace-bin: %v", err) - return - } - d.data.statsTrace = v - d.addMetadata(f.Name, string(v)) - default: - if isReservedHeader(f.Name) && !isWhitelistedHeader(f.Name) { - break - } - v, err := decodeMetadataHeader(f.Name, f.Value) - if err != nil { - if logger.V(logLevel) { - logger.Errorf("Failed to decode metadata header (%q, %q): %v", f.Name, f.Value, err) - } - return - } - d.addMetadata(f.Name, v) + st := &spb.Status{} + if err = proto.Unmarshal(v, st); err != nil { + return nil, err } + return status.FromProto(st), nil } type timeoutUnit uint8 @@ -462,13 +249,13 @@ func encodeGrpcMessage(msg string) string { } func encodeGrpcMessageUnchecked(msg string) string { - var buf bytes.Buffer + var sb strings.Builder for len(msg) > 0 { r, size := utf8.DecodeRuneInString(msg) for _, b := range []byte(string(r)) { if size > 1 { // If size > 1, r is not ascii. Always do percent encoding. - buf.WriteString(fmt.Sprintf("%%%02X", b)) + fmt.Fprintf(&sb, "%%%02X", b) continue } @@ -477,14 +264,14 @@ func encodeGrpcMessageUnchecked(msg string) string { // // fmt.Sprintf("%%%02X", utf8.RuneError) gives "%FFFD". if b >= spaceByte && b <= tildeByte && b != percentByte { - buf.WriteByte(b) + sb.WriteByte(b) } else { - buf.WriteString(fmt.Sprintf("%%%02X", b)) + fmt.Fprintf(&sb, "%%%02X", b) } } msg = msg[size:] } - return buf.String() + return sb.String() } // decodeGrpcMessage decodes the msg encoded by encodeGrpcMessage. @@ -502,23 +289,23 @@ func decodeGrpcMessage(msg string) string { } func decodeGrpcMessageUnchecked(msg string) string { - var buf bytes.Buffer + var sb strings.Builder lenMsg := len(msg) for i := 0; i < lenMsg; i++ { c := msg[i] if c == percentByte && i+2 < lenMsg { parsed, err := strconv.ParseUint(msg[i+1:i+3], 16, 8) if err != nil { - buf.WriteByte(c) + sb.WriteByte(c) } else { - buf.WriteByte(byte(parsed)) + sb.WriteByte(byte(parsed)) i += 2 } } else { - buf.WriteByte(c) + sb.WriteByte(c) } } - return buf.String() + return sb.String() } type bufWriter struct { @@ -527,8 +314,6 @@ type bufWriter struct { batchSize int conn net.Conn err error - - onFlush func() } func newBufWriter(conn net.Conn, batchSize int) *bufWriter { @@ -544,7 +329,8 @@ func (w *bufWriter) Write(b []byte) (n int, err error) { return 0, w.err } if w.batchSize == 0 { // Buffer has been disabled. - return w.conn.Write(b) + n, err = w.conn.Write(b) + return n, toIOError(err) } for len(b) > 0 { nn := copy(w.buf[w.offset:], b) @@ -565,14 +351,31 @@ func (w *bufWriter) Flush() error { if w.offset == 0 { return nil } - if w.onFlush != nil { - w.onFlush() - } _, w.err = w.conn.Write(w.buf[:w.offset]) + w.err = toIOError(w.err) w.offset = 0 return w.err } +type ioError struct { + error +} + +func (i ioError) Unwrap() error { + return i.error +} + +func isIOError(err error) bool { + return errors.As(err, &ioError{}) +} + +func toIOError(err error) error { + if err == nil { + return nil + } + return ioError{error: err} +} + type framer struct { writer *bufWriter fr *http2.Framer diff --git a/vendor/google.golang.org/grpc/internal/transport/logging.go b/vendor/google.golang.org/grpc/internal/transport/logging.go new file mode 100644 index 00000000000..42ed2b07af6 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/transport/logging.go @@ -0,0 +1,40 @@ +/* + * + * Copyright 2023 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package transport + +import ( + "fmt" + + "google.golang.org/grpc/grpclog" + internalgrpclog "google.golang.org/grpc/internal/grpclog" +) + +var logger = grpclog.Component("transport") + +func prefixLoggerForServerTransport(p *http2Server) *internalgrpclog.PrefixLogger { + return internalgrpclog.NewPrefixLogger(logger, fmt.Sprintf("[server-transport %p] ", p)) +} + +func prefixLoggerForServerHandlerTransport(p *serverHandlerTransport) *internalgrpclog.PrefixLogger { + return internalgrpclog.NewPrefixLogger(logger, fmt.Sprintf("[server-handler-transport %p] ", p)) +} + +func prefixLoggerForClientTransport(p *http2Client) *internalgrpclog.PrefixLogger { + return internalgrpclog.NewPrefixLogger(logger, fmt.Sprintf("[client-transport %p] ", p)) +} diff --git a/vendor/google.golang.org/grpc/internal/transport/networktype/networktype.go b/vendor/google.golang.org/grpc/internal/transport/networktype/networktype.go index 96967428b51..c11b5278274 100644 --- a/vendor/google.golang.org/grpc/internal/transport/networktype/networktype.go +++ b/vendor/google.golang.org/grpc/internal/transport/networktype/networktype.go @@ -17,7 +17,7 @@ */ // Package networktype declares the network type to be used in the default -// dailer. Attribute of a resolver.Address. +// dialer. Attribute of a resolver.Address. package networktype import ( @@ -31,7 +31,7 @@ const key = keyType("grpc.internal.transport.networktype") // Set returns a copy of the provided address with attributes containing networkType. func Set(address resolver.Address, networkType string) resolver.Address { - address.Attributes = address.Attributes.WithValues(key, networkType) + address.Attributes = address.Attributes.WithValue(key, networkType) return address } diff --git a/vendor/google.golang.org/grpc/internal/transport/proxy.go b/vendor/google.golang.org/grpc/internal/transport/proxy.go index a662bf39a6c..41596198787 100644 --- a/vendor/google.golang.org/grpc/internal/transport/proxy.go +++ b/vendor/google.golang.org/grpc/internal/transport/proxy.go @@ -37,7 +37,7 @@ var ( httpProxyFromEnvironment = http.ProxyFromEnvironment ) -func mapAddress(ctx context.Context, address string) (*url.URL, error) { +func mapAddress(address string) (*url.URL, error) { req := &http.Request{ URL: &url.URL{ Scheme: "https", @@ -114,7 +114,7 @@ func doHTTPConnectHandshake(ctx context.Context, conn net.Conn, backendAddr stri // connection. func proxyDial(ctx context.Context, addr string, grpcUA string) (conn net.Conn, err error) { newAddr := addr - proxyURL, err := mapAddress(ctx, addr) + proxyURL, err := mapAddress(addr) if err != nil { return nil, err } diff --git a/vendor/google.golang.org/grpc/internal/transport/transport.go b/vendor/google.golang.org/grpc/internal/transport/transport.go index 9c8f79cb4b2..aa1c896595d 100644 --- a/vendor/google.golang.org/grpc/internal/transport/transport.go +++ b/vendor/google.golang.org/grpc/internal/transport/transport.go @@ -30,9 +30,11 @@ import ( "net" "sync" "sync/atomic" + "time" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" + "google.golang.org/grpc/internal/channelz" "google.golang.org/grpc/keepalive" "google.golang.org/grpc/metadata" "google.golang.org/grpc/resolver" @@ -41,6 +43,10 @@ import ( "google.golang.org/grpc/tap" ) +// ErrNoHeaders is used as a signal that a trailers only response was received, +// and is not a real error. +var ErrNoHeaders = errors.New("stream has no headers") + const logLevel = 2 type bufferPool struct { @@ -241,6 +247,7 @@ type Stream struct { ctx context.Context // the associated context of the stream cancel context.CancelFunc // always nil for client side Stream done chan struct{} // closed at the end of stream to unblock writers. On the client side. + doneFunc func() // invoked at the end of stream on client side. ctxDone <-chan struct{} // same as done chan but for server side. Cache of ctx.Done() (for performance) method string // the associated RPC method of the stream recvCompress string @@ -250,6 +257,9 @@ type Stream struct { fc *inFlow wq *writeQuota + // Holds compressor names passed in grpc-accept-encoding metadata from the + // client. This is empty for the client side stream. + clientAdvertisedCompressors string // Callback to state application's intentions to read data. This // is used to adjust flow control, if needed. requestRead func(int) @@ -338,8 +348,24 @@ func (s *Stream) RecvCompress() string { } // SetSendCompress sets the compression algorithm to the stream. -func (s *Stream) SetSendCompress(str string) { - s.sendCompress = str +func (s *Stream) SetSendCompress(name string) error { + if s.isHeaderSent() || s.getState() == streamDone { + return errors.New("transport: set send compressor called after headers sent or stream done") + } + + s.sendCompress = name + return nil +} + +// SendCompress returns the send compressor name. +func (s *Stream) SendCompress() string { + return s.sendCompress +} + +// ClientAdvertisedCompressors returns the compressor names advertised by the +// client via grpc-accept-encoding header. +func (s *Stream) ClientAdvertisedCompressors() string { + return s.clientAdvertisedCompressors } // Done returns a channel which is closed when it receives the final status @@ -363,9 +389,15 @@ func (s *Stream) Header() (metadata.MD, error) { return s.header.Copy(), nil } s.waitOnHeader() + if !s.headerValid { return nil, s.status.Err() } + + if s.noHeaders { + return nil, ErrNoHeaders + } + return s.header.Copy(), nil } @@ -517,26 +549,21 @@ const ( // ServerConfig consists of all the configurations to establish a server transport. type ServerConfig struct { MaxStreams uint32 - AuthInfo credentials.AuthInfo + ConnectionTimeout time.Duration + Credentials credentials.TransportCredentials InTapHandle tap.ServerInHandle - StatsHandler stats.Handler + StatsHandlers []stats.Handler KeepaliveParams keepalive.ServerParameters KeepalivePolicy keepalive.EnforcementPolicy InitialWindowSize int32 InitialConnWindowSize int32 WriteBufferSize int ReadBufferSize int - ChannelzParentID int64 + ChannelzParentID *channelz.Identifier MaxHeaderListSize *uint32 HeaderTableSize *uint32 } -// NewServerTransport creates a ServerTransport with conn or non-nil error -// if it fails. -func NewServerTransport(protocol string, conn net.Conn, config *ServerConfig) (ServerTransport, error) { - return newHTTP2Server(conn, config) -} - // ConnectOptions covers all relevant options for communicating with the server. type ConnectOptions struct { // UserAgent is the application user agent. @@ -555,8 +582,8 @@ type ConnectOptions struct { CredsBundle credentials.Bundle // KeepaliveParams stores the keepalive parameters. KeepaliveParams keepalive.ClientParameters - // StatsHandler stores the handler for stats. - StatsHandler stats.Handler + // StatsHandlers stores the handler for stats. + StatsHandlers []stats.Handler // InitialWindowSize sets the initial window size for a stream. InitialWindowSize int32 // InitialConnWindowSize sets the initial window size for a connection. @@ -566,7 +593,7 @@ type ConnectOptions struct { // ReadBufferSize sets the size of read buffer, which in turn determines how much data can be read at most for one read syscall. ReadBufferSize int // ChannelzParentID sets the addrConn id which initiate the creation of this client transport. - ChannelzParentID int64 + ChannelzParentID *channelz.Identifier // MaxHeaderListSize sets the max (uncompressed) size of header list that is prepared to be received. MaxHeaderListSize *uint32 // UseProxy specifies if a proxy should be used. @@ -575,8 +602,8 @@ type ConnectOptions struct { // NewClientTransport establishes the transport with the required ConnectOptions // and returns it to the caller. -func NewClientTransport(connectCtx, ctx context.Context, addr resolver.Address, opts ConnectOptions, onPrefaceReceipt func(), onGoAway func(GoAwayReason), onClose func()) (ClientTransport, error) { - return newHTTP2Client(connectCtx, ctx, addr, opts, onPrefaceReceipt, onGoAway, onClose) +func NewClientTransport(connectCtx, ctx context.Context, addr resolver.Address, opts ConnectOptions, onClose func(GoAwayReason)) (ClientTransport, error) { + return newHTTP2Client(connectCtx, ctx, addr, opts, onClose) } // Options provides additional hints and information for message @@ -611,6 +638,8 @@ type CallHdr struct { ContentSubtype string PreviousAttempts int // value of grpc-previous-rpc-attempts header to set + + DoneFunc func() // called when the stream is finished } // ClientTransport is the common interface for all gRPC client-side transport @@ -619,7 +648,7 @@ type ClientTransport interface { // Close tears down this transport. Once it returns, the transport // should not be accessed any more. The caller must make sure this // is called only once. - Close() error + Close(err error) // GracefulClose starts to tear down the transport: the transport will stop // accepting new RPCs and NewStream will return error. Once all streams are @@ -653,8 +682,9 @@ type ClientTransport interface { // HTTP/2). GoAway() <-chan struct{} - // GetGoAwayReason returns the reason why GoAway frame was received. - GetGoAwayReason() GoAwayReason + // GetGoAwayReason returns the reason why GoAway frame was received, along + // with a human readable string with debug info. + GetGoAwayReason() (GoAwayReason, string) // RemoteAddr returns the remote network address. RemoteAddr() net.Addr @@ -690,13 +720,13 @@ type ServerTransport interface { // Close tears down the transport. Once it is called, the transport // should not be accessed any more. All the pending streams and their // handlers will be terminated asynchronously. - Close() error + Close(err error) // RemoteAddr returns the remote network address. RemoteAddr() net.Addr // Drain notifies the client this ServerTransport stops accepting new RPCs. - Drain() + Drain(debugData string) // IncrMsgSent increments the number of message sent through this transport. IncrMsgSent() @@ -741,6 +771,12 @@ func (e ConnectionError) Origin() error { return e.err } +// Unwrap returns the original error of this connection error or nil when the +// origin is nil. +func (e ConnectionError) Unwrap() error { + return e.err +} + var ( // ErrConnClosing indicates that the transport is closing. ErrConnClosing = connectionErrorf(true, nil, "transport is closing") diff --git a/vendor/google.golang.org/grpc/internal/xds_handshake_cluster.go b/vendor/google.golang.org/grpc/internal/xds_handshake_cluster.go new file mode 100644 index 00000000000..e8b492774d1 --- /dev/null +++ b/vendor/google.golang.org/grpc/internal/xds_handshake_cluster.go @@ -0,0 +1,40 @@ +/* + * Copyright 2021 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package internal + +import ( + "google.golang.org/grpc/attributes" + "google.golang.org/grpc/resolver" +) + +// handshakeClusterNameKey is the type used as the key to store cluster name in +// the Attributes field of resolver.Address. +type handshakeClusterNameKey struct{} + +// SetXDSHandshakeClusterName returns a copy of addr in which the Attributes field +// is updated with the cluster name. +func SetXDSHandshakeClusterName(addr resolver.Address, clusterName string) resolver.Address { + addr.Attributes = addr.Attributes.WithValue(handshakeClusterNameKey{}, clusterName) + return addr +} + +// GetXDSHandshakeClusterName returns cluster name stored in attr. +func GetXDSHandshakeClusterName(attr *attributes.Attributes) (string, bool) { + v := attr.Value(handshakeClusterNameKey{}) + name, ok := v.(string) + return name, ok +} diff --git a/vendor/google.golang.org/grpc/metadata/metadata.go b/vendor/google.golang.org/grpc/metadata/metadata.go index cf6d1b94781..a2cdcaf12a8 100644 --- a/vendor/google.golang.org/grpc/metadata/metadata.go +++ b/vendor/google.golang.org/grpc/metadata/metadata.go @@ -41,16 +41,17 @@ type MD map[string][]string // New creates an MD from a given key-value map. // // Only the following ASCII characters are allowed in keys: -// - digits: 0-9 -// - uppercase letters: A-Z (normalized to lower) -// - lowercase letters: a-z -// - special characters: -_. +// - digits: 0-9 +// - uppercase letters: A-Z (normalized to lower) +// - lowercase letters: a-z +// - special characters: -_. +// // Uppercase letters are automatically converted to lowercase. // // Keys beginning with "grpc-" are reserved for grpc-internal use only and may // result in errors if set in metadata. func New(m map[string]string) MD { - md := MD{} + md := make(MD, len(m)) for k, val := range m { key := strings.ToLower(k) md[key] = append(md[key], val) @@ -62,10 +63,11 @@ func New(m map[string]string) MD { // Pairs panics if len(kv) is odd. // // Only the following ASCII characters are allowed in keys: -// - digits: 0-9 -// - uppercase letters: A-Z (normalized to lower) -// - lowercase letters: a-z -// - special characters: -_. +// - digits: 0-9 +// - uppercase letters: A-Z (normalized to lower) +// - lowercase letters: a-z +// - special characters: -_. +// // Uppercase letters are automatically converted to lowercase. // // Keys beginning with "grpc-" are reserved for grpc-internal use only and may @@ -74,14 +76,10 @@ func Pairs(kv ...string) MD { if len(kv)%2 == 1 { panic(fmt.Sprintf("metadata: Pairs got the odd number of input pairs for metadata: %d", len(kv))) } - md := MD{} - var key string - for i, s := range kv { - if i%2 == 0 { - key = strings.ToLower(s) - continue - } - md[key] = append(md[key], s) + md := make(MD, len(kv)/2) + for i := 0; i < len(kv); i += 2 { + key := strings.ToLower(kv[i]) + md[key] = append(md[key], kv[i+1]) } return md } @@ -93,16 +91,24 @@ func (md MD) Len() int { // Copy returns a copy of md. func (md MD) Copy() MD { - return Join(md) + out := make(MD, len(md)) + for k, v := range md { + out[k] = copyOf(v) + } + return out } // Get obtains the values for a given key. +// +// k is converted to lowercase before searching in md. func (md MD) Get(k string) []string { k = strings.ToLower(k) return md[k] } // Set sets the value of a given key with a slice of values. +// +// k is converted to lowercase before storing in md. func (md MD) Set(k string, vals ...string) { if len(vals) == 0 { return @@ -111,7 +117,10 @@ func (md MD) Set(k string, vals ...string) { md[k] = vals } -// Append adds the values to key k, not overwriting what was already stored at that key. +// Append adds the values to key k, not overwriting what was already stored at +// that key. +// +// k is converted to lowercase before storing in md. func (md MD) Append(k string, vals ...string) { if len(vals) == 0 { return @@ -120,9 +129,17 @@ func (md MD) Append(k string, vals ...string) { md[k] = append(md[k], vals...) } +// Delete removes the values for a given key k which is converted to lowercase +// before removing it from md. +func (md MD) Delete(k string) { + k = strings.ToLower(k) + delete(md, k) +} + // Join joins any number of mds into a single MD. -// The order of values for each key is determined by the order in which -// the mds containing those values are presented to Join. +// +// The order of values for each key is determined by the order in which the mds +// containing those values are presented to Join. func Join(mds ...MD) MD { out := MD{} for _, md := range mds { @@ -149,8 +166,8 @@ func NewOutgoingContext(ctx context.Context, md MD) context.Context { } // AppendToOutgoingContext returns a new context with the provided kv merged -// with any existing metadata in the context. Please refer to the -// documentation of Pairs for a description of kv. +// with any existing metadata in the context. Please refer to the documentation +// of Pairs for a description of kv. func AppendToOutgoingContext(ctx context.Context, kv ...string) context.Context { if len(kv)%2 == 1 { panic(fmt.Sprintf("metadata: AppendToOutgoingContext got an odd number of input pairs for metadata: %d", len(kv))) @@ -158,25 +175,76 @@ func AppendToOutgoingContext(ctx context.Context, kv ...string) context.Context md, _ := ctx.Value(mdOutgoingKey{}).(rawMD) added := make([][]string, len(md.added)+1) copy(added, md.added) - added[len(added)-1] = make([]string, len(kv)) - copy(added[len(added)-1], kv) + kvCopy := make([]string, 0, len(kv)) + for i := 0; i < len(kv); i += 2 { + kvCopy = append(kvCopy, strings.ToLower(kv[i]), kv[i+1]) + } + added[len(added)-1] = kvCopy return context.WithValue(ctx, mdOutgoingKey{}, rawMD{md: md.md, added: added}) } -// FromIncomingContext returns the incoming metadata in ctx if it exists. The -// returned MD should not be modified. Writing to it may cause races. -// Modification should be made to copies of the returned MD. -func FromIncomingContext(ctx context.Context) (md MD, ok bool) { - md, ok = ctx.Value(mdIncomingKey{}).(MD) - return +// FromIncomingContext returns the incoming metadata in ctx if it exists. +// +// All keys in the returned MD are lowercase. +func FromIncomingContext(ctx context.Context) (MD, bool) { + md, ok := ctx.Value(mdIncomingKey{}).(MD) + if !ok { + return nil, false + } + out := make(MD, len(md)) + for k, v := range md { + // We need to manually convert all keys to lower case, because MD is a + // map, and there's no guarantee that the MD attached to the context is + // created using our helper functions. + key := strings.ToLower(k) + out[key] = copyOf(v) + } + return out, true +} + +// ValueFromIncomingContext returns the metadata value corresponding to the metadata +// key from the incoming metadata if it exists. Key must be lower-case. +// +// # Experimental +// +// Notice: This API is EXPERIMENTAL and may be changed or removed in a +// later release. +func ValueFromIncomingContext(ctx context.Context, key string) []string { + md, ok := ctx.Value(mdIncomingKey{}).(MD) + if !ok { + return nil + } + + if v, ok := md[key]; ok { + return copyOf(v) + } + for k, v := range md { + // We need to manually convert all keys to lower case, because MD is a + // map, and there's no guarantee that the MD attached to the context is + // created using our helper functions. + if strings.ToLower(k) == key { + return copyOf(v) + } + } + return nil +} + +// the returned slice must not be modified in place +func copyOf(v []string) []string { + vals := make([]string, len(v)) + copy(vals, v) + return vals } -// FromOutgoingContextRaw returns the un-merged, intermediary contents -// of rawMD. Remember to perform strings.ToLower on the keys. The returned -// MD should not be modified. Writing to it may cause races. Modification -// should be made to copies of the returned MD. +// FromOutgoingContextRaw returns the un-merged, intermediary contents of rawMD. +// +// Remember to perform strings.ToLower on the keys, for both the returned MD (MD +// is a map, there's no guarantee it's created using our helper functions) and +// the extra kv pairs (AppendToOutgoingContext doesn't turn them into +// lowercase). // -// This is intended for gRPC-internal use ONLY. +// This is intended for gRPC-internal use ONLY. Users should use +// FromOutgoingContext instead. func FromOutgoingContextRaw(ctx context.Context) (MD, [][]string, bool) { raw, ok := ctx.Value(mdOutgoingKey{}).(rawMD) if !ok { @@ -186,21 +254,39 @@ func FromOutgoingContextRaw(ctx context.Context) (MD, [][]string, bool) { return raw.md, raw.added, true } -// FromOutgoingContext returns the outgoing metadata in ctx if it exists. The -// returned MD should not be modified. Writing to it may cause races. -// Modification should be made to copies of the returned MD. +// FromOutgoingContext returns the outgoing metadata in ctx if it exists. +// +// All keys in the returned MD are lowercase. func FromOutgoingContext(ctx context.Context) (MD, bool) { raw, ok := ctx.Value(mdOutgoingKey{}).(rawMD) if !ok { return nil, false } - mds := make([]MD, 0, len(raw.added)+1) - mds = append(mds, raw.md) - for _, vv := range raw.added { - mds = append(mds, Pairs(vv...)) + mdSize := len(raw.md) + for i := range raw.added { + mdSize += len(raw.added[i]) / 2 + } + + out := make(MD, mdSize) + for k, v := range raw.md { + // We need to manually convert all keys to lower case, because MD is a + // map, and there's no guarantee that the MD attached to the context is + // created using our helper functions. + key := strings.ToLower(k) + out[key] = copyOf(v) + } + for _, added := range raw.added { + if len(added)%2 == 1 { + panic(fmt.Sprintf("metadata: FromOutgoingContext got an odd number of input pairs for metadata: %d", len(added))) + } + + for i := 0; i < len(added); i += 2 { + key := strings.ToLower(added[i]) + out[key] = append(out[key], added[i+1]) + } } - return Join(mds...), ok + return out, ok } type rawMD struct { diff --git a/vendor/google.golang.org/grpc/picker_wrapper.go b/vendor/google.golang.org/grpc/picker_wrapper.go index a58174b6f43..02f97595124 100644 --- a/vendor/google.golang.org/grpc/picker_wrapper.go +++ b/vendor/google.golang.org/grpc/picker_wrapper.go @@ -26,6 +26,7 @@ import ( "google.golang.org/grpc/balancer" "google.golang.org/grpc/codes" "google.golang.org/grpc/internal/channelz" + istatus "google.golang.org/grpc/internal/status" "google.golang.org/grpc/internal/transport" "google.golang.org/grpc/status" ) @@ -35,6 +36,7 @@ import ( type pickerWrapper struct { mu sync.Mutex done bool + idle bool blockingCh chan struct{} picker balancer.Picker } @@ -46,7 +48,11 @@ func newPickerWrapper() *pickerWrapper { // updatePicker is called by UpdateBalancerState. It unblocks all blocked pick. func (pw *pickerWrapper) updatePicker(p balancer.Picker) { pw.mu.Lock() - if pw.done { + if pw.done || pw.idle { + // There is a small window where a picker update from the LB policy can + // race with the channel going to idle mode. If the picker is idle here, + // it is because the channel asked it to do so, and therefore it is sage + // to ignore the update from the LB policy. pw.mu.Unlock() return } @@ -57,12 +63,16 @@ func (pw *pickerWrapper) updatePicker(p balancer.Picker) { pw.mu.Unlock() } -func doneChannelzWrapper(acw *acBalancerWrapper, done func(balancer.DoneInfo)) func(balancer.DoneInfo) { - acw.mu.Lock() - ac := acw.ac - acw.mu.Unlock() +// doneChannelzWrapper performs the following: +// - increments the calls started channelz counter +// - wraps the done function in the passed in result to increment the calls +// failed or calls succeeded channelz counter before invoking the actual +// done function. +func doneChannelzWrapper(acbw *acBalancerWrapper, result *balancer.PickResult) { + ac := acbw.ac ac.incrCallsStarted() - return func(b balancer.DoneInfo) { + done := result.Done + result.Done = func(b balancer.DoneInfo) { if b.Err != nil && b.Err != io.EOF { ac.incrCallsFailed() } else { @@ -81,7 +91,7 @@ func doneChannelzWrapper(acw *acBalancerWrapper, done func(balancer.DoneInfo)) f // - the current picker returns other errors and failfast is false. // - the subConn returned by the current picker is not READY // When one of these situations happens, pick blocks until the picker gets updated. -func (pw *pickerWrapper) pick(ctx context.Context, failfast bool, info balancer.PickInfo) (transport.ClientTransport, func(balancer.DoneInfo), error) { +func (pw *pickerWrapper) pick(ctx context.Context, failfast bool, info balancer.PickInfo) (transport.ClientTransport, balancer.PickResult, error) { var ch chan struct{} var lastPickErr error @@ -89,7 +99,7 @@ func (pw *pickerWrapper) pick(ctx context.Context, failfast bool, info balancer. pw.mu.Lock() if pw.done { pw.mu.Unlock() - return nil, nil, ErrClientConnClosing + return nil, balancer.PickResult{}, ErrClientConnClosing } if pw.picker == nil { @@ -110,9 +120,9 @@ func (pw *pickerWrapper) pick(ctx context.Context, failfast bool, info balancer. } switch ctx.Err() { case context.DeadlineExceeded: - return nil, nil, status.Error(codes.DeadlineExceeded, errStr) + return nil, balancer.PickResult{}, status.Error(codes.DeadlineExceeded, errStr) case context.Canceled: - return nil, nil, status.Error(codes.Canceled, errStr) + return nil, balancer.PickResult{}, status.Error(codes.Canceled, errStr) } case <-ch: } @@ -124,14 +134,17 @@ func (pw *pickerWrapper) pick(ctx context.Context, failfast bool, info balancer. pw.mu.Unlock() pickResult, err := p.Pick(info) - if err != nil { if err == balancer.ErrNoSubConnAvailable { continue } - if _, ok := status.FromError(err); ok { + if st, ok := status.FromError(err); ok { // Status error: end the RPC unconditionally with this status. - return nil, nil, err + // First restrict the code to the list allowed by gRFC A54. + if istatus.IsRestrictedControlPlaneCode(st) { + err = status.Errorf(codes.Internal, "received picker error with illegal status: %v", err) + } + return nil, balancer.PickResult{}, dropError{error: err} } // For all other errors, wait for ready RPCs should block and other // RPCs should fail with unavailable. @@ -139,19 +152,20 @@ func (pw *pickerWrapper) pick(ctx context.Context, failfast bool, info balancer. lastPickErr = err continue } - return nil, nil, status.Error(codes.Unavailable, err.Error()) + return nil, balancer.PickResult{}, status.Error(codes.Unavailable, err.Error()) } - acw, ok := pickResult.SubConn.(*acBalancerWrapper) + acbw, ok := pickResult.SubConn.(*acBalancerWrapper) if !ok { - logger.Error("subconn returned from pick is not *acBalancerWrapper") + logger.Errorf("subconn returned from pick is type %T, not *acBalancerWrapper", pickResult.SubConn) continue } - if t, ok := acw.getAddrConn().getReadyTransport(); ok { + if t := acbw.ac.getReadyTransport(); t != nil { if channelz.IsOn() { - return t, doneChannelzWrapper(acw, pickResult.Done), nil + doneChannelzWrapper(acbw, &pickResult) + return t, pickResult, nil } - return t, pickResult.Done, nil + return t, pickResult, nil } if pickResult.Done != nil { // Calling done with nil error, no bytes sent and no bytes received. @@ -175,3 +189,28 @@ func (pw *pickerWrapper) close() { pw.done = true close(pw.blockingCh) } + +func (pw *pickerWrapper) enterIdleMode() { + pw.mu.Lock() + defer pw.mu.Unlock() + if pw.done { + return + } + pw.idle = true +} + +func (pw *pickerWrapper) exitIdleMode() { + pw.mu.Lock() + defer pw.mu.Unlock() + if pw.done { + return + } + pw.blockingCh = make(chan struct{}) + pw.idle = false +} + +// dropError is a wrapper error that indicates the LB policy wishes to drop the +// RPC and not retry it. +type dropError struct { + error +} diff --git a/vendor/google.golang.org/grpc/pickfirst.go b/vendor/google.golang.org/grpc/pickfirst.go index 56e33f6c76b..abe266b021d 100644 --- a/vendor/google.golang.org/grpc/pickfirst.go +++ b/vendor/google.golang.org/grpc/pickfirst.go @@ -19,11 +19,15 @@ package grpc import ( + "encoding/json" "errors" "fmt" "google.golang.org/grpc/balancer" "google.golang.org/grpc/connectivity" + "google.golang.org/grpc/internal/envconfig" + "google.golang.org/grpc/internal/grpcrand" + "google.golang.org/grpc/serviceconfig" ) // PickFirstBalancerName is the name of the pick_first balancer. @@ -43,94 +47,181 @@ func (*pickfirstBuilder) Name() string { return PickFirstBalancerName } +type pfConfig struct { + serviceconfig.LoadBalancingConfig `json:"-"` + + // If set to true, instructs the LB policy to shuffle the order of the list + // of addresses received from the name resolver before attempting to + // connect to them. + ShuffleAddressList bool `json:"shuffleAddressList"` +} + +func (*pickfirstBuilder) ParseConfig(js json.RawMessage) (serviceconfig.LoadBalancingConfig, error) { + cfg := &pfConfig{} + if err := json.Unmarshal(js, cfg); err != nil { + return nil, fmt.Errorf("pickfirst: unable to unmarshal LB policy config: %s, error: %v", string(js), err) + } + return cfg, nil +} + type pickfirstBalancer struct { - state connectivity.State - cc balancer.ClientConn - sc balancer.SubConn + state connectivity.State + cc balancer.ClientConn + subConn balancer.SubConn + cfg *pfConfig } func (b *pickfirstBalancer) ResolverError(err error) { - switch b.state { - case connectivity.TransientFailure, connectivity.Idle, connectivity.Connecting: - // Set a failing picker if we don't have a good picker. - b.cc.UpdateState(balancer.State{ConnectivityState: connectivity.TransientFailure, - Picker: &picker{err: fmt.Errorf("name resolver error: %v", err)}, - }) - } if logger.V(2) { - logger.Infof("pickfirstBalancer: ResolverError called with error %v", err) + logger.Infof("pickfirstBalancer: ResolverError called with error: %v", err) + } + if b.subConn == nil { + b.state = connectivity.TransientFailure + } + + if b.state != connectivity.TransientFailure { + // The picker will not change since the balancer does not currently + // report an error. + return } + b.cc.UpdateState(balancer.State{ + ConnectivityState: connectivity.TransientFailure, + Picker: &picker{err: fmt.Errorf("name resolver error: %v", err)}, + }) } -func (b *pickfirstBalancer) UpdateClientConnState(cs balancer.ClientConnState) error { - if len(cs.ResolverState.Addresses) == 0 { +func (b *pickfirstBalancer) UpdateClientConnState(state balancer.ClientConnState) error { + addrs := state.ResolverState.Addresses + if len(addrs) == 0 { + // The resolver reported an empty address list. Treat it like an error by + // calling b.ResolverError. + if b.subConn != nil { + // Remove the old subConn. All addresses were removed, so it is no longer + // valid. + b.cc.RemoveSubConn(b.subConn) + b.subConn = nil + } b.ResolverError(errors.New("produced zero addresses")) return balancer.ErrBadResolverState } - if b.sc == nil { - var err error - b.sc, err = b.cc.NewSubConn(cs.ResolverState.Addresses, balancer.NewSubConnOptions{}) - if err != nil { - if logger.V(2) { - logger.Errorf("pickfirstBalancer: failed to NewSubConn: %v", err) - } - b.state = connectivity.TransientFailure - b.cc.UpdateState(balancer.State{ConnectivityState: connectivity.TransientFailure, - Picker: &picker{err: fmt.Errorf("error creating connection: %v", err)}, - }) - return balancer.ErrBadResolverState + + if state.BalancerConfig != nil { + cfg, ok := state.BalancerConfig.(*pfConfig) + if !ok { + return fmt.Errorf("pickfirstBalancer: received nil or illegal BalancerConfig (type %T): %v", state.BalancerConfig, state.BalancerConfig) } - b.state = connectivity.Idle - b.cc.UpdateState(balancer.State{ConnectivityState: connectivity.Idle, Picker: &picker{result: balancer.PickResult{SubConn: b.sc}}}) - b.sc.Connect() - } else { - b.sc.UpdateAddresses(cs.ResolverState.Addresses) - b.sc.Connect() + b.cfg = cfg + } + + if envconfig.PickFirstLBConfig && b.cfg != nil && b.cfg.ShuffleAddressList { + grpcrand.Shuffle(len(addrs), func(i, j int) { addrs[i], addrs[j] = addrs[j], addrs[i] }) + } + if b.subConn != nil { + b.cc.UpdateAddresses(b.subConn, addrs) + return nil } + + subConn, err := b.cc.NewSubConn(addrs, balancer.NewSubConnOptions{}) + if err != nil { + if logger.V(2) { + logger.Errorf("pickfirstBalancer: failed to NewSubConn: %v", err) + } + b.state = connectivity.TransientFailure + b.cc.UpdateState(balancer.State{ + ConnectivityState: connectivity.TransientFailure, + Picker: &picker{err: fmt.Errorf("error creating connection: %v", err)}, + }) + return balancer.ErrBadResolverState + } + b.subConn = subConn + b.state = connectivity.Idle + b.cc.UpdateState(balancer.State{ + ConnectivityState: connectivity.Connecting, + Picker: &picker{err: balancer.ErrNoSubConnAvailable}, + }) + b.subConn.Connect() return nil } -func (b *pickfirstBalancer) UpdateSubConnState(sc balancer.SubConn, s balancer.SubConnState) { +func (b *pickfirstBalancer) UpdateSubConnState(subConn balancer.SubConn, state balancer.SubConnState) { if logger.V(2) { - logger.Infof("pickfirstBalancer: UpdateSubConnState: %p, %v", sc, s) + logger.Infof("pickfirstBalancer: UpdateSubConnState: %p, %v", subConn, state) } - if b.sc != sc { + if b.subConn != subConn { if logger.V(2) { - logger.Infof("pickfirstBalancer: ignored state change because sc is not recognized") + logger.Infof("pickfirstBalancer: ignored state change because subConn is not recognized") } return } - b.state = s.ConnectivityState - if s.ConnectivityState == connectivity.Shutdown { - b.sc = nil + if state.ConnectivityState == connectivity.Shutdown { + b.subConn = nil return } - switch s.ConnectivityState { - case connectivity.Ready, connectivity.Idle: - b.cc.UpdateState(balancer.State{ConnectivityState: s.ConnectivityState, Picker: &picker{result: balancer.PickResult{SubConn: sc}}}) + switch state.ConnectivityState { + case connectivity.Ready: + b.cc.UpdateState(balancer.State{ + ConnectivityState: state.ConnectivityState, + Picker: &picker{result: balancer.PickResult{SubConn: subConn}}, + }) case connectivity.Connecting: - b.cc.UpdateState(balancer.State{ConnectivityState: s.ConnectivityState, Picker: &picker{err: balancer.ErrNoSubConnAvailable}}) + if b.state == connectivity.TransientFailure { + // We stay in TransientFailure until we are Ready. See A62. + return + } + b.cc.UpdateState(balancer.State{ + ConnectivityState: state.ConnectivityState, + Picker: &picker{err: balancer.ErrNoSubConnAvailable}, + }) + case connectivity.Idle: + if b.state == connectivity.TransientFailure { + // We stay in TransientFailure until we are Ready. Also kick the + // subConn out of Idle into Connecting. See A62. + b.subConn.Connect() + return + } + b.cc.UpdateState(balancer.State{ + ConnectivityState: state.ConnectivityState, + Picker: &idlePicker{subConn: subConn}, + }) case connectivity.TransientFailure: b.cc.UpdateState(balancer.State{ - ConnectivityState: s.ConnectivityState, - Picker: &picker{err: s.ConnectionError}, + ConnectivityState: state.ConnectivityState, + Picker: &picker{err: state.ConnectionError}, }) } + b.state = state.ConnectivityState } func (b *pickfirstBalancer) Close() { } +func (b *pickfirstBalancer) ExitIdle() { + if b.subConn != nil && b.state == connectivity.Idle { + b.subConn.Connect() + } +} + type picker struct { result balancer.PickResult err error } -func (p *picker) Pick(info balancer.PickInfo) (balancer.PickResult, error) { +func (p *picker) Pick(balancer.PickInfo) (balancer.PickResult, error) { return p.result, p.err } +// idlePicker is used when the SubConn is IDLE and kicks the SubConn into +// CONNECTING when Pick is called. +type idlePicker struct { + subConn balancer.SubConn +} + +func (i *idlePicker) Pick(balancer.PickInfo) (balancer.PickResult, error) { + i.subConn.Connect() + return balancer.PickResult{}, balancer.ErrNoSubConnAvailable +} + func init() { balancer.Register(newPickfirstBuilder()) } diff --git a/vendor/google.golang.org/grpc/preloader.go b/vendor/google.golang.org/grpc/preloader.go index 0a1e975ad91..cd45547854f 100644 --- a/vendor/google.golang.org/grpc/preloader.go +++ b/vendor/google.golang.org/grpc/preloader.go @@ -25,7 +25,7 @@ import ( // PreparedMsg is responsible for creating a Marshalled and Compressed object. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. diff --git a/vendor/google.golang.org/grpc/reflection/grpc_reflection_v1alpha/reflection.pb.go b/vendor/google.golang.org/grpc/reflection/grpc_reflection_v1alpha/reflection.pb.go index 1f859f76488..d54c07676d5 100644 --- a/vendor/google.golang.org/grpc/reflection/grpc_reflection_v1alpha/reflection.pb.go +++ b/vendor/google.golang.org/grpc/reflection/grpc_reflection_v1alpha/reflection.pb.go @@ -1,4 +1,4 @@ -// Copyright 2016 gRPC authors. +// Copyright 2016 The gRPC Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -11,19 +11,20 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. - // Service exported by server reflection +// Warning: this entire file is deprecated. Use this instead: +// https://github.com/grpc/grpc-proto/blob/master/grpc/reflection/v1/reflection.proto + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.25.0 -// protoc v3.14.0 -// source: reflection/grpc_reflection_v1alpha/reflection.proto +// protoc-gen-go v1.30.0 +// protoc v4.22.0 +// grpc/reflection/v1alpha/reflection.proto is a deprecated file. package grpc_reflection_v1alpha import ( - proto "github.com/golang/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -37,22 +38,22 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - // The message sent by the client when calling ServerReflectionInfo method. +// +// Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. type ServerReflectionRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + // Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. Host string `protobuf:"bytes,1,opt,name=host,proto3" json:"host,omitempty"` // To use reflection service, the client should set one of the following // fields in message_request. The server distinguishes requests by their // defined field and then handles them using corresponding methods. // // Types that are assignable to MessageRequest: + // // *ServerReflectionRequest_FileByFilename // *ServerReflectionRequest_FileContainingSymbol // *ServerReflectionRequest_FileContainingExtension @@ -64,7 +65,7 @@ type ServerReflectionRequest struct { func (x *ServerReflectionRequest) Reset() { *x = ServerReflectionRequest{} if protoimpl.UnsafeEnabled { - mi := &file_reflection_grpc_reflection_v1alpha_reflection_proto_msgTypes[0] + mi := &file_grpc_reflection_v1alpha_reflection_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -77,7 +78,7 @@ func (x *ServerReflectionRequest) String() string { func (*ServerReflectionRequest) ProtoMessage() {} func (x *ServerReflectionRequest) ProtoReflect() protoreflect.Message { - mi := &file_reflection_grpc_reflection_v1alpha_reflection_proto_msgTypes[0] + mi := &file_grpc_reflection_v1alpha_reflection_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -90,9 +91,10 @@ func (x *ServerReflectionRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ServerReflectionRequest.ProtoReflect.Descriptor instead. func (*ServerReflectionRequest) Descriptor() ([]byte, []int) { - return file_reflection_grpc_reflection_v1alpha_reflection_proto_rawDescGZIP(), []int{0} + return file_grpc_reflection_v1alpha_reflection_proto_rawDescGZIP(), []int{0} } +// Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. func (x *ServerReflectionRequest) GetHost() string { if x != nil { return x.Host @@ -107,6 +109,7 @@ func (m *ServerReflectionRequest) GetMessageRequest() isServerReflectionRequest_ return nil } +// Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. func (x *ServerReflectionRequest) GetFileByFilename() string { if x, ok := x.GetMessageRequest().(*ServerReflectionRequest_FileByFilename); ok { return x.FileByFilename @@ -114,6 +117,7 @@ func (x *ServerReflectionRequest) GetFileByFilename() string { return "" } +// Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. func (x *ServerReflectionRequest) GetFileContainingSymbol() string { if x, ok := x.GetMessageRequest().(*ServerReflectionRequest_FileContainingSymbol); ok { return x.FileContainingSymbol @@ -121,6 +125,7 @@ func (x *ServerReflectionRequest) GetFileContainingSymbol() string { return "" } +// Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. func (x *ServerReflectionRequest) GetFileContainingExtension() *ExtensionRequest { if x, ok := x.GetMessageRequest().(*ServerReflectionRequest_FileContainingExtension); ok { return x.FileContainingExtension @@ -128,6 +133,7 @@ func (x *ServerReflectionRequest) GetFileContainingExtension() *ExtensionRequest return nil } +// Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. func (x *ServerReflectionRequest) GetAllExtensionNumbersOfType() string { if x, ok := x.GetMessageRequest().(*ServerReflectionRequest_AllExtensionNumbersOfType); ok { return x.AllExtensionNumbersOfType @@ -135,6 +141,7 @@ func (x *ServerReflectionRequest) GetAllExtensionNumbersOfType() string { return "" } +// Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. func (x *ServerReflectionRequest) GetListServices() string { if x, ok := x.GetMessageRequest().(*ServerReflectionRequest_ListServices); ok { return x.ListServices @@ -148,6 +155,8 @@ type isServerReflectionRequest_MessageRequest interface { type ServerReflectionRequest_FileByFilename struct { // Find a proto file by the file name. + // + // Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. FileByFilename string `protobuf:"bytes,3,opt,name=file_by_filename,json=fileByFilename,proto3,oneof"` } @@ -155,12 +164,16 @@ type ServerReflectionRequest_FileContainingSymbol struct { // Find the proto file that declares the given fully-qualified symbol name. // This field should be a fully-qualified symbol name // (e.g. .[.] or .). + // + // Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. FileContainingSymbol string `protobuf:"bytes,4,opt,name=file_containing_symbol,json=fileContainingSymbol,proto3,oneof"` } type ServerReflectionRequest_FileContainingExtension struct { // Find the proto file which defines an extension extending the given // message type with the given field number. + // + // Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. FileContainingExtension *ExtensionRequest `protobuf:"bytes,5,opt,name=file_containing_extension,json=fileContainingExtension,proto3,oneof"` } @@ -173,12 +186,16 @@ type ServerReflectionRequest_AllExtensionNumbersOfType struct { // StatusCode::UNIMPLEMENTED if it's not implemented. // This field should be a fully-qualified type name. The format is // . + // + // Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. AllExtensionNumbersOfType string `protobuf:"bytes,6,opt,name=all_extension_numbers_of_type,json=allExtensionNumbersOfType,proto3,oneof"` } type ServerReflectionRequest_ListServices struct { // List the full names of registered services. The content will not be // checked. + // + // Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. ListServices string `protobuf:"bytes,7,opt,name=list_services,json=listServices,proto3,oneof"` } @@ -195,20 +212,25 @@ func (*ServerReflectionRequest_ListServices) isServerReflectionRequest_MessageRe // The type name and extension number sent by the client when requesting // file_containing_extension. +// +// Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. type ExtensionRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields // Fully-qualified type name. The format should be . - ContainingType string `protobuf:"bytes,1,opt,name=containing_type,json=containingType,proto3" json:"containing_type,omitempty"` - ExtensionNumber int32 `protobuf:"varint,2,opt,name=extension_number,json=extensionNumber,proto3" json:"extension_number,omitempty"` + // + // Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. + ContainingType string `protobuf:"bytes,1,opt,name=containing_type,json=containingType,proto3" json:"containing_type,omitempty"` + // Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. + ExtensionNumber int32 `protobuf:"varint,2,opt,name=extension_number,json=extensionNumber,proto3" json:"extension_number,omitempty"` } func (x *ExtensionRequest) Reset() { *x = ExtensionRequest{} if protoimpl.UnsafeEnabled { - mi := &file_reflection_grpc_reflection_v1alpha_reflection_proto_msgTypes[1] + mi := &file_grpc_reflection_v1alpha_reflection_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -221,7 +243,7 @@ func (x *ExtensionRequest) String() string { func (*ExtensionRequest) ProtoMessage() {} func (x *ExtensionRequest) ProtoReflect() protoreflect.Message { - mi := &file_reflection_grpc_reflection_v1alpha_reflection_proto_msgTypes[1] + mi := &file_grpc_reflection_v1alpha_reflection_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -234,9 +256,10 @@ func (x *ExtensionRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ExtensionRequest.ProtoReflect.Descriptor instead. func (*ExtensionRequest) Descriptor() ([]byte, []int) { - return file_reflection_grpc_reflection_v1alpha_reflection_proto_rawDescGZIP(), []int{1} + return file_grpc_reflection_v1alpha_reflection_proto_rawDescGZIP(), []int{1} } +// Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. func (x *ExtensionRequest) GetContainingType() string { if x != nil { return x.ContainingType @@ -244,6 +267,7 @@ func (x *ExtensionRequest) GetContainingType() string { return "" } +// Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. func (x *ExtensionRequest) GetExtensionNumber() int32 { if x != nil { return x.ExtensionNumber @@ -252,17 +276,22 @@ func (x *ExtensionRequest) GetExtensionNumber() int32 { } // The message sent by the server to answer ServerReflectionInfo method. +// +// Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. type ServerReflectionResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - ValidHost string `protobuf:"bytes,1,opt,name=valid_host,json=validHost,proto3" json:"valid_host,omitempty"` + // Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. + ValidHost string `protobuf:"bytes,1,opt,name=valid_host,json=validHost,proto3" json:"valid_host,omitempty"` + // Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. OriginalRequest *ServerReflectionRequest `protobuf:"bytes,2,opt,name=original_request,json=originalRequest,proto3" json:"original_request,omitempty"` - // The server sets one of the following fields according to the - // message_request in the request. + // The server set one of the following fields according to the message_request + // in the request. // // Types that are assignable to MessageResponse: + // // *ServerReflectionResponse_FileDescriptorResponse // *ServerReflectionResponse_AllExtensionNumbersResponse // *ServerReflectionResponse_ListServicesResponse @@ -273,7 +302,7 @@ type ServerReflectionResponse struct { func (x *ServerReflectionResponse) Reset() { *x = ServerReflectionResponse{} if protoimpl.UnsafeEnabled { - mi := &file_reflection_grpc_reflection_v1alpha_reflection_proto_msgTypes[2] + mi := &file_grpc_reflection_v1alpha_reflection_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -286,7 +315,7 @@ func (x *ServerReflectionResponse) String() string { func (*ServerReflectionResponse) ProtoMessage() {} func (x *ServerReflectionResponse) ProtoReflect() protoreflect.Message { - mi := &file_reflection_grpc_reflection_v1alpha_reflection_proto_msgTypes[2] + mi := &file_grpc_reflection_v1alpha_reflection_proto_msgTypes[2] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -299,9 +328,10 @@ func (x *ServerReflectionResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ServerReflectionResponse.ProtoReflect.Descriptor instead. func (*ServerReflectionResponse) Descriptor() ([]byte, []int) { - return file_reflection_grpc_reflection_v1alpha_reflection_proto_rawDescGZIP(), []int{2} + return file_grpc_reflection_v1alpha_reflection_proto_rawDescGZIP(), []int{2} } +// Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. func (x *ServerReflectionResponse) GetValidHost() string { if x != nil { return x.ValidHost @@ -309,6 +339,7 @@ func (x *ServerReflectionResponse) GetValidHost() string { return "" } +// Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. func (x *ServerReflectionResponse) GetOriginalRequest() *ServerReflectionRequest { if x != nil { return x.OriginalRequest @@ -323,6 +354,7 @@ func (m *ServerReflectionResponse) GetMessageResponse() isServerReflectionRespon return nil } +// Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. func (x *ServerReflectionResponse) GetFileDescriptorResponse() *FileDescriptorResponse { if x, ok := x.GetMessageResponse().(*ServerReflectionResponse_FileDescriptorResponse); ok { return x.FileDescriptorResponse @@ -330,6 +362,7 @@ func (x *ServerReflectionResponse) GetFileDescriptorResponse() *FileDescriptorRe return nil } +// Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. func (x *ServerReflectionResponse) GetAllExtensionNumbersResponse() *ExtensionNumberResponse { if x, ok := x.GetMessageResponse().(*ServerReflectionResponse_AllExtensionNumbersResponse); ok { return x.AllExtensionNumbersResponse @@ -337,6 +370,7 @@ func (x *ServerReflectionResponse) GetAllExtensionNumbersResponse() *ExtensionNu return nil } +// Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. func (x *ServerReflectionResponse) GetListServicesResponse() *ListServiceResponse { if x, ok := x.GetMessageResponse().(*ServerReflectionResponse_ListServicesResponse); ok { return x.ListServicesResponse @@ -344,6 +378,7 @@ func (x *ServerReflectionResponse) GetListServicesResponse() *ListServiceRespons return nil } +// Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. func (x *ServerReflectionResponse) GetErrorResponse() *ErrorResponse { if x, ok := x.GetMessageResponse().(*ServerReflectionResponse_ErrorResponse); ok { return x.ErrorResponse @@ -357,26 +392,34 @@ type isServerReflectionResponse_MessageResponse interface { type ServerReflectionResponse_FileDescriptorResponse struct { // This message is used to answer file_by_filename, file_containing_symbol, - // file_containing_extension requests with transitive dependencies. - // As the repeated label is not allowed in oneof fields, we use a + // file_containing_extension requests with transitive dependencies. As + // the repeated label is not allowed in oneof fields, we use a // FileDescriptorResponse message to encapsulate the repeated fields. // The reflection service is allowed to avoid sending FileDescriptorProtos // that were previously sent in response to earlier requests in the stream. + // + // Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. FileDescriptorResponse *FileDescriptorResponse `protobuf:"bytes,4,opt,name=file_descriptor_response,json=fileDescriptorResponse,proto3,oneof"` } type ServerReflectionResponse_AllExtensionNumbersResponse struct { - // This message is used to answer all_extension_numbers_of_type requests. + // This message is used to answer all_extension_numbers_of_type requst. + // + // Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. AllExtensionNumbersResponse *ExtensionNumberResponse `protobuf:"bytes,5,opt,name=all_extension_numbers_response,json=allExtensionNumbersResponse,proto3,oneof"` } type ServerReflectionResponse_ListServicesResponse struct { - // This message is used to answer list_services requests. + // This message is used to answer list_services request. + // + // Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. ListServicesResponse *ListServiceResponse `protobuf:"bytes,6,opt,name=list_services_response,json=listServicesResponse,proto3,oneof"` } type ServerReflectionResponse_ErrorResponse struct { // This message is used when an error occurs. + // + // Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. ErrorResponse *ErrorResponse `protobuf:"bytes,7,opt,name=error_response,json=errorResponse,proto3,oneof"` } @@ -393,6 +436,8 @@ func (*ServerReflectionResponse_ErrorResponse) isServerReflectionResponse_Messag // Serialized FileDescriptorProto messages sent by the server answering // a file_by_filename, file_containing_symbol, or file_containing_extension // request. +// +// Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. type FileDescriptorResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -401,13 +446,15 @@ type FileDescriptorResponse struct { // Serialized FileDescriptorProto messages. We avoid taking a dependency on // descriptor.proto, which uses proto2 only features, by making them opaque // bytes instead. + // + // Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. FileDescriptorProto [][]byte `protobuf:"bytes,1,rep,name=file_descriptor_proto,json=fileDescriptorProto,proto3" json:"file_descriptor_proto,omitempty"` } func (x *FileDescriptorResponse) Reset() { *x = FileDescriptorResponse{} if protoimpl.UnsafeEnabled { - mi := &file_reflection_grpc_reflection_v1alpha_reflection_proto_msgTypes[3] + mi := &file_grpc_reflection_v1alpha_reflection_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -420,7 +467,7 @@ func (x *FileDescriptorResponse) String() string { func (*FileDescriptorResponse) ProtoMessage() {} func (x *FileDescriptorResponse) ProtoReflect() protoreflect.Message { - mi := &file_reflection_grpc_reflection_v1alpha_reflection_proto_msgTypes[3] + mi := &file_grpc_reflection_v1alpha_reflection_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -433,9 +480,10 @@ func (x *FileDescriptorResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use FileDescriptorResponse.ProtoReflect.Descriptor instead. func (*FileDescriptorResponse) Descriptor() ([]byte, []int) { - return file_reflection_grpc_reflection_v1alpha_reflection_proto_rawDescGZIP(), []int{3} + return file_grpc_reflection_v1alpha_reflection_proto_rawDescGZIP(), []int{3} } +// Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. func (x *FileDescriptorResponse) GetFileDescriptorProto() [][]byte { if x != nil { return x.FileDescriptorProto @@ -445,6 +493,8 @@ func (x *FileDescriptorResponse) GetFileDescriptorProto() [][]byte { // A list of extension numbers sent by the server answering // all_extension_numbers_of_type request. +// +// Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. type ExtensionNumberResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -452,14 +502,17 @@ type ExtensionNumberResponse struct { // Full name of the base type, including the package name. The format // is . - BaseTypeName string `protobuf:"bytes,1,opt,name=base_type_name,json=baseTypeName,proto3" json:"base_type_name,omitempty"` + // + // Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. + BaseTypeName string `protobuf:"bytes,1,opt,name=base_type_name,json=baseTypeName,proto3" json:"base_type_name,omitempty"` + // Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. ExtensionNumber []int32 `protobuf:"varint,2,rep,packed,name=extension_number,json=extensionNumber,proto3" json:"extension_number,omitempty"` } func (x *ExtensionNumberResponse) Reset() { *x = ExtensionNumberResponse{} if protoimpl.UnsafeEnabled { - mi := &file_reflection_grpc_reflection_v1alpha_reflection_proto_msgTypes[4] + mi := &file_grpc_reflection_v1alpha_reflection_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -472,7 +525,7 @@ func (x *ExtensionNumberResponse) String() string { func (*ExtensionNumberResponse) ProtoMessage() {} func (x *ExtensionNumberResponse) ProtoReflect() protoreflect.Message { - mi := &file_reflection_grpc_reflection_v1alpha_reflection_proto_msgTypes[4] + mi := &file_grpc_reflection_v1alpha_reflection_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -485,9 +538,10 @@ func (x *ExtensionNumberResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ExtensionNumberResponse.ProtoReflect.Descriptor instead. func (*ExtensionNumberResponse) Descriptor() ([]byte, []int) { - return file_reflection_grpc_reflection_v1alpha_reflection_proto_rawDescGZIP(), []int{4} + return file_grpc_reflection_v1alpha_reflection_proto_rawDescGZIP(), []int{4} } +// Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. func (x *ExtensionNumberResponse) GetBaseTypeName() string { if x != nil { return x.BaseTypeName @@ -495,6 +549,7 @@ func (x *ExtensionNumberResponse) GetBaseTypeName() string { return "" } +// Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. func (x *ExtensionNumberResponse) GetExtensionNumber() []int32 { if x != nil { return x.ExtensionNumber @@ -503,6 +558,8 @@ func (x *ExtensionNumberResponse) GetExtensionNumber() []int32 { } // A list of ServiceResponse sent by the server answering list_services request. +// +// Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. type ListServiceResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -510,13 +567,15 @@ type ListServiceResponse struct { // The information of each service may be expanded in the future, so we use // ServiceResponse message to encapsulate it. + // + // Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. Service []*ServiceResponse `protobuf:"bytes,1,rep,name=service,proto3" json:"service,omitempty"` } func (x *ListServiceResponse) Reset() { *x = ListServiceResponse{} if protoimpl.UnsafeEnabled { - mi := &file_reflection_grpc_reflection_v1alpha_reflection_proto_msgTypes[5] + mi := &file_grpc_reflection_v1alpha_reflection_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -529,7 +588,7 @@ func (x *ListServiceResponse) String() string { func (*ListServiceResponse) ProtoMessage() {} func (x *ListServiceResponse) ProtoReflect() protoreflect.Message { - mi := &file_reflection_grpc_reflection_v1alpha_reflection_proto_msgTypes[5] + mi := &file_grpc_reflection_v1alpha_reflection_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -542,9 +601,10 @@ func (x *ListServiceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListServiceResponse.ProtoReflect.Descriptor instead. func (*ListServiceResponse) Descriptor() ([]byte, []int) { - return file_reflection_grpc_reflection_v1alpha_reflection_proto_rawDescGZIP(), []int{5} + return file_grpc_reflection_v1alpha_reflection_proto_rawDescGZIP(), []int{5} } +// Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. func (x *ListServiceResponse) GetService() []*ServiceResponse { if x != nil { return x.Service @@ -554,6 +614,8 @@ func (x *ListServiceResponse) GetService() []*ServiceResponse { // The information of a single service used by ListServiceResponse to answer // list_services request. +// +// Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. type ServiceResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -561,13 +623,15 @@ type ServiceResponse struct { // Full name of a registered service, including its package name. The format // is . + // + // Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` } func (x *ServiceResponse) Reset() { *x = ServiceResponse{} if protoimpl.UnsafeEnabled { - mi := &file_reflection_grpc_reflection_v1alpha_reflection_proto_msgTypes[6] + mi := &file_grpc_reflection_v1alpha_reflection_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -580,7 +644,7 @@ func (x *ServiceResponse) String() string { func (*ServiceResponse) ProtoMessage() {} func (x *ServiceResponse) ProtoReflect() protoreflect.Message { - mi := &file_reflection_grpc_reflection_v1alpha_reflection_proto_msgTypes[6] + mi := &file_grpc_reflection_v1alpha_reflection_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -593,9 +657,10 @@ func (x *ServiceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ServiceResponse.ProtoReflect.Descriptor instead. func (*ServiceResponse) Descriptor() ([]byte, []int) { - return file_reflection_grpc_reflection_v1alpha_reflection_proto_rawDescGZIP(), []int{6} + return file_grpc_reflection_v1alpha_reflection_proto_rawDescGZIP(), []int{6} } +// Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. func (x *ServiceResponse) GetName() string { if x != nil { return x.Name @@ -604,20 +669,25 @@ func (x *ServiceResponse) GetName() string { } // The error code and error message sent by the server when an error occurs. +// +// Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. type ErrorResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields // This field uses the error codes defined in grpc::StatusCode. - ErrorCode int32 `protobuf:"varint,1,opt,name=error_code,json=errorCode,proto3" json:"error_code,omitempty"` + // + // Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. + ErrorCode int32 `protobuf:"varint,1,opt,name=error_code,json=errorCode,proto3" json:"error_code,omitempty"` + // Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. ErrorMessage string `protobuf:"bytes,2,opt,name=error_message,json=errorMessage,proto3" json:"error_message,omitempty"` } func (x *ErrorResponse) Reset() { *x = ErrorResponse{} if protoimpl.UnsafeEnabled { - mi := &file_reflection_grpc_reflection_v1alpha_reflection_proto_msgTypes[7] + mi := &file_grpc_reflection_v1alpha_reflection_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -630,7 +700,7 @@ func (x *ErrorResponse) String() string { func (*ErrorResponse) ProtoMessage() {} func (x *ErrorResponse) ProtoReflect() protoreflect.Message { - mi := &file_reflection_grpc_reflection_v1alpha_reflection_proto_msgTypes[7] + mi := &file_grpc_reflection_v1alpha_reflection_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -643,9 +713,10 @@ func (x *ErrorResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ErrorResponse.ProtoReflect.Descriptor instead. func (*ErrorResponse) Descriptor() ([]byte, []int) { - return file_reflection_grpc_reflection_v1alpha_reflection_proto_rawDescGZIP(), []int{7} + return file_grpc_reflection_v1alpha_reflection_proto_rawDescGZIP(), []int{7} } +// Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. func (x *ErrorResponse) GetErrorCode() int32 { if x != nil { return x.ErrorCode @@ -653,6 +724,7 @@ func (x *ErrorResponse) GetErrorCode() int32 { return 0 } +// Deprecated: The entire proto file grpc/reflection/v1alpha/reflection.proto is marked as deprecated. func (x *ErrorResponse) GetErrorMessage() string { if x != nil { return x.ErrorMessage @@ -660,136 +732,139 @@ func (x *ErrorResponse) GetErrorMessage() string { return "" } -var File_reflection_grpc_reflection_v1alpha_reflection_proto protoreflect.FileDescriptor - -var file_reflection_grpc_reflection_v1alpha_reflection_proto_rawDesc = []byte{ - 0x0a, 0x33, 0x72, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x67, 0x72, 0x70, - 0x63, 0x5f, 0x72, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x76, 0x31, 0x61, - 0x6c, 0x70, 0x68, 0x61, 0x2f, 0x72, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x17, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x72, 0x65, 0x66, 0x6c, - 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x22, 0xf8, - 0x02, 0x0a, 0x17, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, - 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x12, 0x2a, - 0x0a, 0x10, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x62, 0x79, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0e, 0x66, 0x69, 0x6c, 0x65, - 0x42, 0x79, 0x46, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x36, 0x0a, 0x16, 0x66, 0x69, - 0x6c, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x79, - 0x6d, 0x62, 0x6f, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x14, 0x66, 0x69, - 0x6c, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x53, 0x79, 0x6d, 0x62, - 0x6f, 0x6c, 0x12, 0x67, 0x0a, 0x19, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, - 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x72, 0x65, 0x66, - 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, - 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x48, 0x00, 0x52, 0x17, 0x66, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x69, - 0x6e, 0x67, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x42, 0x0a, 0x1d, 0x61, - 0x6c, 0x6c, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x75, 0x6d, - 0x62, 0x65, 0x72, 0x73, 0x5f, 0x6f, 0x66, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x09, 0x48, 0x00, 0x52, 0x19, 0x61, 0x6c, 0x6c, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, - 0x6f, 0x6e, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x4f, 0x66, 0x54, 0x79, 0x70, 0x65, 0x12, - 0x25, 0x0a, 0x0d, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, - 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0c, 0x6c, 0x69, 0x73, 0x74, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x42, 0x11, 0x0a, 0x0f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x66, 0x0a, 0x10, 0x45, 0x78, 0x74, - 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, - 0x0f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x79, 0x70, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x69, - 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, - 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x0f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x4e, 0x75, 0x6d, 0x62, 0x65, - 0x72, 0x22, 0xc7, 0x04, 0x0a, 0x18, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x66, 0x6c, - 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, - 0x0a, 0x0a, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x09, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x5b, 0x0a, - 0x10, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x72, - 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, - 0x61, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x0f, 0x6f, 0x72, 0x69, 0x67, 0x69, - 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6b, 0x0a, 0x18, 0x66, 0x69, - 0x6c, 0x65, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x5f, 0x72, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x67, +var File_grpc_reflection_v1alpha_reflection_proto protoreflect.FileDescriptor + +var file_grpc_reflection_v1alpha_reflection_proto_rawDesc = []byte{ + 0x0a, 0x28, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x72, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2f, 0x72, 0x65, 0x66, 0x6c, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x17, 0x67, 0x72, 0x70, 0x63, + 0x2e, 0x72, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x61, 0x6c, + 0x70, 0x68, 0x61, 0x22, 0xf8, 0x02, 0x0a, 0x17, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, + 0x66, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, + 0x6f, 0x73, 0x74, 0x12, 0x2a, 0x0a, 0x10, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x62, 0x79, 0x5f, 0x66, + 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, + 0x0e, 0x66, 0x69, 0x6c, 0x65, 0x42, 0x79, 0x46, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x36, 0x0a, 0x16, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x69, + 0x6e, 0x67, 0x5f, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, + 0x00, 0x52, 0x14, 0x66, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x69, 0x6e, + 0x67, 0x53, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x12, 0x67, 0x0a, 0x19, 0x66, 0x69, 0x6c, 0x65, 0x5f, + 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x6e, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x67, 0x72, 0x70, + 0x63, 0x2e, 0x72, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x61, + 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x17, 0x66, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, + 0x12, 0x42, 0x0a, 0x1d, 0x61, 0x6c, 0x6c, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, + 0x6e, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x5f, 0x6f, 0x66, 0x5f, 0x74, 0x79, 0x70, + 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x19, 0x61, 0x6c, 0x6c, 0x45, 0x78, + 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x4f, 0x66, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x25, 0x0a, 0x0d, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0c, 0x6c, + 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x42, 0x11, 0x0a, 0x0f, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x66, + 0x0a, 0x10, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, + 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x6f, 0x6e, + 0x74, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x65, + 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, + 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0xc7, 0x04, 0x0a, 0x18, 0x53, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x52, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x68, 0x6f, 0x73, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x48, 0x6f, + 0x73, 0x74, 0x12, 0x5b, 0x0a, 0x10, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x72, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, - 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, - 0x16, 0x66, 0x69, 0x6c, 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x77, 0x0a, 0x1e, 0x61, 0x6c, 0x6c, 0x5f, 0x65, - 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, - 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x30, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x72, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, - 0x69, 0x6f, 0x6e, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x48, 0x00, 0x52, 0x1b, 0x61, 0x6c, 0x6c, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, - 0x6e, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x64, 0x0a, 0x16, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x73, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x2c, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x72, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, - 0x52, 0x14, 0x6c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4f, 0x0a, 0x0e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, - 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, + 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x66, + 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x0f, + 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x6b, 0x0a, 0x18, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x6f, 0x72, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x2f, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x72, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x46, 0x69, 0x6c, 0x65, + 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x48, 0x00, 0x52, 0x16, 0x66, 0x69, 0x6c, 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x77, 0x0a, 0x1e, + 0x61, 0x6c, 0x6c, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x75, + 0x6d, 0x62, 0x65, 0x72, 0x73, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x72, 0x65, 0x66, 0x6c, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, + 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x1b, 0x61, 0x6c, 0x6c, 0x45, 0x78, 0x74, + 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x64, 0x0a, 0x16, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x72, 0x65, 0x66, + 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, + 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x14, 0x6c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4f, 0x0a, 0x0e, 0x65, + 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x72, 0x65, 0x66, 0x6c, 0x65, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, 0x72, + 0x72, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x0d, 0x65, + 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x12, 0x0a, 0x10, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x4c, 0x0a, 0x16, 0x46, 0x69, 0x6c, 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x15, 0x66, 0x69, + 0x6c, 0x65, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x5f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x13, 0x66, 0x69, 0x6c, 0x65, 0x44, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x6a, + 0x0a, 0x17, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x4e, 0x75, 0x6d, 0x62, 0x65, + 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x62, 0x61, 0x73, + 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0c, 0x62, 0x61, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, + 0x29, 0x0a, 0x10, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x75, 0x6d, + 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x05, 0x52, 0x0f, 0x65, 0x78, 0x74, 0x65, 0x6e, + 0x73, 0x69, 0x6f, 0x6e, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x59, 0x0a, 0x13, 0x4c, 0x69, + 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x42, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x72, 0x65, 0x66, 0x6c, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x07, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0x25, 0x0a, 0x0f, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x53, 0x0a, 0x0d, + 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, + 0x0a, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x09, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x23, 0x0a, 0x0d, + 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x32, 0x93, 0x01, 0x0a, 0x10, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x66, 0x6c, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x7f, 0x0a, 0x14, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x52, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x30, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x72, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x12, 0x0a, 0x10, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4c, 0x0a, 0x16, 0x46, - 0x69, 0x6c, 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x15, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x64, 0x65, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0c, 0x52, 0x13, 0x66, 0x69, 0x6c, 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x6a, 0x0a, 0x17, 0x45, 0x78, 0x74, - 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x74, 0x79, 0x70, - 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x62, 0x61, - 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x65, 0x78, - 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, - 0x20, 0x03, 0x28, 0x05, 0x52, 0x0f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x4e, - 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x59, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x42, 0x0a, 0x07, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, - 0x67, 0x72, 0x70, 0x63, 0x2e, 0x72, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, - 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x22, 0x25, 0x0a, 0x0f, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x53, 0x0a, 0x0d, 0x45, 0x72, 0x72, 0x6f, 0x72, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x72, 0x72, 0x6f, - 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x65, 0x72, - 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, - 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, - 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0x93, 0x01, 0x0a, - 0x10, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x7f, 0x0a, 0x14, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x66, 0x6c, 0x65, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x30, 0x2e, 0x67, 0x72, 0x70, 0x63, - 0x2e, 0x72, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x61, 0x6c, - 0x70, 0x68, 0x61, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x66, 0x6c, 0x65, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x67, 0x72, + 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, + 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x31, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x72, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x52, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 0x42, 0x73, 0x0a, 0x1a, 0x69, 0x6f, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x72, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, - 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x66, 0x6c, - 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, - 0x30, 0x01, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, - 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x72, 0x65, 0x66, - 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x5f, 0x72, 0x65, 0x66, - 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x61, 0x6c, 0x70, 0x68, 0x61, 0x42, 0x15, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x65, 0x66, + 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x39, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, + 0x67, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x72, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x5f, 0x72, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0xb8, 0x01, 0x01, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( - file_reflection_grpc_reflection_v1alpha_reflection_proto_rawDescOnce sync.Once - file_reflection_grpc_reflection_v1alpha_reflection_proto_rawDescData = file_reflection_grpc_reflection_v1alpha_reflection_proto_rawDesc + file_grpc_reflection_v1alpha_reflection_proto_rawDescOnce sync.Once + file_grpc_reflection_v1alpha_reflection_proto_rawDescData = file_grpc_reflection_v1alpha_reflection_proto_rawDesc ) -func file_reflection_grpc_reflection_v1alpha_reflection_proto_rawDescGZIP() []byte { - file_reflection_grpc_reflection_v1alpha_reflection_proto_rawDescOnce.Do(func() { - file_reflection_grpc_reflection_v1alpha_reflection_proto_rawDescData = protoimpl.X.CompressGZIP(file_reflection_grpc_reflection_v1alpha_reflection_proto_rawDescData) +func file_grpc_reflection_v1alpha_reflection_proto_rawDescGZIP() []byte { + file_grpc_reflection_v1alpha_reflection_proto_rawDescOnce.Do(func() { + file_grpc_reflection_v1alpha_reflection_proto_rawDescData = protoimpl.X.CompressGZIP(file_grpc_reflection_v1alpha_reflection_proto_rawDescData) }) - return file_reflection_grpc_reflection_v1alpha_reflection_proto_rawDescData + return file_grpc_reflection_v1alpha_reflection_proto_rawDescData } -var file_reflection_grpc_reflection_v1alpha_reflection_proto_msgTypes = make([]protoimpl.MessageInfo, 8) -var file_reflection_grpc_reflection_v1alpha_reflection_proto_goTypes = []interface{}{ +var file_grpc_reflection_v1alpha_reflection_proto_msgTypes = make([]protoimpl.MessageInfo, 8) +var file_grpc_reflection_v1alpha_reflection_proto_goTypes = []interface{}{ (*ServerReflectionRequest)(nil), // 0: grpc.reflection.v1alpha.ServerReflectionRequest (*ExtensionRequest)(nil), // 1: grpc.reflection.v1alpha.ExtensionRequest (*ServerReflectionResponse)(nil), // 2: grpc.reflection.v1alpha.ServerReflectionResponse @@ -799,7 +874,7 @@ var file_reflection_grpc_reflection_v1alpha_reflection_proto_goTypes = []interfa (*ServiceResponse)(nil), // 6: grpc.reflection.v1alpha.ServiceResponse (*ErrorResponse)(nil), // 7: grpc.reflection.v1alpha.ErrorResponse } -var file_reflection_grpc_reflection_v1alpha_reflection_proto_depIdxs = []int32{ +var file_grpc_reflection_v1alpha_reflection_proto_depIdxs = []int32{ 1, // 0: grpc.reflection.v1alpha.ServerReflectionRequest.file_containing_extension:type_name -> grpc.reflection.v1alpha.ExtensionRequest 0, // 1: grpc.reflection.v1alpha.ServerReflectionResponse.original_request:type_name -> grpc.reflection.v1alpha.ServerReflectionRequest 3, // 2: grpc.reflection.v1alpha.ServerReflectionResponse.file_descriptor_response:type_name -> grpc.reflection.v1alpha.FileDescriptorResponse @@ -816,13 +891,13 @@ var file_reflection_grpc_reflection_v1alpha_reflection_proto_depIdxs = []int32{ 0, // [0:7] is the sub-list for field type_name } -func init() { file_reflection_grpc_reflection_v1alpha_reflection_proto_init() } -func file_reflection_grpc_reflection_v1alpha_reflection_proto_init() { - if File_reflection_grpc_reflection_v1alpha_reflection_proto != nil { +func init() { file_grpc_reflection_v1alpha_reflection_proto_init() } +func file_grpc_reflection_v1alpha_reflection_proto_init() { + if File_grpc_reflection_v1alpha_reflection_proto != nil { return } if !protoimpl.UnsafeEnabled { - file_reflection_grpc_reflection_v1alpha_reflection_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_grpc_reflection_v1alpha_reflection_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ServerReflectionRequest); i { case 0: return &v.state @@ -834,7 +909,7 @@ func file_reflection_grpc_reflection_v1alpha_reflection_proto_init() { return nil } } - file_reflection_grpc_reflection_v1alpha_reflection_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_grpc_reflection_v1alpha_reflection_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ExtensionRequest); i { case 0: return &v.state @@ -846,7 +921,7 @@ func file_reflection_grpc_reflection_v1alpha_reflection_proto_init() { return nil } } - file_reflection_grpc_reflection_v1alpha_reflection_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_grpc_reflection_v1alpha_reflection_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ServerReflectionResponse); i { case 0: return &v.state @@ -858,7 +933,7 @@ func file_reflection_grpc_reflection_v1alpha_reflection_proto_init() { return nil } } - file_reflection_grpc_reflection_v1alpha_reflection_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_grpc_reflection_v1alpha_reflection_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*FileDescriptorResponse); i { case 0: return &v.state @@ -870,7 +945,7 @@ func file_reflection_grpc_reflection_v1alpha_reflection_proto_init() { return nil } } - file_reflection_grpc_reflection_v1alpha_reflection_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_grpc_reflection_v1alpha_reflection_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ExtensionNumberResponse); i { case 0: return &v.state @@ -882,7 +957,7 @@ func file_reflection_grpc_reflection_v1alpha_reflection_proto_init() { return nil } } - file_reflection_grpc_reflection_v1alpha_reflection_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_grpc_reflection_v1alpha_reflection_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ListServiceResponse); i { case 0: return &v.state @@ -894,7 +969,7 @@ func file_reflection_grpc_reflection_v1alpha_reflection_proto_init() { return nil } } - file_reflection_grpc_reflection_v1alpha_reflection_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_grpc_reflection_v1alpha_reflection_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ServiceResponse); i { case 0: return &v.state @@ -906,7 +981,7 @@ func file_reflection_grpc_reflection_v1alpha_reflection_proto_init() { return nil } } - file_reflection_grpc_reflection_v1alpha_reflection_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_grpc_reflection_v1alpha_reflection_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ErrorResponse); i { case 0: return &v.state @@ -919,14 +994,14 @@ func file_reflection_grpc_reflection_v1alpha_reflection_proto_init() { } } } - file_reflection_grpc_reflection_v1alpha_reflection_proto_msgTypes[0].OneofWrappers = []interface{}{ + file_grpc_reflection_v1alpha_reflection_proto_msgTypes[0].OneofWrappers = []interface{}{ (*ServerReflectionRequest_FileByFilename)(nil), (*ServerReflectionRequest_FileContainingSymbol)(nil), (*ServerReflectionRequest_FileContainingExtension)(nil), (*ServerReflectionRequest_AllExtensionNumbersOfType)(nil), (*ServerReflectionRequest_ListServices)(nil), } - file_reflection_grpc_reflection_v1alpha_reflection_proto_msgTypes[2].OneofWrappers = []interface{}{ + file_grpc_reflection_v1alpha_reflection_proto_msgTypes[2].OneofWrappers = []interface{}{ (*ServerReflectionResponse_FileDescriptorResponse)(nil), (*ServerReflectionResponse_AllExtensionNumbersResponse)(nil), (*ServerReflectionResponse_ListServicesResponse)(nil), @@ -936,18 +1011,18 @@ func file_reflection_grpc_reflection_v1alpha_reflection_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_reflection_grpc_reflection_v1alpha_reflection_proto_rawDesc, + RawDescriptor: file_grpc_reflection_v1alpha_reflection_proto_rawDesc, NumEnums: 0, NumMessages: 8, NumExtensions: 0, NumServices: 1, }, - GoTypes: file_reflection_grpc_reflection_v1alpha_reflection_proto_goTypes, - DependencyIndexes: file_reflection_grpc_reflection_v1alpha_reflection_proto_depIdxs, - MessageInfos: file_reflection_grpc_reflection_v1alpha_reflection_proto_msgTypes, + GoTypes: file_grpc_reflection_v1alpha_reflection_proto_goTypes, + DependencyIndexes: file_grpc_reflection_v1alpha_reflection_proto_depIdxs, + MessageInfos: file_grpc_reflection_v1alpha_reflection_proto_msgTypes, }.Build() - File_reflection_grpc_reflection_v1alpha_reflection_proto = out.File - file_reflection_grpc_reflection_v1alpha_reflection_proto_rawDesc = nil - file_reflection_grpc_reflection_v1alpha_reflection_proto_goTypes = nil - file_reflection_grpc_reflection_v1alpha_reflection_proto_depIdxs = nil + File_grpc_reflection_v1alpha_reflection_proto = out.File + file_grpc_reflection_v1alpha_reflection_proto_rawDesc = nil + file_grpc_reflection_v1alpha_reflection_proto_goTypes = nil + file_grpc_reflection_v1alpha_reflection_proto_depIdxs = nil } diff --git a/vendor/google.golang.org/grpc/reflection/grpc_reflection_v1alpha/reflection.proto b/vendor/google.golang.org/grpc/reflection/grpc_reflection_v1alpha/reflection.proto deleted file mode 100644 index ee2b82c0a5b..00000000000 --- a/vendor/google.golang.org/grpc/reflection/grpc_reflection_v1alpha/reflection.proto +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright 2016 gRPC authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Service exported by server reflection - -syntax = "proto3"; - -option go_package = "google.golang.org/grpc/reflection/grpc_reflection_v1alpha"; - -package grpc.reflection.v1alpha; - -service ServerReflection { - // The reflection service is structured as a bidirectional stream, ensuring - // all related requests go to a single server. - rpc ServerReflectionInfo(stream ServerReflectionRequest) - returns (stream ServerReflectionResponse); -} - -// The message sent by the client when calling ServerReflectionInfo method. -message ServerReflectionRequest { - string host = 1; - // To use reflection service, the client should set one of the following - // fields in message_request. The server distinguishes requests by their - // defined field and then handles them using corresponding methods. - oneof message_request { - // Find a proto file by the file name. - string file_by_filename = 3; - - // Find the proto file that declares the given fully-qualified symbol name. - // This field should be a fully-qualified symbol name - // (e.g. .[.] or .). - string file_containing_symbol = 4; - - // Find the proto file which defines an extension extending the given - // message type with the given field number. - ExtensionRequest file_containing_extension = 5; - - // Finds the tag numbers used by all known extensions of extendee_type, and - // appends them to ExtensionNumberResponse in an undefined order. - // Its corresponding method is best-effort: it's not guaranteed that the - // reflection service will implement this method, and it's not guaranteed - // that this method will provide all extensions. Returns - // StatusCode::UNIMPLEMENTED if it's not implemented. - // This field should be a fully-qualified type name. The format is - // . - string all_extension_numbers_of_type = 6; - - // List the full names of registered services. The content will not be - // checked. - string list_services = 7; - } -} - -// The type name and extension number sent by the client when requesting -// file_containing_extension. -message ExtensionRequest { - // Fully-qualified type name. The format should be . - string containing_type = 1; - int32 extension_number = 2; -} - -// The message sent by the server to answer ServerReflectionInfo method. -message ServerReflectionResponse { - string valid_host = 1; - ServerReflectionRequest original_request = 2; - // The server sets one of the following fields according to the - // message_request in the request. - oneof message_response { - // This message is used to answer file_by_filename, file_containing_symbol, - // file_containing_extension requests with transitive dependencies. - // As the repeated label is not allowed in oneof fields, we use a - // FileDescriptorResponse message to encapsulate the repeated fields. - // The reflection service is allowed to avoid sending FileDescriptorProtos - // that were previously sent in response to earlier requests in the stream. - FileDescriptorResponse file_descriptor_response = 4; - - // This message is used to answer all_extension_numbers_of_type requests. - ExtensionNumberResponse all_extension_numbers_response = 5; - - // This message is used to answer list_services requests. - ListServiceResponse list_services_response = 6; - - // This message is used when an error occurs. - ErrorResponse error_response = 7; - } -} - -// Serialized FileDescriptorProto messages sent by the server answering -// a file_by_filename, file_containing_symbol, or file_containing_extension -// request. -message FileDescriptorResponse { - // Serialized FileDescriptorProto messages. We avoid taking a dependency on - // descriptor.proto, which uses proto2 only features, by making them opaque - // bytes instead. - repeated bytes file_descriptor_proto = 1; -} - -// A list of extension numbers sent by the server answering -// all_extension_numbers_of_type request. -message ExtensionNumberResponse { - // Full name of the base type, including the package name. The format - // is . - string base_type_name = 1; - repeated int32 extension_number = 2; -} - -// A list of ServiceResponse sent by the server answering list_services request. -message ListServiceResponse { - // The information of each service may be expanded in the future, so we use - // ServiceResponse message to encapsulate it. - repeated ServiceResponse service = 1; -} - -// The information of a single service used by ListServiceResponse to answer -// list_services request. -message ServiceResponse { - // Full name of a registered service, including its package name. The format - // is . - string name = 1; -} - -// The error code and error message sent by the server when an error occurs. -message ErrorResponse { - // This field uses the error codes defined in grpc::StatusCode. - int32 error_code = 1; - string error_message = 2; -} diff --git a/vendor/google.golang.org/grpc/reflection/grpc_reflection_v1alpha/reflection_grpc.pb.go b/vendor/google.golang.org/grpc/reflection/grpc_reflection_v1alpha/reflection_grpc.pb.go index c2b7429a06b..367a029be6b 100644 --- a/vendor/google.golang.org/grpc/reflection/grpc_reflection_v1alpha/reflection_grpc.pb.go +++ b/vendor/google.golang.org/grpc/reflection/grpc_reflection_v1alpha/reflection_grpc.pb.go @@ -1,4 +1,26 @@ +// Copyright 2016 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// Service exported by server reflection + +// Warning: this entire file is deprecated. Use this instead: +// https://github.com/grpc/grpc-proto/blob/master/grpc/reflection/v1/reflection.proto + // Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.3.0 +// - protoc v4.22.0 +// grpc/reflection/v1alpha/reflection.proto is a deprecated file. package grpc_reflection_v1alpha @@ -14,6 +36,10 @@ import ( // Requires gRPC-Go v1.32.0 or later. const _ = grpc.SupportPackageIsVersion7 +const ( + ServerReflection_ServerReflectionInfo_FullMethodName = "/grpc.reflection.v1alpha.ServerReflection/ServerReflectionInfo" +) + // ServerReflectionClient is the client API for ServerReflection service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. @@ -32,7 +58,7 @@ func NewServerReflectionClient(cc grpc.ClientConnInterface) ServerReflectionClie } func (c *serverReflectionClient) ServerReflectionInfo(ctx context.Context, opts ...grpc.CallOption) (ServerReflection_ServerReflectionInfoClient, error) { - stream, err := c.cc.NewStream(ctx, &ServerReflection_ServiceDesc.Streams[0], "/grpc.reflection.v1alpha.ServerReflection/ServerReflectionInfo", opts...) + stream, err := c.cc.NewStream(ctx, &ServerReflection_ServiceDesc.Streams[0], ServerReflection_ServerReflectionInfo_FullMethodName, opts...) if err != nil { return nil, err } @@ -131,5 +157,5 @@ var ServerReflection_ServiceDesc = grpc.ServiceDesc{ ClientStreams: true, }, }, - Metadata: "reflection/grpc_reflection_v1alpha/reflection.proto", + Metadata: "grpc/reflection/v1alpha/reflection.proto", } diff --git a/vendor/google.golang.org/grpc/reflection/serverreflection.go b/vendor/google.golang.org/grpc/reflection/serverreflection.go index d2696168b10..e2f9ebfbbce 100644 --- a/vendor/google.golang.org/grpc/reflection/serverreflection.go +++ b/vendor/google.golang.org/grpc/reflection/serverreflection.go @@ -23,6 +23,7 @@ The service implemented is defined in: https://github.com/grpc/grpc/blob/master/src/proto/grpc/reflection/v1alpha/reflection.proto. To register server reflection on a gRPC server: + import "google.golang.org/grpc/reflection" s := grpc.NewServer() @@ -32,360 +33,202 @@ To register server reflection on a gRPC server: reflection.Register(s) s.Serve(lis) - */ package reflection // import "google.golang.org/grpc/reflection" import ( - "bytes" - "compress/gzip" - "fmt" "io" - "io/ioutil" - "reflect" "sort" - "sync" - "github.com/golang/protobuf/proto" - dpb "github.com/golang/protobuf/protoc-gen-go/descriptor" "google.golang.org/grpc" "google.golang.org/grpc/codes" - rpb "google.golang.org/grpc/reflection/grpc_reflection_v1alpha" "google.golang.org/grpc/status" -) - -type serverReflectionServer struct { - rpb.UnimplementedServerReflectionServer - s *grpc.Server - - initSymbols sync.Once - serviceNames []string - symbols map[string]*dpb.FileDescriptorProto // map of fully-qualified names to files -} - -// Register registers the server reflection service on the given gRPC server. -func Register(s *grpc.Server) { - rpb.RegisterServerReflectionServer(s, &serverReflectionServer{ - s: s, - }) -} - -// protoMessage is used for type assertion on proto messages. -// Generated proto message implements function Descriptor(), but Descriptor() -// is not part of interface proto.Message. This interface is needed to -// call Descriptor(). -type protoMessage interface { - Descriptor() ([]byte, []int) -} - -func (s *serverReflectionServer) getSymbols() (svcNames []string, symbolIndex map[string]*dpb.FileDescriptorProto) { - s.initSymbols.Do(func() { - serviceInfo := s.s.GetServiceInfo() - - s.symbols = map[string]*dpb.FileDescriptorProto{} - s.serviceNames = make([]string, 0, len(serviceInfo)) - processed := map[string]struct{}{} - for svc, info := range serviceInfo { - s.serviceNames = append(s.serviceNames, svc) - fdenc, ok := parseMetadata(info.Metadata) - if !ok { - continue - } - fd, err := decodeFileDesc(fdenc) - if err != nil { - continue - } - s.processFile(fd, processed) - } - sort.Strings(s.serviceNames) - }) - - return s.serviceNames, s.symbols -} - -func (s *serverReflectionServer) processFile(fd *dpb.FileDescriptorProto, processed map[string]struct{}) { - filename := fd.GetName() - if _, ok := processed[filename]; ok { - return - } - processed[filename] = struct{}{} - - prefix := fd.GetPackage() - - for _, msg := range fd.MessageType { - s.processMessage(fd, prefix, msg) - } - for _, en := range fd.EnumType { - s.processEnum(fd, prefix, en) - } - for _, ext := range fd.Extension { - s.processField(fd, prefix, ext) - } - for _, svc := range fd.Service { - svcName := fqn(prefix, svc.GetName()) - s.symbols[svcName] = fd - for _, meth := range svc.Method { - name := fqn(svcName, meth.GetName()) - s.symbols[name] = fd - } - } - - for _, dep := range fd.Dependency { - fdenc := proto.FileDescriptor(dep) - fdDep, err := decodeFileDesc(fdenc) - if err != nil { - continue - } - s.processFile(fdDep, processed) - } -} - -func (s *serverReflectionServer) processMessage(fd *dpb.FileDescriptorProto, prefix string, msg *dpb.DescriptorProto) { - msgName := fqn(prefix, msg.GetName()) - s.symbols[msgName] = fd - - for _, nested := range msg.NestedType { - s.processMessage(fd, msgName, nested) - } - for _, en := range msg.EnumType { - s.processEnum(fd, msgName, en) - } - for _, ext := range msg.Extension { - s.processField(fd, msgName, ext) - } - for _, fld := range msg.Field { - s.processField(fd, msgName, fld) - } - for _, oneof := range msg.OneofDecl { - oneofName := fqn(msgName, oneof.GetName()) - s.symbols[oneofName] = fd - } -} + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protodesc" + "google.golang.org/protobuf/reflect/protoreflect" + "google.golang.org/protobuf/reflect/protoregistry" -func (s *serverReflectionServer) processEnum(fd *dpb.FileDescriptorProto, prefix string, en *dpb.EnumDescriptorProto) { - enName := fqn(prefix, en.GetName()) - s.symbols[enName] = fd - - for _, val := range en.Value { - valName := fqn(enName, val.GetName()) - s.symbols[valName] = fd - } -} - -func (s *serverReflectionServer) processField(fd *dpb.FileDescriptorProto, prefix string, fld *dpb.FieldDescriptorProto) { - fldName := fqn(prefix, fld.GetName()) - s.symbols[fldName] = fd -} + v1alphagrpc "google.golang.org/grpc/reflection/grpc_reflection_v1alpha" + v1alphapb "google.golang.org/grpc/reflection/grpc_reflection_v1alpha" +) -func fqn(prefix, name string) string { - if prefix == "" { - return name - } - return prefix + "." + name +// GRPCServer is the interface provided by a gRPC server. It is implemented by +// *grpc.Server, but could also be implemented by other concrete types. It acts +// as a registry, for accumulating the services exposed by the server. +type GRPCServer interface { + grpc.ServiceRegistrar + ServiceInfoProvider } -// fileDescForType gets the file descriptor for the given type. -// The given type should be a proto message. -func (s *serverReflectionServer) fileDescForType(st reflect.Type) (*dpb.FileDescriptorProto, error) { - m, ok := reflect.Zero(reflect.PtrTo(st)).Interface().(protoMessage) - if !ok { - return nil, fmt.Errorf("failed to create message from type: %v", st) - } - enc, _ := m.Descriptor() +var _ GRPCServer = (*grpc.Server)(nil) - return decodeFileDesc(enc) +// Register registers the server reflection service on the given gRPC server. +func Register(s GRPCServer) { + svr := NewServer(ServerOptions{Services: s}) + v1alphagrpc.RegisterServerReflectionServer(s, svr) } -// decodeFileDesc does decompression and unmarshalling on the given -// file descriptor byte slice. -func decodeFileDesc(enc []byte) (*dpb.FileDescriptorProto, error) { - raw, err := decompress(enc) - if err != nil { - return nil, fmt.Errorf("failed to decompress enc: %v", err) - } - - fd := new(dpb.FileDescriptorProto) - if err := proto.Unmarshal(raw, fd); err != nil { - return nil, fmt.Errorf("bad descriptor: %v", err) - } - return fd, nil +// ServiceInfoProvider is an interface used to retrieve metadata about the +// services to expose. +// +// The reflection service is only interested in the service names, but the +// signature is this way so that *grpc.Server implements it. So it is okay +// for a custom implementation to return zero values for the +// grpc.ServiceInfo values in the map. +// +// # Experimental +// +// Notice: This type is EXPERIMENTAL and may be changed or removed in a +// later release. +type ServiceInfoProvider interface { + GetServiceInfo() map[string]grpc.ServiceInfo } -// decompress does gzip decompression. -func decompress(b []byte) ([]byte, error) { - r, err := gzip.NewReader(bytes.NewReader(b)) - if err != nil { - return nil, fmt.Errorf("bad gzipped descriptor: %v", err) - } - out, err := ioutil.ReadAll(r) - if err != nil { - return nil, fmt.Errorf("bad gzipped descriptor: %v", err) - } - return out, nil +// ExtensionResolver is the interface used to query details about extensions. +// This interface is satisfied by protoregistry.GlobalTypes. +// +// # Experimental +// +// Notice: This type is EXPERIMENTAL and may be changed or removed in a +// later release. +type ExtensionResolver interface { + protoregistry.ExtensionTypeResolver + RangeExtensionsByMessage(message protoreflect.FullName, f func(protoreflect.ExtensionType) bool) } -func typeForName(name string) (reflect.Type, error) { - pt := proto.MessageType(name) - if pt == nil { - return nil, fmt.Errorf("unknown type: %q", name) - } - st := pt.Elem() - - return st, nil +// ServerOptions represents the options used to construct a reflection server. +// +// # Experimental +// +// Notice: This type is EXPERIMENTAL and may be changed or removed in a +// later release. +type ServerOptions struct { + // The source of advertised RPC services. If not specified, the reflection + // server will report an empty list when asked to list services. + // + // This value will typically be a *grpc.Server. But the set of advertised + // services can be customized by wrapping a *grpc.Server or using an + // alternate implementation that returns a custom set of service names. + Services ServiceInfoProvider + // Optional resolver used to load descriptors. If not specified, + // protoregistry.GlobalFiles will be used. + DescriptorResolver protodesc.Resolver + // Optional resolver used to query for known extensions. If not specified, + // protoregistry.GlobalTypes will be used. + ExtensionResolver ExtensionResolver } -func fileDescContainingExtension(st reflect.Type, ext int32) (*dpb.FileDescriptorProto, error) { - m, ok := reflect.Zero(reflect.PtrTo(st)).Interface().(proto.Message) - if !ok { - return nil, fmt.Errorf("failed to create message from type: %v", st) +// NewServer returns a reflection server implementation using the given options. +// This can be used to customize behavior of the reflection service. Most usages +// should prefer to use Register instead. +// +// # Experimental +// +// Notice: This function is EXPERIMENTAL and may be changed or removed in a +// later release. +func NewServer(opts ServerOptions) v1alphagrpc.ServerReflectionServer { + if opts.DescriptorResolver == nil { + opts.DescriptorResolver = protoregistry.GlobalFiles + } + if opts.ExtensionResolver == nil { + opts.ExtensionResolver = protoregistry.GlobalTypes + } + return &serverReflectionServer{ + s: opts.Services, + descResolver: opts.DescriptorResolver, + extResolver: opts.ExtensionResolver, } - - var extDesc *proto.ExtensionDesc - for id, desc := range proto.RegisteredExtensions(m) { - if id == ext { - extDesc = desc - break - } - } - - if extDesc == nil { - return nil, fmt.Errorf("failed to find registered extension for extension number %v", ext) - } - - return decodeFileDesc(proto.FileDescriptor(extDesc.Filename)) } -func (s *serverReflectionServer) allExtensionNumbersForType(st reflect.Type) ([]int32, error) { - m, ok := reflect.Zero(reflect.PtrTo(st)).Interface().(proto.Message) - if !ok { - return nil, fmt.Errorf("failed to create message from type: %v", st) - } - - exts := proto.RegisteredExtensions(m) - out := make([]int32, 0, len(exts)) - for id := range exts { - out = append(out, id) - } - return out, nil +type serverReflectionServer struct { + v1alphagrpc.UnimplementedServerReflectionServer + s ServiceInfoProvider + descResolver protodesc.Resolver + extResolver ExtensionResolver } // fileDescWithDependencies returns a slice of serialized fileDescriptors in // wire format ([]byte). The fileDescriptors will include fd and all the // transitive dependencies of fd with names not in sentFileDescriptors. -func fileDescWithDependencies(fd *dpb.FileDescriptorProto, sentFileDescriptors map[string]bool) ([][]byte, error) { - r := [][]byte{} - queue := []*dpb.FileDescriptorProto{fd} +func (s *serverReflectionServer) fileDescWithDependencies(fd protoreflect.FileDescriptor, sentFileDescriptors map[string]bool) ([][]byte, error) { + var r [][]byte + queue := []protoreflect.FileDescriptor{fd} for len(queue) > 0 { currentfd := queue[0] queue = queue[1:] - if sent := sentFileDescriptors[currentfd.GetName()]; len(r) == 0 || !sent { - sentFileDescriptors[currentfd.GetName()] = true - currentfdEncoded, err := proto.Marshal(currentfd) + if sent := sentFileDescriptors[currentfd.Path()]; len(r) == 0 || !sent { + sentFileDescriptors[currentfd.Path()] = true + fdProto := protodesc.ToFileDescriptorProto(currentfd) + currentfdEncoded, err := proto.Marshal(fdProto) if err != nil { return nil, err } r = append(r, currentfdEncoded) } - for _, dep := range currentfd.Dependency { - fdenc := proto.FileDescriptor(dep) - fdDep, err := decodeFileDesc(fdenc) - if err != nil { - continue - } - queue = append(queue, fdDep) + for i := 0; i < currentfd.Imports().Len(); i++ { + queue = append(queue, currentfd.Imports().Get(i)) } } return r, nil } -// fileDescEncodingByFilename finds the file descriptor for given filename, -// finds all of its previously unsent transitive dependencies, does marshalling -// on them, and returns the marshalled result. -func (s *serverReflectionServer) fileDescEncodingByFilename(name string, sentFileDescriptors map[string]bool) ([][]byte, error) { - enc := proto.FileDescriptor(name) - if enc == nil { - return nil, fmt.Errorf("unknown file: %v", name) - } - fd, err := decodeFileDesc(enc) - if err != nil { - return nil, err - } - return fileDescWithDependencies(fd, sentFileDescriptors) -} - -// parseMetadata finds the file descriptor bytes specified meta. -// For SupportPackageIsVersion4, m is the name of the proto file, we -// call proto.FileDescriptor to get the byte slice. -// For SupportPackageIsVersion3, m is a byte slice itself. -func parseMetadata(meta interface{}) ([]byte, bool) { - // Check if meta is the file name. - if fileNameForMeta, ok := meta.(string); ok { - return proto.FileDescriptor(fileNameForMeta), true - } - - // Check if meta is the byte slice. - if enc, ok := meta.([]byte); ok { - return enc, true - } - - return nil, false -} - // fileDescEncodingContainingSymbol finds the file descriptor containing the // given symbol, finds all of its previously unsent transitive dependencies, // does marshalling on them, and returns the marshalled result. The given symbol // can be a type, a service or a method. func (s *serverReflectionServer) fileDescEncodingContainingSymbol(name string, sentFileDescriptors map[string]bool) ([][]byte, error) { - _, symbols := s.getSymbols() - fd := symbols[name] - if fd == nil { - // Check if it's a type name that was not present in the - // transitive dependencies of the registered services. - if st, err := typeForName(name); err == nil { - fd, err = s.fileDescForType(st) - if err != nil { - return nil, err - } - } - } - - if fd == nil { - return nil, fmt.Errorf("unknown symbol: %v", name) + d, err := s.descResolver.FindDescriptorByName(protoreflect.FullName(name)) + if err != nil { + return nil, err } - - return fileDescWithDependencies(fd, sentFileDescriptors) + return s.fileDescWithDependencies(d.ParentFile(), sentFileDescriptors) } // fileDescEncodingContainingExtension finds the file descriptor containing // given extension, finds all of its previously unsent transitive dependencies, // does marshalling on them, and returns the marshalled result. func (s *serverReflectionServer) fileDescEncodingContainingExtension(typeName string, extNum int32, sentFileDescriptors map[string]bool) ([][]byte, error) { - st, err := typeForName(typeName) - if err != nil { - return nil, err - } - fd, err := fileDescContainingExtension(st, extNum) + xt, err := s.extResolver.FindExtensionByNumber(protoreflect.FullName(typeName), protoreflect.FieldNumber(extNum)) if err != nil { return nil, err } - return fileDescWithDependencies(fd, sentFileDescriptors) + return s.fileDescWithDependencies(xt.TypeDescriptor().ParentFile(), sentFileDescriptors) } // allExtensionNumbersForTypeName returns all extension numbers for the given type. func (s *serverReflectionServer) allExtensionNumbersForTypeName(name string) ([]int32, error) { - st, err := typeForName(name) - if err != nil { - return nil, err + var numbers []int32 + s.extResolver.RangeExtensionsByMessage(protoreflect.FullName(name), func(xt protoreflect.ExtensionType) bool { + numbers = append(numbers, int32(xt.TypeDescriptor().Number())) + return true + }) + sort.Slice(numbers, func(i, j int) bool { + return numbers[i] < numbers[j] + }) + if len(numbers) == 0 { + // maybe return an error if given type name is not known + if _, err := s.descResolver.FindDescriptorByName(protoreflect.FullName(name)); err != nil { + return nil, err + } } - extNums, err := s.allExtensionNumbersForType(st) - if err != nil { - return nil, err + return numbers, nil +} + +// listServices returns the names of services this server exposes. +func (s *serverReflectionServer) listServices() []*v1alphapb.ServiceResponse { + serviceInfo := s.s.GetServiceInfo() + resp := make([]*v1alphapb.ServiceResponse, 0, len(serviceInfo)) + for svc := range serviceInfo { + resp = append(resp, &v1alphapb.ServiceResponse{Name: svc}) } - return extNums, nil + sort.Slice(resp, func(i, j int) bool { + return resp[i].Name < resp[j].Name + }) + return resp } // ServerReflectionInfo is the reflection service handler. -func (s *serverReflectionServer) ServerReflectionInfo(stream rpb.ServerReflection_ServerReflectionInfoServer) error { +func (s *serverReflectionServer) ServerReflectionInfo(stream v1alphagrpc.ServerReflection_ServerReflectionInfoServer) error { sentFileDescriptors := make(map[string]bool) for { in, err := stream.Recv() @@ -396,83 +239,80 @@ func (s *serverReflectionServer) ServerReflectionInfo(stream rpb.ServerReflectio return err } - out := &rpb.ServerReflectionResponse{ + out := &v1alphapb.ServerReflectionResponse{ ValidHost: in.Host, OriginalRequest: in, } switch req := in.MessageRequest.(type) { - case *rpb.ServerReflectionRequest_FileByFilename: - b, err := s.fileDescEncodingByFilename(req.FileByFilename, sentFileDescriptors) + case *v1alphapb.ServerReflectionRequest_FileByFilename: + var b [][]byte + fd, err := s.descResolver.FindFileByPath(req.FileByFilename) + if err == nil { + b, err = s.fileDescWithDependencies(fd, sentFileDescriptors) + } if err != nil { - out.MessageResponse = &rpb.ServerReflectionResponse_ErrorResponse{ - ErrorResponse: &rpb.ErrorResponse{ + out.MessageResponse = &v1alphapb.ServerReflectionResponse_ErrorResponse{ + ErrorResponse: &v1alphapb.ErrorResponse{ ErrorCode: int32(codes.NotFound), ErrorMessage: err.Error(), }, } } else { - out.MessageResponse = &rpb.ServerReflectionResponse_FileDescriptorResponse{ - FileDescriptorResponse: &rpb.FileDescriptorResponse{FileDescriptorProto: b}, + out.MessageResponse = &v1alphapb.ServerReflectionResponse_FileDescriptorResponse{ + FileDescriptorResponse: &v1alphapb.FileDescriptorResponse{FileDescriptorProto: b}, } } - case *rpb.ServerReflectionRequest_FileContainingSymbol: + case *v1alphapb.ServerReflectionRequest_FileContainingSymbol: b, err := s.fileDescEncodingContainingSymbol(req.FileContainingSymbol, sentFileDescriptors) if err != nil { - out.MessageResponse = &rpb.ServerReflectionResponse_ErrorResponse{ - ErrorResponse: &rpb.ErrorResponse{ + out.MessageResponse = &v1alphapb.ServerReflectionResponse_ErrorResponse{ + ErrorResponse: &v1alphapb.ErrorResponse{ ErrorCode: int32(codes.NotFound), ErrorMessage: err.Error(), }, } } else { - out.MessageResponse = &rpb.ServerReflectionResponse_FileDescriptorResponse{ - FileDescriptorResponse: &rpb.FileDescriptorResponse{FileDescriptorProto: b}, + out.MessageResponse = &v1alphapb.ServerReflectionResponse_FileDescriptorResponse{ + FileDescriptorResponse: &v1alphapb.FileDescriptorResponse{FileDescriptorProto: b}, } } - case *rpb.ServerReflectionRequest_FileContainingExtension: + case *v1alphapb.ServerReflectionRequest_FileContainingExtension: typeName := req.FileContainingExtension.ContainingType extNum := req.FileContainingExtension.ExtensionNumber b, err := s.fileDescEncodingContainingExtension(typeName, extNum, sentFileDescriptors) if err != nil { - out.MessageResponse = &rpb.ServerReflectionResponse_ErrorResponse{ - ErrorResponse: &rpb.ErrorResponse{ + out.MessageResponse = &v1alphapb.ServerReflectionResponse_ErrorResponse{ + ErrorResponse: &v1alphapb.ErrorResponse{ ErrorCode: int32(codes.NotFound), ErrorMessage: err.Error(), }, } } else { - out.MessageResponse = &rpb.ServerReflectionResponse_FileDescriptorResponse{ - FileDescriptorResponse: &rpb.FileDescriptorResponse{FileDescriptorProto: b}, + out.MessageResponse = &v1alphapb.ServerReflectionResponse_FileDescriptorResponse{ + FileDescriptorResponse: &v1alphapb.FileDescriptorResponse{FileDescriptorProto: b}, } } - case *rpb.ServerReflectionRequest_AllExtensionNumbersOfType: + case *v1alphapb.ServerReflectionRequest_AllExtensionNumbersOfType: extNums, err := s.allExtensionNumbersForTypeName(req.AllExtensionNumbersOfType) if err != nil { - out.MessageResponse = &rpb.ServerReflectionResponse_ErrorResponse{ - ErrorResponse: &rpb.ErrorResponse{ + out.MessageResponse = &v1alphapb.ServerReflectionResponse_ErrorResponse{ + ErrorResponse: &v1alphapb.ErrorResponse{ ErrorCode: int32(codes.NotFound), ErrorMessage: err.Error(), }, } } else { - out.MessageResponse = &rpb.ServerReflectionResponse_AllExtensionNumbersResponse{ - AllExtensionNumbersResponse: &rpb.ExtensionNumberResponse{ + out.MessageResponse = &v1alphapb.ServerReflectionResponse_AllExtensionNumbersResponse{ + AllExtensionNumbersResponse: &v1alphapb.ExtensionNumberResponse{ BaseTypeName: req.AllExtensionNumbersOfType, ExtensionNumber: extNums, }, } } - case *rpb.ServerReflectionRequest_ListServices: - svcNames, _ := s.getSymbols() - serviceResponses := make([]*rpb.ServiceResponse, len(svcNames)) - for i, n := range svcNames { - serviceResponses[i] = &rpb.ServiceResponse{ - Name: n, - } - } - out.MessageResponse = &rpb.ServerReflectionResponse_ListServicesResponse{ - ListServicesResponse: &rpb.ListServiceResponse{ - Service: serviceResponses, + case *v1alphapb.ServerReflectionRequest_ListServices: + out.MessageResponse = &v1alphapb.ServerReflectionResponse_ListServicesResponse{ + ListServicesResponse: &v1alphapb.ListServiceResponse{ + Service: s.listServices(), }, } default: diff --git a/vendor/google.golang.org/grpc/regenerate.sh b/vendor/google.golang.org/grpc/regenerate.sh index fc6725b89f8..a6f26c8ab0f 100644 --- a/vendor/google.golang.org/grpc/regenerate.sh +++ b/vendor/google.golang.org/grpc/regenerate.sh @@ -27,9 +27,9 @@ export PATH=${GOBIN}:${PATH} mkdir -p ${GOBIN} echo "remove existing generated files" -# grpc_testingv3/testv3.pb.go is not re-generated because it was -# intentionally generated by an older version of protoc-gen-go. -rm -f $(find . -name '*.pb.go' | grep -v 'grpc_testingv3/testv3.pb.go') +# grpc_testing_not_regenerate/*.pb.go is not re-generated, +# see grpc_testing_not_regenerate/README.md for details. +rm -f $(find . -name '*.pb.go' | grep -v 'grpc_testing_not_regenerate') echo "go install google.golang.org/protobuf/cmd/protoc-gen-go" (cd test/tools && go install google.golang.org/protobuf/cmd/protoc-gen-go) @@ -48,11 +48,6 @@ mkdir -p ${WORKDIR}/googleapis/google/rpc echo "curl https://raw.githubusercontent.com/googleapis/googleapis/master/google/rpc/code.proto" curl --silent https://raw.githubusercontent.com/googleapis/googleapis/master/google/rpc/code.proto > ${WORKDIR}/googleapis/google/rpc/code.proto -# Pull in the MeshCA service proto. -mkdir -p ${WORKDIR}/istio/istio/google/security/meshca/v1 -echo "curl https://raw.githubusercontent.com/istio/istio/master/security/proto/providers/google/meshca.proto" -curl --silent https://raw.githubusercontent.com/istio/istio/master/security/proto/providers/google/meshca.proto > ${WORKDIR}/istio/istio/google/security/meshca/v1/meshca.proto - mkdir -p ${WORKDIR}/out # Generates sources without the embed requirement @@ -62,7 +57,8 @@ LEGACY_SOURCES=( ${WORKDIR}/grpc-proto/grpc/health/v1/health.proto ${WORKDIR}/grpc-proto/grpc/lb/v1/load_balancer.proto profiling/proto/service.proto - reflection/grpc_reflection_v1alpha/reflection.proto + ${WORKDIR}/grpc-proto/grpc/reflection/v1alpha/reflection.proto + ${WORKDIR}/grpc-proto/grpc/reflection/v1/reflection.proto ) # Generates only the new gRPC Service symbols @@ -73,16 +69,27 @@ SOURCES=( ${WORKDIR}/grpc-proto/grpc/gcp/transport_security_common.proto ${WORKDIR}/grpc-proto/grpc/lookup/v1/rls.proto ${WORKDIR}/grpc-proto/grpc/lookup/v1/rls_config.proto - ${WORKDIR}/grpc-proto/grpc/service_config/service_config.proto ${WORKDIR}/grpc-proto/grpc/testing/*.proto ${WORKDIR}/grpc-proto/grpc/core/*.proto - ${WORKDIR}/istio/istio/google/security/meshca/v1/meshca.proto ) # These options of the form 'Mfoo.proto=bar' instruct the codegen to use an # import path of 'bar' in the generated code when 'foo.proto' is imported in # one of the sources. -OPTS=Mgrpc/service_config/service_config.proto=/internal/proto/grpc_service_config,Mgrpc/core/stats.proto=google.golang.org/grpc/interop/grpc_testing/core +# +# Note that the protos listed here are all for testing purposes. All protos to +# be used externally should have a go_package option (and they don't need to be +# listed here). +OPTS=Mgrpc/core/stats.proto=google.golang.org/grpc/interop/grpc_testing/core,\ +Mgrpc/testing/benchmark_service.proto=google.golang.org/grpc/interop/grpc_testing,\ +Mgrpc/testing/stats.proto=google.golang.org/grpc/interop/grpc_testing,\ +Mgrpc/testing/report_qps_scenario_service.proto=google.golang.org/grpc/interop/grpc_testing,\ +Mgrpc/testing/messages.proto=google.golang.org/grpc/interop/grpc_testing,\ +Mgrpc/testing/worker_service.proto=google.golang.org/grpc/interop/grpc_testing,\ +Mgrpc/testing/control.proto=google.golang.org/grpc/interop/grpc_testing,\ +Mgrpc/testing/test.proto=google.golang.org/grpc/interop/grpc_testing,\ +Mgrpc/testing/payloads.proto=google.golang.org/grpc/interop/grpc_testing,\ +Mgrpc/testing/empty.proto=google.golang.org/grpc/interop/grpc_testing for src in ${SOURCES[@]}; do echo "protoc ${src}" @@ -91,7 +98,6 @@ for src in ${SOURCES[@]}; do -I${WORKDIR}/grpc-proto \ -I${WORKDIR}/googleapis \ -I${WORKDIR}/protobuf/src \ - -I${WORKDIR}/istio \ ${src} done @@ -102,28 +108,16 @@ for src in ${LEGACY_SOURCES[@]}; do -I${WORKDIR}/grpc-proto \ -I${WORKDIR}/googleapis \ -I${WORKDIR}/protobuf/src \ - -I${WORKDIR}/istio \ ${src} done # The go_package option in grpc/lookup/v1/rls.proto doesn't match the # current location. Move it into the right place. -mkdir -p ${WORKDIR}/out/google.golang.org/grpc/balancer/rls/internal/proto/grpc_lookup_v1 -mv ${WORKDIR}/out/google.golang.org/grpc/lookup/grpc_lookup_v1/* ${WORKDIR}/out/google.golang.org/grpc/balancer/rls/internal/proto/grpc_lookup_v1 - -# grpc_testingv3/testv3.pb.go is not re-generated because it was -# intentionally generated by an older version of protoc-gen-go. -rm ${WORKDIR}/out/google.golang.org/grpc/reflection/grpc_testingv3/*.pb.go - -# grpc/service_config/service_config.proto does not have a go_package option. -mv ${WORKDIR}/out/grpc/service_config/service_config.pb.go internal/proto/grpc_service_config - -# grpc/testing does not have a go_package option. -mv ${WORKDIR}/out/grpc/testing/*.pb.go interop/grpc_testing/ -mv ${WORKDIR}/out/grpc/core/*.pb.go interop/grpc_testing/core/ +mkdir -p ${WORKDIR}/out/google.golang.org/grpc/internal/proto/grpc_lookup_v1 +mv ${WORKDIR}/out/google.golang.org/grpc/lookup/grpc_lookup_v1/* ${WORKDIR}/out/google.golang.org/grpc/internal/proto/grpc_lookup_v1 -# istio/google/security/meshca/v1/meshca.proto does not have a go_package option. -mkdir -p ${WORKDIR}/out/google.golang.org/grpc/credentials/tls/certprovider/meshca/internal/v1/ -mv ${WORKDIR}/out/istio/google/security/meshca/v1/* ${WORKDIR}/out/google.golang.org/grpc/credentials/tls/certprovider/meshca/internal/v1/ +# grpc_testing_not_regenerate/*.pb.go are not re-generated, +# see grpc_testing_not_regenerate/README.md for details. +rm ${WORKDIR}/out/google.golang.org/grpc/reflection/grpc_testing_not_regenerate/*.pb.go cp -R ${WORKDIR}/out/google.golang.org/grpc/* . diff --git a/vendor/google.golang.org/grpc/resolver/map.go b/vendor/google.golang.org/grpc/resolver/map.go new file mode 100644 index 00000000000..efcb7f3efd8 --- /dev/null +++ b/vendor/google.golang.org/grpc/resolver/map.go @@ -0,0 +1,138 @@ +/* + * + * Copyright 2021 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package resolver + +type addressMapEntry struct { + addr Address + value interface{} +} + +// AddressMap is a map of addresses to arbitrary values taking into account +// Attributes. BalancerAttributes are ignored, as are Metadata and Type. +// Multiple accesses may not be performed concurrently. Must be created via +// NewAddressMap; do not construct directly. +type AddressMap struct { + // The underlying map is keyed by an Address with fields that we don't care + // about being set to their zero values. The only fields that we care about + // are `Addr`, `ServerName` and `Attributes`. Since we need to be able to + // distinguish between addresses with same `Addr` and `ServerName`, but + // different `Attributes`, we cannot store the `Attributes` in the map key. + // + // The comparison operation for structs work as follows: + // Struct values are comparable if all their fields are comparable. Two + // struct values are equal if their corresponding non-blank fields are equal. + // + // The value type of the map contains a slice of addresses which match the key + // in their `Addr` and `ServerName` fields and contain the corresponding value + // associated with them. + m map[Address]addressMapEntryList +} + +func toMapKey(addr *Address) Address { + return Address{Addr: addr.Addr, ServerName: addr.ServerName} +} + +type addressMapEntryList []*addressMapEntry + +// NewAddressMap creates a new AddressMap. +func NewAddressMap() *AddressMap { + return &AddressMap{m: make(map[Address]addressMapEntryList)} +} + +// find returns the index of addr in the addressMapEntry slice, or -1 if not +// present. +func (l addressMapEntryList) find(addr Address) int { + for i, entry := range l { + // Attributes are the only thing to match on here, since `Addr` and + // `ServerName` are already equal. + if entry.addr.Attributes.Equal(addr.Attributes) { + return i + } + } + return -1 +} + +// Get returns the value for the address in the map, if present. +func (a *AddressMap) Get(addr Address) (value interface{}, ok bool) { + addrKey := toMapKey(&addr) + entryList := a.m[addrKey] + if entry := entryList.find(addr); entry != -1 { + return entryList[entry].value, true + } + return nil, false +} + +// Set updates or adds the value to the address in the map. +func (a *AddressMap) Set(addr Address, value interface{}) { + addrKey := toMapKey(&addr) + entryList := a.m[addrKey] + if entry := entryList.find(addr); entry != -1 { + entryList[entry].value = value + return + } + a.m[addrKey] = append(entryList, &addressMapEntry{addr: addr, value: value}) +} + +// Delete removes addr from the map. +func (a *AddressMap) Delete(addr Address) { + addrKey := toMapKey(&addr) + entryList := a.m[addrKey] + entry := entryList.find(addr) + if entry == -1 { + return + } + if len(entryList) == 1 { + entryList = nil + } else { + copy(entryList[entry:], entryList[entry+1:]) + entryList = entryList[:len(entryList)-1] + } + a.m[addrKey] = entryList +} + +// Len returns the number of entries in the map. +func (a *AddressMap) Len() int { + ret := 0 + for _, entryList := range a.m { + ret += len(entryList) + } + return ret +} + +// Keys returns a slice of all current map keys. +func (a *AddressMap) Keys() []Address { + ret := make([]Address, 0, a.Len()) + for _, entryList := range a.m { + for _, entry := range entryList { + ret = append(ret, entry.addr) + } + } + return ret +} + +// Values returns a slice of all current map values. +func (a *AddressMap) Values() []interface{} { + ret := make([]interface{}, 0, a.Len()) + for _, entryList := range a.m { + for _, entry := range entryList { + ret = append(ret, entry.value) + } + } + return ret +} diff --git a/vendor/google.golang.org/grpc/resolver/resolver.go b/vendor/google.golang.org/grpc/resolver/resolver.go index e9fa8e33d92..353c10b69a5 100644 --- a/vendor/google.golang.org/grpc/resolver/resolver.go +++ b/vendor/google.golang.org/grpc/resolver/resolver.go @@ -22,7 +22,10 @@ package resolver import ( "context" + "fmt" "net" + "net/url" + "strings" "google.golang.org/grpc/attributes" "google.golang.org/grpc/credentials" @@ -38,8 +41,9 @@ var ( // TODO(bar) install dns resolver in init(){}. -// Register registers the resolver builder to the resolver map. b.Scheme will be -// used as the scheme registered with this builder. +// Register registers the resolver builder to the resolver map. b.Scheme will +// be used as the scheme registered with this builder. The registry is case +// sensitive, and schemes should not contain any uppercase characters. // // NOTE: this function must only be called during initialization time (i.e. in // an init() function), and is not thread-safe. If multiple Resolvers are @@ -94,7 +98,7 @@ const ( // Address represents a server the client connects to. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. @@ -116,9 +120,14 @@ type Address struct { ServerName string // Attributes contains arbitrary data about this address intended for - // consumption by the load balancing policy. + // consumption by the SubConn. Attributes *attributes.Attributes + // BalancerAttributes contains arbitrary data about this address intended + // for consumption by the LB policy. These attributes do not affect SubConn + // creation, connection establishment, handshaking, etc. + BalancerAttributes *attributes.Attributes + // Type is the type of this address. // // Deprecated: use Attributes instead. @@ -131,6 +140,30 @@ type Address struct { Metadata interface{} } +// Equal returns whether a and o are identical. Metadata is compared directly, +// not with any recursive introspection. +func (a Address) Equal(o Address) bool { + return a.Addr == o.Addr && a.ServerName == o.ServerName && + a.Attributes.Equal(o.Attributes) && + a.BalancerAttributes.Equal(o.BalancerAttributes) && + a.Type == o.Type && a.Metadata == o.Metadata +} + +// String returns JSON formatted string representation of the address. +func (a Address) String() string { + var sb strings.Builder + sb.WriteString(fmt.Sprintf("{Addr: %q, ", a.Addr)) + sb.WriteString(fmt.Sprintf("ServerName: %q, ", a.ServerName)) + if a.Attributes != nil { + sb.WriteString(fmt.Sprintf("Attributes: %v, ", a.Attributes.String())) + } + if a.BalancerAttributes != nil { + sb.WriteString(fmt.Sprintf("BalancerAttributes: %v", a.BalancerAttributes.String())) + } + sb.WriteString("}") + return sb.String() +} + // BuildOptions includes additional information for the builder to create // the resolver. type BuildOptions struct { @@ -181,7 +214,16 @@ type State struct { // gRPC to add new methods to this interface. type ClientConn interface { // UpdateState updates the state of the ClientConn appropriately. - UpdateState(State) + // + // If an error is returned, the resolver should try to resolve the + // target again. The resolver should use a backoff timer to prevent + // overloading the server with requests. If a resolver is certain that + // reresolving will not change the result, e.g. because it is + // a watch-based resolver, returned errors can be ignored. + // + // If the resolved State is the same as the last reported one, calling + // UpdateState can be omitted. + UpdateState(State) error // ReportError notifies the ClientConn that the Resolver encountered an // error. The ClientConn will notify the load balancer and begin calling // ResolveNow on the Resolver with exponential backoff. @@ -204,25 +246,51 @@ type ClientConn interface { // Target represents a target for gRPC, as specified in: // https://github.com/grpc/grpc/blob/master/doc/naming.md. -// It is parsed from the target string that gets passed into Dial or DialContext by the user. And -// grpc passes it to the resolver and the balancer. +// It is parsed from the target string that gets passed into Dial or DialContext +// by the user. And gRPC passes it to the resolver and the balancer. // -// If the target follows the naming spec, and the parsed scheme is registered with grpc, we will -// parse the target string according to the spec. e.g. "dns://some_authority/foo.bar" will be parsed -// into &Target{Scheme: "dns", Authority: "some_authority", Endpoint: "foo.bar"} +// If the target follows the naming spec, and the parsed scheme is registered +// with gRPC, we will parse the target string according to the spec. If the +// target does not contain a scheme or if the parsed scheme is not registered +// (i.e. no corresponding resolver available to resolve the endpoint), we will +// apply the default scheme, and will attempt to reparse it. // -// If the target does not contain a scheme, we will apply the default scheme, and set the Target to -// be the full target string. e.g. "foo.bar" will be parsed into -// &Target{Scheme: resolver.GetDefaultScheme(), Endpoint: "foo.bar"}. +// Examples: // -// If the parsed scheme is not registered (i.e. no corresponding resolver available to resolve the -// endpoint), we set the Scheme to be the default scheme, and set the Endpoint to be the full target -// string. e.g. target string "unknown_scheme://authority/endpoint" will be parsed into -// &Target{Scheme: resolver.GetDefaultScheme(), Endpoint: "unknown_scheme://authority/endpoint"}. +// - "dns://some_authority/foo.bar" +// Target{Scheme: "dns", Authority: "some_authority", Endpoint: "foo.bar"} +// - "foo.bar" +// Target{Scheme: resolver.GetDefaultScheme(), Endpoint: "foo.bar"} +// - "unknown_scheme://authority/endpoint" +// Target{Scheme: resolver.GetDefaultScheme(), Endpoint: "unknown_scheme://authority/endpoint"} type Target struct { - Scheme string + // Deprecated: use URL.Scheme instead. + Scheme string + // Deprecated: use URL.Host instead. Authority string - Endpoint string + // URL contains the parsed dial target with an optional default scheme added + // to it if the original dial target contained no scheme or contained an + // unregistered scheme. Any query params specified in the original dial + // target can be accessed from here. + URL url.URL +} + +// Endpoint retrieves endpoint without leading "/" from either `URL.Path` +// or `URL.Opaque`. The latter is used when the former is empty. +func (t Target) Endpoint() string { + endpoint := t.URL.Path + if endpoint == "" { + endpoint = t.URL.Opaque + } + // For targets of the form "[scheme]://[authority]/endpoint, the endpoint + // value returned from url.Parse() contains a leading "/". Although this is + // in accordance with RFC 3986, we do not want to break existing resolver + // implementations which expect the endpoint without the leading "/". So, we + // end up stripping the leading "/" here. But this will result in an + // incorrect parsing for something like "unix:///path/to/socket". Since we + // own the "unix" resolver, we can workaround in the unix resolver by using + // the `URL` field. + return strings.TrimPrefix(endpoint, "/") } // Builder creates a resolver that will be used to watch name resolution updates. @@ -232,8 +300,10 @@ type Builder interface { // gRPC dial calls Build synchronously, and fails if the returned error is // not nil. Build(target Target, cc ClientConn, opts BuildOptions) (Resolver, error) - // Scheme returns the scheme supported by this resolver. - // Scheme is defined at https://github.com/grpc/grpc/blob/master/doc/naming.md. + // Scheme returns the scheme supported by this resolver. Scheme is defined + // at https://github.com/grpc/grpc/blob/master/doc/naming.md. The returned + // string should not contain uppercase characters, as they will not match + // the parsed target's scheme as defined in RFC 3986. Scheme() string } diff --git a/vendor/google.golang.org/grpc/resolver_conn_wrapper.go b/vendor/google.golang.org/grpc/resolver_conn_wrapper.go index f2d81968f9e..b408b3688f2 100644 --- a/vendor/google.golang.org/grpc/resolver_conn_wrapper.go +++ b/vendor/google.golang.org/grpc/resolver_conn_wrapper.go @@ -19,184 +19,204 @@ package grpc import ( - "fmt" + "context" "strings" "sync" - "time" "google.golang.org/grpc/balancer" - "google.golang.org/grpc/credentials" "google.golang.org/grpc/internal/channelz" "google.golang.org/grpc/internal/grpcsync" + "google.golang.org/grpc/internal/pretty" "google.golang.org/grpc/resolver" "google.golang.org/grpc/serviceconfig" ) +// resolverStateUpdater wraps the single method used by ccResolverWrapper to +// report a state update from the actual resolver implementation. +type resolverStateUpdater interface { + updateResolverState(s resolver.State, err error) error +} + // ccResolverWrapper is a wrapper on top of cc for resolvers. // It implements resolver.ClientConn interface. type ccResolverWrapper struct { - cc *ClientConn - resolverMu sync.Mutex - resolver resolver.Resolver - done *grpcsync.Event - curState resolver.State - - pollingMu sync.Mutex - polling chan struct{} + // The following fields are initialized when the wrapper is created and are + // read-only afterwards, and therefore can be accessed without a mutex. + cc resolverStateUpdater + channelzID *channelz.Identifier + ignoreServiceConfig bool + opts ccResolverWrapperOpts + serializer *grpcsync.CallbackSerializer // To serialize all incoming calls. + serializerCancel context.CancelFunc // To close the serializer, accessed only from close(). + + // All incoming (resolver --> gRPC) calls are guaranteed to execute in a + // mutually exclusive manner as they are scheduled on the serializer. + // Fields accessed *only* in these serializer callbacks, can therefore be + // accessed without a mutex. + curState resolver.State + + // mu guards access to the below fields. + mu sync.Mutex + closed bool + resolver resolver.Resolver // Accessed only from outgoing calls. +} + +// ccResolverWrapperOpts wraps the arguments to be passed when creating a new +// ccResolverWrapper. +type ccResolverWrapperOpts struct { + target resolver.Target // User specified dial target to resolve. + builder resolver.Builder // Resolver builder to use. + bOpts resolver.BuildOptions // Resolver build options to use. + channelzID *channelz.Identifier // Channelz identifier for the channel. } // newCCResolverWrapper uses the resolver.Builder to build a Resolver and // returns a ccResolverWrapper object which wraps the newly built resolver. -func newCCResolverWrapper(cc *ClientConn, rb resolver.Builder) (*ccResolverWrapper, error) { +func newCCResolverWrapper(cc resolverStateUpdater, opts ccResolverWrapperOpts) (*ccResolverWrapper, error) { + ctx, cancel := context.WithCancel(context.Background()) ccr := &ccResolverWrapper{ - cc: cc, - done: grpcsync.NewEvent(), - } - - var credsClone credentials.TransportCredentials - if creds := cc.dopts.copts.TransportCredentials; creds != nil { - credsClone = creds.Clone() - } - rbo := resolver.BuildOptions{ - DisableServiceConfig: cc.dopts.disableServiceConfig, - DialCreds: credsClone, - CredsBundle: cc.dopts.copts.CredsBundle, - Dialer: cc.dopts.copts.Dialer, - } - - var err error - // We need to hold the lock here while we assign to the ccr.resolver field - // to guard against a data race caused by the following code path, - // rb.Build-->ccr.ReportError-->ccr.poll-->ccr.resolveNow, would end up - // accessing ccr.resolver which is being assigned here. - ccr.resolverMu.Lock() - defer ccr.resolverMu.Unlock() - ccr.resolver, err = rb.Build(cc.parsedTarget, ccr, rbo) + cc: cc, + channelzID: opts.channelzID, + ignoreServiceConfig: opts.bOpts.DisableServiceConfig, + opts: opts, + serializer: grpcsync.NewCallbackSerializer(ctx), + serializerCancel: cancel, + } + + // Cannot hold the lock at build time because the resolver can send an + // update or error inline and these incoming calls grab the lock to schedule + // a callback in the serializer. + r, err := opts.builder.Build(opts.target, ccr, opts.bOpts) if err != nil { + cancel() return nil, err } + + // Any error reported by the resolver at build time that leads to a + // re-resolution request from the balancer is dropped by grpc until we + // return from this function. So, we don't have to handle pending resolveNow + // requests here. + ccr.mu.Lock() + ccr.resolver = r + ccr.mu.Unlock() + return ccr, nil } func (ccr *ccResolverWrapper) resolveNow(o resolver.ResolveNowOptions) { - ccr.resolverMu.Lock() - if !ccr.done.HasFired() { - ccr.resolver.ResolveNow(o) + ccr.mu.Lock() + defer ccr.mu.Unlock() + + // ccr.resolver field is set only after the call to Build() returns. But in + // the process of building, the resolver may send an error update which when + // propagated to the balancer may result in a re-resolution request. + if ccr.closed || ccr.resolver == nil { + return } - ccr.resolverMu.Unlock() + ccr.resolver.ResolveNow(o) } func (ccr *ccResolverWrapper) close() { - ccr.resolverMu.Lock() - ccr.resolver.Close() - ccr.done.Fire() - ccr.resolverMu.Unlock() -} - -// poll begins or ends asynchronous polling of the resolver based on whether -// err is ErrBadResolverState. -func (ccr *ccResolverWrapper) poll(err error) { - ccr.pollingMu.Lock() - defer ccr.pollingMu.Unlock() - if err != balancer.ErrBadResolverState { - // stop polling - if ccr.polling != nil { - close(ccr.polling) - ccr.polling = nil - } - return - } - if ccr.polling != nil { - // already polling + ccr.mu.Lock() + if ccr.closed { + ccr.mu.Unlock() return } - p := make(chan struct{}) - ccr.polling = p - go func() { - for i := 0; ; i++ { - ccr.resolveNow(resolver.ResolveNowOptions{}) - t := time.NewTimer(ccr.cc.dopts.resolveNowBackoff(i)) - select { - case <-p: - t.Stop() - return - case <-ccr.done.Done(): - // Resolver has been closed. - t.Stop() - return - case <-t.C: - select { - case <-p: - return - default: - } - // Timer expired; re-resolve. - } - } - }() + + channelz.Info(logger, ccr.channelzID, "Closing the name resolver") + + // Close the serializer to ensure that no more calls from the resolver are + // handled, before actually closing the resolver. + ccr.serializerCancel() + ccr.closed = true + r := ccr.resolver + ccr.mu.Unlock() + + // Give enqueued callbacks a chance to finish. + <-ccr.serializer.Done + + // Spawn a goroutine to close the resolver (since it may block trying to + // cleanup all allocated resources) and return early. + go r.Close() } -func (ccr *ccResolverWrapper) UpdateState(s resolver.State) { - if ccr.done.HasFired() { - return - } - channelz.Infof(logger, ccr.cc.channelzID, "ccResolverWrapper: sending update to cc: %v", s) - if channelz.IsOn() { +// serializerScheduleLocked is a convenience method to schedule a function to be +// run on the serializer while holding ccr.mu. +func (ccr *ccResolverWrapper) serializerScheduleLocked(f func(context.Context)) { + ccr.mu.Lock() + ccr.serializer.Schedule(f) + ccr.mu.Unlock() +} + +// UpdateState is called by resolver implementations to report new state to gRPC +// which includes addresses and service config. +func (ccr *ccResolverWrapper) UpdateState(s resolver.State) error { + errCh := make(chan error, 1) + ok := ccr.serializer.Schedule(func(context.Context) { ccr.addChannelzTraceEvent(s) + ccr.curState = s + if err := ccr.cc.updateResolverState(ccr.curState, nil); err == balancer.ErrBadResolverState { + errCh <- balancer.ErrBadResolverState + return + } + errCh <- nil + }) + if !ok { + // The only time when Schedule() fail to add the callback to the + // serializer is when the serializer is closed, and this happens only + // when the resolver wrapper is closed. + return nil } - ccr.curState = s - ccr.poll(ccr.cc.updateResolverState(ccr.curState, nil)) + return <-errCh } +// ReportError is called by resolver implementations to report errors +// encountered during name resolution to gRPC. func (ccr *ccResolverWrapper) ReportError(err error) { - if ccr.done.HasFired() { - return - } - channelz.Warningf(logger, ccr.cc.channelzID, "ccResolverWrapper: reporting error to cc: %v", err) - ccr.poll(ccr.cc.updateResolverState(resolver.State{}, err)) + ccr.serializerScheduleLocked(func(_ context.Context) { + channelz.Warningf(logger, ccr.channelzID, "ccResolverWrapper: reporting error to cc: %v", err) + ccr.cc.updateResolverState(resolver.State{}, err) + }) } -// NewAddress is called by the resolver implementation to send addresses to gRPC. +// NewAddress is called by the resolver implementation to send addresses to +// gRPC. func (ccr *ccResolverWrapper) NewAddress(addrs []resolver.Address) { - if ccr.done.HasFired() { - return - } - channelz.Infof(logger, ccr.cc.channelzID, "ccResolverWrapper: sending new addresses to cc: %v", addrs) - if channelz.IsOn() { + ccr.serializerScheduleLocked(func(_ context.Context) { ccr.addChannelzTraceEvent(resolver.State{Addresses: addrs, ServiceConfig: ccr.curState.ServiceConfig}) - } - ccr.curState.Addresses = addrs - ccr.poll(ccr.cc.updateResolverState(ccr.curState, nil)) + ccr.curState.Addresses = addrs + ccr.cc.updateResolverState(ccr.curState, nil) + }) } // NewServiceConfig is called by the resolver implementation to send service // configs to gRPC. func (ccr *ccResolverWrapper) NewServiceConfig(sc string) { - if ccr.done.HasFired() { - return - } - channelz.Infof(logger, ccr.cc.channelzID, "ccResolverWrapper: got new service config: %v", sc) - if ccr.cc.dopts.disableServiceConfig { - channelz.Info(logger, ccr.cc.channelzID, "Service config lookups disabled; ignoring config") - return - } - scpr := parseServiceConfig(sc) - if scpr.Err != nil { - channelz.Warningf(logger, ccr.cc.channelzID, "ccResolverWrapper: error parsing service config: %v", scpr.Err) - ccr.poll(balancer.ErrBadResolverState) - return - } - if channelz.IsOn() { + ccr.serializerScheduleLocked(func(_ context.Context) { + channelz.Infof(logger, ccr.channelzID, "ccResolverWrapper: got new service config: %s", sc) + if ccr.ignoreServiceConfig { + channelz.Info(logger, ccr.channelzID, "Service config lookups disabled; ignoring config") + return + } + scpr := parseServiceConfig(sc) + if scpr.Err != nil { + channelz.Warningf(logger, ccr.channelzID, "ccResolverWrapper: error parsing service config: %v", scpr.Err) + return + } ccr.addChannelzTraceEvent(resolver.State{Addresses: ccr.curState.Addresses, ServiceConfig: scpr}) - } - ccr.curState.ServiceConfig = scpr - ccr.poll(ccr.cc.updateResolverState(ccr.curState, nil)) + ccr.curState.ServiceConfig = scpr + ccr.cc.updateResolverState(ccr.curState, nil) + }) } +// ParseServiceConfig is called by resolver implementations to parse a JSON +// representation of the service config. func (ccr *ccResolverWrapper) ParseServiceConfig(scJSON string) *serviceconfig.ParseResult { return parseServiceConfig(scJSON) } +// addChannelzTraceEvent adds a channelz trace event containing the new +// state received from resolver implementations. func (ccr *ccResolverWrapper) addChannelzTraceEvent(s resolver.State) { var updates []string var oldSC, newSC *ServiceConfig @@ -215,8 +235,5 @@ func (ccr *ccResolverWrapper) addChannelzTraceEvent(s resolver.State) { } else if len(ccr.curState.Addresses) == 0 && len(s.Addresses) > 0 { updates = append(updates, "resolver returned new addresses") } - channelz.AddTraceEvent(logger, ccr.cc.channelzID, 0, &channelz.TraceEventDesc{ - Desc: fmt.Sprintf("Resolver state updated: %+v (%v)", s, strings.Join(updates, "; ")), - Severity: channelz.CtInfo, - }) + channelz.Infof(logger, ccr.channelzID, "Resolver state updated: %s (%v)", pretty.ToJSON(s), strings.Join(updates, "; ")) } diff --git a/vendor/google.golang.org/grpc/rpc_util.go b/vendor/google.golang.org/grpc/rpc_util.go index c0a1208f2f3..2030736a306 100644 --- a/vendor/google.golang.org/grpc/rpc_util.go +++ b/vendor/google.golang.org/grpc/rpc_util.go @@ -25,7 +25,6 @@ import ( "encoding/binary" "fmt" "io" - "io/ioutil" "math" "strings" "sync" @@ -77,7 +76,7 @@ func NewGZIPCompressorWithLevel(level int) (Compressor, error) { return &gzipCompressor{ pool: sync.Pool{ New: func() interface{} { - w, err := gzip.NewWriterLevel(ioutil.Discard, level) + w, err := gzip.NewWriterLevel(io.Discard, level) if err != nil { panic(err) } @@ -143,7 +142,7 @@ func (d *gzipDecompressor) Do(r io.Reader) ([]byte, error) { z.Close() d.pool.Put(z) }() - return ioutil.ReadAll(z) + return io.ReadAll(z) } func (d *gzipDecompressor) Type() string { @@ -160,6 +159,7 @@ type callInfo struct { contentSubtype string codec baseCodec maxRetryRPCBufferSize int + onFinish []func(err error) } func defaultCallInfo() *callInfo { @@ -198,7 +198,7 @@ func Header(md *metadata.MD) CallOption { // HeaderCallOption is a CallOption for collecting response header metadata. // The metadata field will be populated *after* the RPC completes. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. @@ -220,7 +220,7 @@ func Trailer(md *metadata.MD) CallOption { // TrailerCallOption is a CallOption for collecting response trailer metadata. // The metadata field will be populated *after* the RPC completes. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. @@ -242,7 +242,7 @@ func Peer(p *peer.Peer) CallOption { // PeerCallOption is a CallOption for collecting the identity of the remote // peer. The peer field will be populated *after* the RPC completes. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. @@ -258,7 +258,8 @@ func (o PeerCallOption) after(c *callInfo, attempt *csAttempt) { } // WaitForReady configures the action to take when an RPC is attempted on broken -// connections or unreachable servers. If waitForReady is false, the RPC will fail +// connections or unreachable servers. If waitForReady is false and the +// connection is in the TRANSIENT_FAILURE state, the RPC will fail // immediately. Otherwise, the RPC client will block the call until a // connection is available (or the call is canceled or times out) and will // retry the call if it fails due to a transient error. gRPC will not retry if @@ -281,7 +282,7 @@ func FailFast(failFast bool) CallOption { // FailFastCallOption is a CallOption for indicating whether an RPC should fail // fast or not. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. @@ -295,8 +296,44 @@ func (o FailFastCallOption) before(c *callInfo) error { } func (o FailFastCallOption) after(c *callInfo, attempt *csAttempt) {} +// OnFinish returns a CallOption that configures a callback to be called when +// the call completes. The error passed to the callback is the status of the +// RPC, and may be nil. The onFinish callback provided will only be called once +// by gRPC. This is mainly used to be used by streaming interceptors, to be +// notified when the RPC completes along with information about the status of +// the RPC. +// +// # Experimental +// +// Notice: This API is EXPERIMENTAL and may be changed or removed in a +// later release. +func OnFinish(onFinish func(err error)) CallOption { + return OnFinishCallOption{ + OnFinish: onFinish, + } +} + +// OnFinishCallOption is CallOption that indicates a callback to be called when +// the call completes. +// +// # Experimental +// +// Notice: This type is EXPERIMENTAL and may be changed or removed in a +// later release. +type OnFinishCallOption struct { + OnFinish func(error) +} + +func (o OnFinishCallOption) before(c *callInfo) error { + c.onFinish = append(c.onFinish, o.OnFinish) + return nil +} + +func (o OnFinishCallOption) after(c *callInfo, attempt *csAttempt) {} + // MaxCallRecvMsgSize returns a CallOption which sets the maximum message size -// in bytes the client can receive. +// in bytes the client can receive. If this is not set, gRPC uses the default +// 4MB. func MaxCallRecvMsgSize(bytes int) CallOption { return MaxRecvMsgSizeCallOption{MaxRecvMsgSize: bytes} } @@ -304,7 +341,7 @@ func MaxCallRecvMsgSize(bytes int) CallOption { // MaxRecvMsgSizeCallOption is a CallOption that indicates the maximum message // size in bytes the client can receive. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. @@ -319,7 +356,8 @@ func (o MaxRecvMsgSizeCallOption) before(c *callInfo) error { func (o MaxRecvMsgSizeCallOption) after(c *callInfo, attempt *csAttempt) {} // MaxCallSendMsgSize returns a CallOption which sets the maximum message size -// in bytes the client can send. +// in bytes the client can send. If this is not set, gRPC uses the default +// `math.MaxInt32`. func MaxCallSendMsgSize(bytes int) CallOption { return MaxSendMsgSizeCallOption{MaxSendMsgSize: bytes} } @@ -327,7 +365,7 @@ func MaxCallSendMsgSize(bytes int) CallOption { // MaxSendMsgSizeCallOption is a CallOption that indicates the maximum message // size in bytes the client can send. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. @@ -350,7 +388,7 @@ func PerRPCCredentials(creds credentials.PerRPCCredentials) CallOption { // PerRPCCredsCallOption is a CallOption that indicates the per-RPC // credentials to use for the call. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. @@ -368,7 +406,7 @@ func (o PerRPCCredsCallOption) after(c *callInfo, attempt *csAttempt) {} // sending the request. If WithCompressor is also set, UseCompressor has // higher priority. // -// Experimental +// # Experimental // // Notice: This API is EXPERIMENTAL and may be changed or removed in a // later release. @@ -378,7 +416,7 @@ func UseCompressor(name string) CallOption { // CompressorCallOption is a CallOption that indicates the compressor to use. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. @@ -415,7 +453,7 @@ func CallContentSubtype(contentSubtype string) CallOption { // ContentSubtypeCallOption is a CallOption that indicates the content-subtype // used for marshaling messages. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. @@ -429,9 +467,10 @@ func (o ContentSubtypeCallOption) before(c *callInfo) error { } func (o ContentSubtypeCallOption) after(c *callInfo, attempt *csAttempt) {} -// ForceCodec returns a CallOption that will set the given Codec to be -// used for all request and response messages for a call. The result of calling -// String() will be used as the content-subtype in a case-insensitive manner. +// ForceCodec returns a CallOption that will set codec to be used for all +// request and response messages for a call. The result of calling Name() will +// be used as the content-subtype after converting to lowercase, unless +// CallContentSubtype is also used. // // See Content-Type on // https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#requests for @@ -442,7 +481,7 @@ func (o ContentSubtypeCallOption) after(c *callInfo, attempt *csAttempt) {} // This function is provided for advanced users; prefer to use only // CallContentSubtype to select a registered codec instead. // -// Experimental +// # Experimental // // Notice: This API is EXPERIMENTAL and may be changed or removed in a // later release. @@ -453,7 +492,7 @@ func ForceCodec(codec encoding.Codec) CallOption { // ForceCodecCallOption is a CallOption that indicates the codec used for // marshaling messages. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. @@ -478,7 +517,7 @@ func CallCustomCodec(codec Codec) CallOption { // CustomCodecCallOption is a CallOption that indicates the codec used for // marshaling messages. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. @@ -495,7 +534,7 @@ func (o CustomCodecCallOption) after(c *callInfo, attempt *csAttempt) {} // MaxRetryRPCBufferSize returns a CallOption that limits the amount of memory // used for buffering this RPC's requests for retry purposes. // -// Experimental +// # Experimental // // Notice: This API is EXPERIMENTAL and may be changed or removed in a // later release. @@ -506,7 +545,7 @@ func MaxRetryRPCBufferSize(bytes int) CallOption { // MaxRetryRPCBufferSizeCallOption is a CallOption indicating the amount of // memory to be used for caching this RPC for retry purposes. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. @@ -546,10 +585,11 @@ type parser struct { // format. The caller owns the returned msg memory. // // If there is an error, possible values are: -// * io.EOF, when no messages remain -// * io.ErrUnexpectedEOF -// * of type transport.ConnectionError -// * an error from the status package +// - io.EOF, when no messages remain +// - io.ErrUnexpectedEOF +// - of type transport.ConnectionError +// - an error from the status package +// // No other error values or types must be returned, which also means // that the underlying io.Reader must not return an incompatible // error. @@ -654,12 +694,13 @@ func msgHeader(data, compData []byte) (hdr []byte, payload []byte) { func outPayload(client bool, msg interface{}, data, payload []byte, t time.Time) *stats.OutPayload { return &stats.OutPayload{ - Client: client, - Payload: msg, - Data: data, - Length: len(data), - WireLength: len(payload) + headerLen, - SentTime: t, + Client: client, + Payload: msg, + Data: data, + Length: len(data), + WireLength: len(payload) + headerLen, + CompressedLength: len(payload), + SentTime: t, } } @@ -680,7 +721,7 @@ func checkRecvPayload(pf payloadFormat, recvCompress string, haveCompressor bool } type payloadInfo struct { - wireLength int // The compressed length got from wire. + compressedLength int // The compressed length got from wire. uncompressedBytes []byte } @@ -690,7 +731,7 @@ func recvAndDecompress(p *parser, s *transport.Stream, dc Decompressor, maxRecei return nil, err } if payInfo != nil { - payInfo.wireLength = len(d) + payInfo.compressedLength = len(d) } if st := checkRecvPayload(pf, s.RecvCompress(), compressor != nil || dc != nil); st != nil { @@ -708,15 +749,13 @@ func recvAndDecompress(p *parser, s *transport.Stream, dc Decompressor, maxRecei d, size, err = decompress(compressor, d, maxReceiveMessageSize) } if err != nil { - return nil, status.Errorf(codes.Internal, "grpc: failed to decompress the received message %v", err) + return nil, status.Errorf(codes.Internal, "grpc: failed to decompress the received message: %v", err) + } + if size > maxReceiveMessageSize { + // TODO: Revisit the error code. Currently keep it consistent with java + // implementation. + return nil, status.Errorf(codes.ResourceExhausted, "grpc: received message after decompression larger than max (%d vs. %d)", size, maxReceiveMessageSize) } - } else { - size = len(d) - } - if size > maxReceiveMessageSize { - // TODO: Revisit the error code. Currently keep it consistent with java - // implementation. - return nil, status.Errorf(codes.ResourceExhausted, "grpc: received message larger than max (%d vs. %d)", size, maxReceiveMessageSize) } return d, nil } @@ -745,7 +784,7 @@ func decompress(compressor encoding.Compressor, d []byte, maxReceiveMessageSize } // Read from LimitReader with limit max+1. So if the underlying // reader is over limit, the result will be bigger than max. - d, err = ioutil.ReadAll(io.LimitReader(dcReader, int64(maxReceiveMessageSize)+1)) + d, err = io.ReadAll(io.LimitReader(dcReader, int64(maxReceiveMessageSize)+1)) return d, len(d), err } @@ -758,7 +797,7 @@ func recv(p *parser, c baseCodec, s *transport.Stream, dc Decompressor, m interf return err } if err := c.Unmarshal(d, m); err != nil { - return status.Errorf(codes.Internal, "grpc: failed to unmarshal the received message %v", err) + return status.Errorf(codes.Internal, "grpc: failed to unmarshal the received message: %v", err) } if payInfo != nil { payInfo.uncompressedBytes = d @@ -827,33 +866,45 @@ func Errorf(c codes.Code, format string, a ...interface{}) error { // toRPCErr converts an error into an error from the status package. func toRPCErr(err error) error { - if err == nil || err == io.EOF { + switch err { + case nil, io.EOF: return err - } - if err == io.ErrUnexpectedEOF { + case context.DeadlineExceeded: + return status.Error(codes.DeadlineExceeded, err.Error()) + case context.Canceled: + return status.Error(codes.Canceled, err.Error()) + case io.ErrUnexpectedEOF: return status.Error(codes.Internal, err.Error()) } - if _, ok := status.FromError(err); ok { - return err - } + switch e := err.(type) { case transport.ConnectionError: return status.Error(codes.Unavailable, e.Desc) - default: - switch err { - case context.DeadlineExceeded: - return status.Error(codes.DeadlineExceeded, err.Error()) - case context.Canceled: - return status.Error(codes.Canceled, err.Error()) - } + case *transport.NewStreamError: + return toRPCErr(e.Err) + } + + if _, ok := status.FromError(err); ok { + return err } + return status.Error(codes.Unknown, err.Error()) } // setCallInfoCodec should only be called after CallOptions have been applied. func setCallInfoCodec(c *callInfo) error { if c.codec != nil { - // codec was already set by a CallOption; use it. + // codec was already set by a CallOption; use it, but set the content + // subtype if it is not set. + if c.contentSubtype == "" { + // c.codec is a baseCodec to hide the difference between grpc.Codec and + // encoding.Codec (Name vs. String method name). We only support + // setting content subtype from encoding.Codec to avoid a behavior + // change with the deprecated version. + if ec, ok := c.codec.(encoding.Codec); ok { + c.contentSubtype = strings.ToLower(ec.Name()) + } + } return nil } diff --git a/vendor/google.golang.org/grpc/server.go b/vendor/google.golang.org/grpc/server.go index 7a2aa28a114..8869cc906f2 100644 --- a/vendor/google.golang.org/grpc/server.go +++ b/vendor/google.golang.org/grpc/server.go @@ -43,8 +43,8 @@ import ( "google.golang.org/grpc/internal" "google.golang.org/grpc/internal/binarylog" "google.golang.org/grpc/internal/channelz" - "google.golang.org/grpc/internal/grpcrand" "google.golang.org/grpc/internal/grpcsync" + "google.golang.org/grpc/internal/grpcutil" "google.golang.org/grpc/internal/transport" "google.golang.org/grpc/keepalive" "google.golang.org/grpc/metadata" @@ -57,12 +57,30 @@ import ( const ( defaultServerMaxReceiveMessageSize = 1024 * 1024 * 4 defaultServerMaxSendMessageSize = math.MaxInt32 + + // Server transports are tracked in a map which is keyed on listener + // address. For regular gRPC traffic, connections are accepted in Serve() + // through a call to Accept(), and we use the actual listener address as key + // when we add it to the map. But for connections received through + // ServeHTTP(), we do not have a listener and hence use this dummy value. + listenerAddressForServeHTTP = "listenerAddressForServeHTTP" ) func init() { internal.GetServerCredentials = func(srv *Server) credentials.TransportCredentials { return srv.opts.creds } + internal.DrainServerTransports = func(srv *Server, addr string) { + srv.drainServerTransports(addr) + } + internal.AddGlobalServerOptions = func(opt ...ServerOption) { + globalServerOptions = append(globalServerOptions, opt...) + } + internal.ClearGlobalServerOptions = func() { + globalServerOptions = nil + } + internal.BinaryLogger = binaryLogger + internal.JoinServerOptions = newJoinServerOption } var statusOK = status.New(codes.OK, "") @@ -97,19 +115,16 @@ type serviceInfo struct { mdata interface{} } -type serverWorkerData struct { - st transport.ServerTransport - wg *sync.WaitGroup - stream *transport.Stream -} - // Server is a gRPC server to serve RPC requests. type Server struct { opts serverOptions - mu sync.Mutex // guards following - lis map[net.Listener]bool - conns map[transport.ServerTransport]bool + mu sync.Mutex // guards following + lis map[net.Listener]bool + // conns contains all active server transports. It is a map keyed on a + // listener address with the value being the set of active transports + // belonging to that listener. + conns map[string]map[transport.ServerTransport]bool serve bool drain bool cv *sync.Cond // signaled when connections close for GracefulStop @@ -121,10 +136,10 @@ type Server struct { channelzRemoveOnce sync.Once serveWG sync.WaitGroup // counts active Serve goroutines for GracefulStop - channelzID int64 // channelz unique identification number + channelzID *channelz.Identifier czData *channelzData - serverWorkerChannels []chan *serverWorkerData + serverWorkerChannel chan func() } type serverOptions struct { @@ -136,8 +151,9 @@ type serverOptions struct { streamInt StreamServerInterceptor chainUnaryInts []UnaryServerInterceptor chainStreamInts []StreamServerInterceptor + binaryLogger binarylog.Logger inTapHandle tap.ServerInHandle - statsHandler stats.Handler + statsHandlers []stats.Handler maxConcurrentStreams uint32 maxReceiveMessageSize int maxSendMessageSize int @@ -155,12 +171,14 @@ type serverOptions struct { } var defaultServerOptions = serverOptions{ + maxConcurrentStreams: math.MaxUint32, maxReceiveMessageSize: defaultServerMaxReceiveMessageSize, maxSendMessageSize: defaultServerMaxSendMessageSize, connectionTimeout: 120 * time.Second, writeBufferSize: defaultWriteBufSize, readBufferSize: defaultReadBufSize, } +var globalServerOptions []ServerOption // A ServerOption sets options such as credentials, codec and keepalive parameters, etc. type ServerOption interface { @@ -170,7 +188,7 @@ type ServerOption interface { // EmptyServerOption does not alter the server configuration. It can be embedded // in another structure to build custom server options. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. @@ -194,10 +212,27 @@ func newFuncServerOption(f func(*serverOptions)) *funcServerOption { } } -// WriteBufferSize determines how much data can be batched before doing a write on the wire. -// The corresponding memory allocation for this buffer will be twice the size to keep syscalls low. -// The default value for this buffer is 32KB. -// Zero will disable the write buffer such that each write will be on underlying connection. +// joinServerOption provides a way to combine arbitrary number of server +// options into one. +type joinServerOption struct { + opts []ServerOption +} + +func (mdo *joinServerOption) apply(do *serverOptions) { + for _, opt := range mdo.opts { + opt.apply(do) + } +} + +func newJoinServerOption(opts ...ServerOption) ServerOption { + return &joinServerOption{opts: opts} +} + +// WriteBufferSize determines how much data can be batched before doing a write +// on the wire. The corresponding memory allocation for this buffer will be +// twice the size to keep syscalls low. The default value for this buffer is +// 32KB. Zero or negative values will disable the write buffer such that each +// write will be on underlying connection. // Note: A Send call may not directly translate to a write. func WriteBufferSize(s int) ServerOption { return newFuncServerOption(func(o *serverOptions) { @@ -205,11 +240,10 @@ func WriteBufferSize(s int) ServerOption { }) } -// ReadBufferSize lets you set the size of read buffer, this determines how much data can be read at most -// for one read syscall. -// The default value for this buffer is 32KB. -// Zero will disable read buffer for a connection so data framer can access the underlying -// conn directly. +// ReadBufferSize lets you set the size of read buffer, this determines how much +// data can be read at most for one read syscall. The default value for this +// buffer is 32KB. Zero or negative values will disable read buffer for a +// connection so data framer can access the underlying conn directly. func ReadBufferSize(s int) ServerOption { return newFuncServerOption(func(o *serverOptions) { o.readBufferSize = s @@ -266,6 +300,35 @@ func CustomCodec(codec Codec) ServerOption { }) } +// ForceServerCodec returns a ServerOption that sets a codec for message +// marshaling and unmarshaling. +// +// This will override any lookups by content-subtype for Codecs registered +// with RegisterCodec. +// +// See Content-Type on +// https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#requests for +// more details. Also see the documentation on RegisterCodec and +// CallContentSubtype for more details on the interaction between encoding.Codec +// and content-subtype. +// +// This function is provided for advanced users; prefer to register codecs +// using encoding.RegisterCodec. +// The server will automatically use registered codecs based on the incoming +// requests' headers. See also +// https://github.com/grpc/grpc-go/blob/master/Documentation/encoding.md#using-a-codec. +// Will be supported throughout 1.x. +// +// # Experimental +// +// Notice: This API is EXPERIMENTAL and may be changed or removed in a +// later release. +func ForceServerCodec(codec encoding.Codec) ServerOption { + return newFuncServerOption(func(o *serverOptions) { + o.codec = codec + }) +} + // RPCCompressor returns a ServerOption that sets a compressor for outbound // messages. For backward compatibility, all outbound messages will be sent // using this compressor, regardless of incoming message compression. By @@ -319,6 +382,9 @@ func MaxSendMsgSize(m int) ServerOption { // MaxConcurrentStreams returns a ServerOption that will apply a limit on the number // of concurrent streams to each ServerTransport. func MaxConcurrentStreams(n uint32) ServerOption { + if n == 0 { + n = math.MaxUint32 + } return newFuncServerOption(func(o *serverOptions) { o.maxConcurrentStreams = n }) @@ -376,6 +442,11 @@ func ChainStreamInterceptor(interceptors ...StreamServerInterceptor) ServerOptio // InTapHandle returns a ServerOption that sets the tap handle for all the server // transport to be created. Only one can be installed. +// +// # Experimental +// +// Notice: This API is EXPERIMENTAL and may be changed or removed in a +// later release. func InTapHandle(h tap.ServerInHandle) ServerOption { return newFuncServerOption(func(o *serverOptions) { if o.inTapHandle != nil { @@ -388,7 +459,21 @@ func InTapHandle(h tap.ServerInHandle) ServerOption { // StatsHandler returns a ServerOption that sets the stats handler for the server. func StatsHandler(h stats.Handler) ServerOption { return newFuncServerOption(func(o *serverOptions) { - o.statsHandler = h + if h == nil { + logger.Error("ignoring nil parameter in grpc.StatsHandler ServerOption") + // Do not allow a nil stats handler, which would otherwise cause + // panics. + return + } + o.statsHandlers = append(o.statsHandlers, h) + }) +} + +// binaryLogger returns a ServerOption that can set the binary logger for the +// server. +func binaryLogger(bl binarylog.Logger) ServerOption { + return newFuncServerOption(func(o *serverOptions) { + o.binaryLogger = bl }) } @@ -415,7 +500,7 @@ func UnknownServiceHandler(streamHandler StreamHandler) ServerOption { // new connections. If this is not set, the default is 120 seconds. A zero or // negative value will result in an immediate timeout. // -// Experimental +// # Experimental // // Notice: This API is EXPERIMENTAL and may be changed or removed in a // later release. @@ -436,7 +521,7 @@ func MaxHeaderListSize(s uint32) ServerOption { // HeaderTableSize returns a ServerOption that sets the size of dynamic // header table for stream. // -// Experimental +// # Experimental // // Notice: This API is EXPERIMENTAL and may be changed or removed in a // later release. @@ -451,7 +536,7 @@ func HeaderTableSize(s uint32) ServerOption { // zero (default) will disable workers and spawn a new goroutine for each // stream. // -// Experimental +// # Experimental // // Notice: This API is EXPERIMENTAL and may be changed or removed in a // later release. @@ -473,53 +558,49 @@ func NumStreamWorkers(numServerWorkers uint32) ServerOption { const serverWorkerResetThreshold = 1 << 16 // serverWorkers blocks on a *transport.Stream channel forever and waits for -// data to be fed by serveStreams. This allows different requests to be +// data to be fed by serveStreams. This allows multiple requests to be // processed by the same goroutine, removing the need for expensive stack // re-allocations (see the runtime.morestack problem [1]). // // [1] https://github.com/golang/go/issues/18138 -func (s *Server) serverWorker(ch chan *serverWorkerData) { - // To make sure all server workers don't reset at the same time, choose a - // random number of iterations before resetting. - threshold := serverWorkerResetThreshold + grpcrand.Intn(serverWorkerResetThreshold) - for completed := 0; completed < threshold; completed++ { - data, ok := <-ch +func (s *Server) serverWorker() { + for completed := 0; completed < serverWorkerResetThreshold; completed++ { + f, ok := <-s.serverWorkerChannel if !ok { return } - s.handleStream(data.st, data.stream, s.traceInfo(data.st, data.stream)) - data.wg.Done() + f() } - go s.serverWorker(ch) + go s.serverWorker() } -// initServerWorkers creates worker goroutines and channels to process incoming +// initServerWorkers creates worker goroutines and a channel to process incoming // connections to reduce the time spent overall on runtime.morestack. func (s *Server) initServerWorkers() { - s.serverWorkerChannels = make([]chan *serverWorkerData, s.opts.numServerWorkers) + s.serverWorkerChannel = make(chan func()) for i := uint32(0); i < s.opts.numServerWorkers; i++ { - s.serverWorkerChannels[i] = make(chan *serverWorkerData) - go s.serverWorker(s.serverWorkerChannels[i]) + go s.serverWorker() } } func (s *Server) stopServerWorkers() { - for i := uint32(0); i < s.opts.numServerWorkers; i++ { - close(s.serverWorkerChannels[i]) - } + close(s.serverWorkerChannel) } // NewServer creates a gRPC server which has no service registered and has not // started to accept requests yet. func NewServer(opt ...ServerOption) *Server { opts := defaultServerOptions + for _, o := range globalServerOptions { + o.apply(&opts) + } for _, o := range opt { o.apply(&opts) } s := &Server{ lis: make(map[net.Listener]bool), opts: opts, - conns: make(map[transport.ServerTransport]bool), + conns: make(map[string]map[transport.ServerTransport]bool), services: make(map[string]*serviceInfo), quit: grpcsync.NewEvent(), done: grpcsync.NewEvent(), @@ -537,9 +618,8 @@ func NewServer(opt ...ServerOption) *Server { s.initServerWorkers() } - if channelz.IsOn() { - s.channelzID = channelz.RegisterServer(&channelzServer{s}, "") - } + s.channelzID = channelz.RegisterServer(&channelzServer{s}, "") + channelz.Info(logger, s.channelzID, "Server created") return s } @@ -663,16 +743,9 @@ func (s *Server) GetServiceInfo() map[string]ServiceInfo { // the server being stopped. var ErrServerStopped = errors.New("grpc: the server has been stopped") -func (s *Server) useTransportAuthenticator(rawConn net.Conn) (net.Conn, credentials.AuthInfo, error) { - if s.opts.creds == nil { - return rawConn, nil, nil - } - return s.opts.creds.ServerHandshake(rawConn) -} - type listenSocket struct { net.Listener - channelzID int64 + channelzID *channelz.Identifier } func (l *listenSocket) ChannelzMetric() *channelz.SocketInternalMetric { @@ -684,9 +757,8 @@ func (l *listenSocket) ChannelzMetric() *channelz.SocketInternalMetric { func (l *listenSocket) Close() error { err := l.Listener.Close() - if channelz.IsOn() { - channelz.RemoveEntry(l.channelzID) - } + channelz.RemoveEntry(l.channelzID) + channelz.Info(logger, l.channelzID, "ListenSocket deleted") return err } @@ -719,11 +791,6 @@ func (s *Server) Serve(lis net.Listener) error { ls := &listenSocket{Listener: lis} s.lis[ls] = true - if channelz.IsOn() { - ls.channelzID = channelz.RegisterListenSocket(ls, s.channelzID, lis.Addr().String()) - } - s.mu.Unlock() - defer func() { s.mu.Lock() if s.lis != nil && s.lis[ls] { @@ -733,8 +800,16 @@ func (s *Server) Serve(lis net.Listener) error { s.mu.Unlock() }() - var tempDelay time.Duration // how long to sleep on accept failure + var err error + ls.channelzID, err = channelz.RegisterListenSocket(ls, s.channelzID, lis.Addr().String()) + if err != nil { + s.mu.Unlock() + return err + } + s.mu.Unlock() + channelz.Info(logger, ls.channelzID, "ListenSocket created") + var tempDelay time.Duration // how long to sleep on accept failure for { rawConn, err := lis.Accept() if err != nil { @@ -778,7 +853,7 @@ func (s *Server) Serve(lis net.Listener) error { // s.conns before this conn can be added. s.serveWG.Add(1) go func() { - s.handleRawConn(rawConn) + s.handleRawConn(lis.Addr().String(), rawConn) s.serveWG.Done() }() } @@ -786,51 +861,47 @@ func (s *Server) Serve(lis net.Listener) error { // handleRawConn forks a goroutine to handle a just-accepted connection that // has not had any I/O performed on it yet. -func (s *Server) handleRawConn(rawConn net.Conn) { +func (s *Server) handleRawConn(lisAddr string, rawConn net.Conn) { if s.quit.HasFired() { rawConn.Close() return } rawConn.SetDeadline(time.Now().Add(s.opts.connectionTimeout)) - conn, authInfo, err := s.useTransportAuthenticator(rawConn) - if err != nil { - // ErrConnDispatched means that the connection was dispatched away from - // gRPC; those connections should be left open. - if err != credentials.ErrConnDispatched { - s.mu.Lock() - s.errorf("ServerHandshake(%q) failed: %v", rawConn.RemoteAddr(), err) - s.mu.Unlock() - channelz.Warningf(logger, s.channelzID, "grpc: Server.Serve failed to complete security handshake from %q: %v", rawConn.RemoteAddr(), err) - rawConn.Close() - } - rawConn.SetDeadline(time.Time{}) - return - } // Finish handshaking (HTTP2) - st := s.newHTTP2Transport(conn, authInfo) + st := s.newHTTP2Transport(rawConn) + rawConn.SetDeadline(time.Time{}) if st == nil { return } - rawConn.SetDeadline(time.Time{}) - if !s.addConn(st) { + if !s.addConn(lisAddr, st) { return } go func() { s.serveStreams(st) - s.removeConn(st) + s.removeConn(lisAddr, st) }() } +func (s *Server) drainServerTransports(addr string) { + s.mu.Lock() + conns := s.conns[addr] + for st := range conns { + st.Drain("") + } + s.mu.Unlock() +} + // newHTTP2Transport sets up a http/2 transport (using the // gRPC http2 server transport in transport/http2_server.go). -func (s *Server) newHTTP2Transport(c net.Conn, authInfo credentials.AuthInfo) transport.ServerTransport { +func (s *Server) newHTTP2Transport(c net.Conn) transport.ServerTransport { config := &transport.ServerConfig{ MaxStreams: s.opts.maxConcurrentStreams, - AuthInfo: authInfo, + ConnectionTimeout: s.opts.connectionTimeout, + Credentials: s.opts.creds, InTapHandle: s.opts.inTapHandle, - StatsHandler: s.opts.statsHandler, + StatsHandlers: s.opts.statsHandlers, KeepaliveParams: s.opts.keepaliveParams, KeepalivePolicy: s.opts.keepalivePolicy, InitialWindowSize: s.opts.initialWindowSize, @@ -841,13 +912,20 @@ func (s *Server) newHTTP2Transport(c net.Conn, authInfo credentials.AuthInfo) tr MaxHeaderListSize: s.opts.maxHeaderListSize, HeaderTableSize: s.opts.headerTableSize, } - st, err := transport.NewServerTransport("http2", c, config) + st, err := transport.NewServerTransport(c, config) if err != nil { s.mu.Lock() s.errorf("NewServerTransport(%q) failed: %v", c.RemoteAddr(), err) s.mu.Unlock() - c.Close() - channelz.Warning(logger, s.channelzID, "grpc: Server.Serve failed to create ServerTransport: ", err) + // ErrConnDispatched means that the connection was dispatched away from + // gRPC; those connections should be left open. + if err != credentials.ErrConnDispatched { + // Don't log on ErrConnDispatched and io.EOF to prevent log spam. + if err != io.EOF { + channelz.Info(logger, s.channelzID, "grpc: Server.Serve failed to create ServerTransport: ", err) + } + c.Close() + } return nil } @@ -855,29 +933,29 @@ func (s *Server) newHTTP2Transport(c net.Conn, authInfo credentials.AuthInfo) tr } func (s *Server) serveStreams(st transport.ServerTransport) { - defer st.Close() + defer st.Close(errors.New("finished serving streams for the server transport")) var wg sync.WaitGroup - var roundRobinCounter uint32 + streamQuota := newHandlerQuota(s.opts.maxConcurrentStreams) st.HandleStreams(func(stream *transport.Stream) { wg.Add(1) + + streamQuota.acquire() + f := func() { + defer streamQuota.release() + defer wg.Done() + s.handleStream(st, stream, s.traceInfo(st, stream)) + } + if s.opts.numServerWorkers > 0 { - data := &serverWorkerData{st: st, wg: &wg, stream: stream} select { - case s.serverWorkerChannels[atomic.AddUint32(&roundRobinCounter, 1)%s.opts.numServerWorkers] <- data: + case s.serverWorkerChannel <- f: + return default: // If all stream workers are busy, fallback to the default code path. - go func() { - s.handleStream(st, stream, s.traceInfo(st, stream)) - wg.Done() - }() } - } else { - go func() { - defer wg.Done() - s.handleStream(st, stream, s.traceInfo(st, stream)) - }() } + go f() }, func(ctx context.Context, method string) context.Context { if !EnableTracing { return ctx @@ -902,32 +980,33 @@ var _ http.Handler = (*Server)(nil) // To share one port (such as 443 for https) between gRPC and an // existing http.Handler, use a root http.Handler such as: // -// if r.ProtoMajor == 2 && strings.HasPrefix( -// r.Header.Get("Content-Type"), "application/grpc") { -// grpcServer.ServeHTTP(w, r) -// } else { -// yourMux.ServeHTTP(w, r) -// } +// if r.ProtoMajor == 2 && strings.HasPrefix( +// r.Header.Get("Content-Type"), "application/grpc") { +// grpcServer.ServeHTTP(w, r) +// } else { +// yourMux.ServeHTTP(w, r) +// } // // Note that ServeHTTP uses Go's HTTP/2 server implementation which is totally // separate from grpc-go's HTTP/2 server. Performance and features may vary // between the two paths. ServeHTTP does not support some gRPC features // available through grpc-go's HTTP/2 server. // -// Experimental +// # Experimental // // Notice: This API is EXPERIMENTAL and may be changed or removed in a // later release. func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { - st, err := transport.NewServerHandlerTransport(w, r, s.opts.statsHandler) + st, err := transport.NewServerHandlerTransport(w, r, s.opts.statsHandlers) if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) + // Errors returned from transport.NewServerHandlerTransport have + // already been written to w. return } - if !s.addConn(st) { + if !s.addConn(listenerAddressForServeHTTP, st) { return } - defer s.removeConn(st) + defer s.removeConn(listenerAddressForServeHTTP, st) s.serveStreams(st) } @@ -955,27 +1034,40 @@ func (s *Server) traceInfo(st transport.ServerTransport, stream *transport.Strea return trInfo } -func (s *Server) addConn(st transport.ServerTransport) bool { +func (s *Server) addConn(addr string, st transport.ServerTransport) bool { s.mu.Lock() defer s.mu.Unlock() if s.conns == nil { - st.Close() + st.Close(errors.New("Server.addConn called when server has already been stopped")) return false } if s.drain { // Transport added after we drained our existing conns: drain it // immediately. - st.Drain() + st.Drain("") } - s.conns[st] = true + + if s.conns[addr] == nil { + // Create a map entry if this is the first connection on this listener. + s.conns[addr] = make(map[transport.ServerTransport]bool) + } + s.conns[addr][st] = true return true } -func (s *Server) removeConn(st transport.ServerTransport) { +func (s *Server) removeConn(addr string, st transport.ServerTransport) { s.mu.Lock() defer s.mu.Unlock() - if s.conns != nil { - delete(s.conns, st) + + conns := s.conns[addr] + if conns != nil { + delete(conns, st) + if len(conns) == 0 { + // If the last connection for this address is being removed, also + // remove the map entry corresponding to the address. This is used + // in GracefulStop() when waiting for all connections to be closed. + delete(s.conns, addr) + } s.cv.Broadcast() } } @@ -1019,8 +1111,10 @@ func (s *Server) sendResponse(t transport.ServerTransport, stream *transport.Str return status.Errorf(codes.ResourceExhausted, "grpc: trying to send message larger than max (%d vs. %d)", len(payload), s.opts.maxSendMessageSize) } err = t.Write(stream, hdr, payload, opts) - if err == nil && s.opts.statsHandler != nil { - s.opts.statsHandler.HandleRPC(stream.Context(), outPayload(false, msg, data, payload, time.Now())) + if err == nil { + for _, sh := range s.opts.statsHandlers { + sh.HandleRPC(stream.Context(), outPayload(false, msg, data, payload, time.Now())) + } } return err } @@ -1040,36 +1134,40 @@ func chainUnaryServerInterceptors(s *Server) { } else if len(interceptors) == 1 { chainedInt = interceptors[0] } else { - chainedInt = func(ctx context.Context, req interface{}, info *UnaryServerInfo, handler UnaryHandler) (interface{}, error) { - return interceptors[0](ctx, req, info, getChainUnaryHandler(interceptors, 0, info, handler)) - } + chainedInt = chainUnaryInterceptors(interceptors) } s.opts.unaryInt = chainedInt } -// getChainUnaryHandler recursively generate the chained UnaryHandler +func chainUnaryInterceptors(interceptors []UnaryServerInterceptor) UnaryServerInterceptor { + return func(ctx context.Context, req interface{}, info *UnaryServerInfo, handler UnaryHandler) (interface{}, error) { + return interceptors[0](ctx, req, info, getChainUnaryHandler(interceptors, 0, info, handler)) + } +} + func getChainUnaryHandler(interceptors []UnaryServerInterceptor, curr int, info *UnaryServerInfo, finalHandler UnaryHandler) UnaryHandler { if curr == len(interceptors)-1 { return finalHandler } - return func(ctx context.Context, req interface{}) (interface{}, error) { return interceptors[curr+1](ctx, req, info, getChainUnaryHandler(interceptors, curr+1, info, finalHandler)) } } func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.Stream, info *serviceInfo, md *MethodDesc, trInfo *traceInfo) (err error) { - sh := s.opts.statsHandler - if sh != nil || trInfo != nil || channelz.IsOn() { + shs := s.opts.statsHandlers + if len(shs) != 0 || trInfo != nil || channelz.IsOn() { if channelz.IsOn() { s.incrCallsStarted() } var statsBegin *stats.Begin - if sh != nil { + for _, sh := range shs { beginTime := time.Now() statsBegin = &stats.Begin{ - BeginTime: beginTime, + BeginTime: beginTime, + IsClientStream: false, + IsServerStream: false, } sh.HandleRPC(stream.Context(), statsBegin) } @@ -1095,7 +1193,7 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport. trInfo.tr.Finish() } - if sh != nil { + for _, sh := range shs { end := &stats.End{ BeginTime: statsBegin.BeginTime, EndTime: time.Now(), @@ -1115,9 +1213,16 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport. } }() } - - binlog := binarylog.GetMethodLogger(stream.Method()) - if binlog != nil { + var binlogs []binarylog.MethodLogger + if ml := binarylog.GetMethodLogger(stream.Method()); ml != nil { + binlogs = append(binlogs, ml) + } + if s.opts.binaryLogger != nil { + if ml := s.opts.binaryLogger.GetMethodLogger(stream.Method()); ml != nil { + binlogs = append(binlogs, ml) + } + } + if len(binlogs) != 0 { ctx := stream.Context() md, _ := metadata.FromIncomingContext(ctx) logEntry := &binarylog.ClientHeader{ @@ -1137,7 +1242,9 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport. if peer, ok := peer.FromContext(ctx); ok { logEntry.PeerAddr = peer.Addr } - binlog.Log(logEntry) + for _, binlog := range binlogs { + binlog.Log(ctx, logEntry) + } } // comp and cp are used for compression. decomp and dc are used for @@ -1147,6 +1254,7 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport. var comp, decomp encoding.Compressor var cp Compressor var dc Decompressor + var sendCompressorName string // If dc is set and matches the stream's compression, use it. Otherwise, try // to find a matching registered compressor for decomp. @@ -1167,23 +1275,29 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport. // NOTE: this needs to be ahead of all handling, https://github.com/grpc/grpc-go/issues/686. if s.opts.cp != nil { cp = s.opts.cp - stream.SetSendCompress(cp.Type()) + sendCompressorName = cp.Type() } else if rc := stream.RecvCompress(); rc != "" && rc != encoding.Identity { // Legacy compressor not specified; attempt to respond with same encoding. comp = encoding.GetCompressor(rc) if comp != nil { - stream.SetSendCompress(rc) + sendCompressorName = comp.Name() + } + } + + if sendCompressorName != "" { + if err := stream.SetSendCompress(sendCompressorName); err != nil { + return status.Errorf(codes.Internal, "grpc: failed to set send compressor: %v", err) } } var payInfo *payloadInfo - if sh != nil || binlog != nil { + if len(shs) != 0 || len(binlogs) != 0 { payInfo = &payloadInfo{} } d, err := recvAndDecompress(&parser{r: stream}, stream, dc, s.opts.maxReceiveMessageSize, payInfo, decomp) if err != nil { if e := t.WriteStatus(stream, status.Convert(err)); e != nil { - channelz.Warningf(logger, s.channelzID, "grpc: Server.processUnaryRPC failed to write status %v", e) + channelz.Warningf(logger, s.channelzID, "grpc: Server.processUnaryRPC failed to write status: %v", e) } return err } @@ -1194,19 +1308,23 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport. if err := s.getCodec(stream.ContentSubtype()).Unmarshal(d, v); err != nil { return status.Errorf(codes.Internal, "grpc: error unmarshalling request: %v", err) } - if sh != nil { + for _, sh := range shs { sh.HandleRPC(stream.Context(), &stats.InPayload{ - RecvTime: time.Now(), - Payload: v, - WireLength: payInfo.wireLength + headerLen, - Data: d, - Length: len(d), + RecvTime: time.Now(), + Payload: v, + Length: len(d), + WireLength: payInfo.compressedLength + headerLen, + CompressedLength: payInfo.compressedLength, + Data: d, }) } - if binlog != nil { - binlog.Log(&binarylog.ClientMessage{ + if len(binlogs) != 0 { + cm := &binarylog.ClientMessage{ Message: d, - }) + } + for _, binlog := range binlogs { + binlog.Log(stream.Context(), cm) + } } if trInfo != nil { trInfo.tr.LazyLog(&payload{sent: false, msg: v}, true) @@ -1218,9 +1336,10 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport. if appErr != nil { appStatus, ok := status.FromError(appErr) if !ok { - // Convert appErr if it is not a grpc status error. - appErr = status.Error(codes.Unknown, appErr.Error()) - appStatus, _ = status.FromError(appErr) + // Convert non-status application error to a status error with code + // Unknown, but handle context errors specifically. + appStatus = status.FromContextError(appErr) + appErr = appStatus.Err() } if trInfo != nil { trInfo.tr.LazyLog(stringer(appStatus.Message()), true) @@ -1229,18 +1348,24 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport. if e := t.WriteStatus(stream, appStatus); e != nil { channelz.Warningf(logger, s.channelzID, "grpc: Server.processUnaryRPC failed to write status: %v", e) } - if binlog != nil { + if len(binlogs) != 0 { if h, _ := stream.Header(); h.Len() > 0 { // Only log serverHeader if there was header. Otherwise it can // be trailer only. - binlog.Log(&binarylog.ServerHeader{ + sh := &binarylog.ServerHeader{ Header: h, - }) + } + for _, binlog := range binlogs { + binlog.Log(stream.Context(), sh) + } } - binlog.Log(&binarylog.ServerTrailer{ + st := &binarylog.ServerTrailer{ Trailer: stream.Trailer(), Err: appErr, - }) + } + for _, binlog := range binlogs { + binlog.Log(stream.Context(), st) + } } return appErr } @@ -1249,6 +1374,11 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport. } opts := &transport.Options{Last: true} + // Server handler could have set new compressor by calling SetSendCompressor. + // In case it is set, we need to use it for compressing outbound message. + if stream.SendCompress() != sendCompressorName { + comp = encoding.GetCompressor(stream.SendCompress()) + } if err := s.sendResponse(t, stream, reply, cp, opts, comp); err != nil { if err == io.EOF { // The entire stream is done (for unary RPC only). @@ -1266,26 +1396,34 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport. panic(fmt.Sprintf("grpc: Unexpected error (%T) from sendResponse: %v", st, st)) } } - if binlog != nil { + if len(binlogs) != 0 { h, _ := stream.Header() - binlog.Log(&binarylog.ServerHeader{ + sh := &binarylog.ServerHeader{ Header: h, - }) - binlog.Log(&binarylog.ServerTrailer{ + } + st := &binarylog.ServerTrailer{ Trailer: stream.Trailer(), Err: appErr, - }) + } + for _, binlog := range binlogs { + binlog.Log(stream.Context(), sh) + binlog.Log(stream.Context(), st) + } } return err } - if binlog != nil { + if len(binlogs) != 0 { h, _ := stream.Header() - binlog.Log(&binarylog.ServerHeader{ + sh := &binarylog.ServerHeader{ Header: h, - }) - binlog.Log(&binarylog.ServerMessage{ + } + sm := &binarylog.ServerMessage{ Message: reply, - }) + } + for _, binlog := range binlogs { + binlog.Log(stream.Context(), sh) + binlog.Log(stream.Context(), sm) + } } if channelz.IsOn() { t.IncrMsgSent() @@ -1296,14 +1434,16 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport. // TODO: Should we be logging if writing status failed here, like above? // Should the logging be in WriteStatus? Should we ignore the WriteStatus // error or allow the stats handler to see it? - err = t.WriteStatus(stream, statusOK) - if binlog != nil { - binlog.Log(&binarylog.ServerTrailer{ + if len(binlogs) != 0 { + st := &binarylog.ServerTrailer{ Trailer: stream.Trailer(), Err: appErr, - }) + } + for _, binlog := range binlogs { + binlog.Log(stream.Context(), st) + } } - return err + return t.WriteStatus(stream, statusOK) } // chainStreamServerInterceptors chains all stream server interceptors into one. @@ -1321,22 +1461,24 @@ func chainStreamServerInterceptors(s *Server) { } else if len(interceptors) == 1 { chainedInt = interceptors[0] } else { - chainedInt = func(srv interface{}, ss ServerStream, info *StreamServerInfo, handler StreamHandler) error { - return interceptors[0](srv, ss, info, getChainStreamHandler(interceptors, 0, info, handler)) - } + chainedInt = chainStreamInterceptors(interceptors) } s.opts.streamInt = chainedInt } -// getChainStreamHandler recursively generate the chained StreamHandler +func chainStreamInterceptors(interceptors []StreamServerInterceptor) StreamServerInterceptor { + return func(srv interface{}, ss ServerStream, info *StreamServerInfo, handler StreamHandler) error { + return interceptors[0](srv, ss, info, getChainStreamHandler(interceptors, 0, info, handler)) + } +} + func getChainStreamHandler(interceptors []StreamServerInterceptor, curr int, info *StreamServerInfo, finalHandler StreamHandler) StreamHandler { if curr == len(interceptors)-1 { return finalHandler } - - return func(srv interface{}, ss ServerStream) error { - return interceptors[curr+1](srv, ss, info, getChainStreamHandler(interceptors, curr+1, info, finalHandler)) + return func(srv interface{}, stream ServerStream) error { + return interceptors[curr+1](srv, stream, info, getChainStreamHandler(interceptors, curr+1, info, finalHandler)) } } @@ -1344,14 +1486,18 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp if channelz.IsOn() { s.incrCallsStarted() } - sh := s.opts.statsHandler + shs := s.opts.statsHandlers var statsBegin *stats.Begin - if sh != nil { + if len(shs) != 0 { beginTime := time.Now() statsBegin = &stats.Begin{ - BeginTime: beginTime, + BeginTime: beginTime, + IsClientStream: sd.ClientStreams, + IsServerStream: sd.ServerStreams, + } + for _, sh := range shs { + sh.HandleRPC(stream.Context(), statsBegin) } - sh.HandleRPC(stream.Context(), statsBegin) } ctx := NewContextWithServerTransportStream(stream.Context(), stream) ss := &serverStream{ @@ -1363,10 +1509,10 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp maxReceiveMessageSize: s.opts.maxReceiveMessageSize, maxSendMessageSize: s.opts.maxSendMessageSize, trInfo: trInfo, - statsHandler: sh, + statsHandler: shs, } - if sh != nil || trInfo != nil || channelz.IsOn() { + if len(shs) != 0 || trInfo != nil || channelz.IsOn() { // See comment in processUnaryRPC on defers. defer func() { if trInfo != nil { @@ -1380,7 +1526,7 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp ss.mu.Unlock() } - if sh != nil { + if len(shs) != 0 { end := &stats.End{ BeginTime: statsBegin.BeginTime, EndTime: time.Now(), @@ -1388,7 +1534,9 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp if err != nil && err != io.EOF { end.Error = toRPCErr(err) } - sh.HandleRPC(stream.Context(), end) + for _, sh := range shs { + sh.HandleRPC(stream.Context(), end) + } } if channelz.IsOn() { @@ -1401,8 +1549,15 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp }() } - ss.binlog = binarylog.GetMethodLogger(stream.Method()) - if ss.binlog != nil { + if ml := binarylog.GetMethodLogger(stream.Method()); ml != nil { + ss.binlogs = append(ss.binlogs, ml) + } + if s.opts.binaryLogger != nil { + if ml := s.opts.binaryLogger.GetMethodLogger(stream.Method()); ml != nil { + ss.binlogs = append(ss.binlogs, ml) + } + } + if len(ss.binlogs) != 0 { md, _ := metadata.FromIncomingContext(ctx) logEntry := &binarylog.ClientHeader{ Header: md, @@ -1421,7 +1576,9 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp if peer, ok := peer.FromContext(ss.Context()); ok { logEntry.PeerAddr = peer.Addr } - ss.binlog.Log(logEntry) + for _, binlog := range ss.binlogs { + binlog.Log(stream.Context(), logEntry) + } } // If dc is set and matches the stream's compression, use it. Otherwise, try @@ -1443,15 +1600,23 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp // NOTE: this needs to be ahead of all handling, https://github.com/grpc/grpc-go/issues/686. if s.opts.cp != nil { ss.cp = s.opts.cp - stream.SetSendCompress(s.opts.cp.Type()) + ss.sendCompressorName = s.opts.cp.Type() } else if rc := stream.RecvCompress(); rc != "" && rc != encoding.Identity { // Legacy compressor not specified; attempt to respond with same encoding. ss.comp = encoding.GetCompressor(rc) if ss.comp != nil { - stream.SetSendCompress(rc) + ss.sendCompressorName = rc + } + } + + if ss.sendCompressorName != "" { + if err := stream.SetSendCompress(ss.sendCompressorName); err != nil { + return status.Errorf(codes.Internal, "grpc: failed to set send compressor: %v", err) } } + ss.ctx = newContextWithRPCInfo(ss.ctx, false, ss.codec, ss.cp, ss.comp) + if trInfo != nil { trInfo.tr.LazyLog(&trInfo.firstLine, false) } @@ -1473,7 +1638,9 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp if appErr != nil { appStatus, ok := status.FromError(appErr) if !ok { - appStatus = status.New(codes.Unknown, appErr.Error()) + // Convert non-status application error to a status error with code + // Unknown, but handle context errors specifically. + appStatus = status.FromContextError(appErr) appErr = appStatus.Err() } if trInfo != nil { @@ -1482,13 +1649,16 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp ss.trInfo.tr.SetError() ss.mu.Unlock() } - t.WriteStatus(ss.s, appStatus) - if ss.binlog != nil { - ss.binlog.Log(&binarylog.ServerTrailer{ + if len(ss.binlogs) != 0 { + st := &binarylog.ServerTrailer{ Trailer: ss.s.Trailer(), Err: appErr, - }) + } + for _, binlog := range ss.binlogs { + binlog.Log(stream.Context(), st) + } } + t.WriteStatus(ss.s, appStatus) // TODO: Should we log an error from WriteStatus here and below? return appErr } @@ -1497,14 +1667,16 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp ss.trInfo.tr.LazyLog(stringer("OK"), false) ss.mu.Unlock() } - err = t.WriteStatus(ss.s, statusOK) - if ss.binlog != nil { - ss.binlog.Log(&binarylog.ServerTrailer{ + if len(ss.binlogs) != 0 { + st := &binarylog.ServerTrailer{ Trailer: ss.s.Trailer(), Err: appErr, - }) + } + for _, binlog := range ss.binlogs { + binlog.Log(stream.Context(), st) + } } - return err + return t.WriteStatus(ss.s, statusOK) } func (s *Server) handleStream(t transport.ServerTransport, stream *transport.Stream, trInfo *traceInfo) { @@ -1519,7 +1691,7 @@ func (s *Server) handleStream(t transport.ServerTransport, stream *transport.Str trInfo.tr.SetError() } errDesc := fmt.Sprintf("malformed method name: %q", stream.Method()) - if err := t.WriteStatus(stream, status.New(codes.ResourceExhausted, errDesc)); err != nil { + if err := t.WriteStatus(stream, status.New(codes.Unimplemented, errDesc)); err != nil { if trInfo != nil { trInfo.tr.LazyLog(&fmtStringer{"%v", []interface{}{err}}, true) trInfo.tr.SetError() @@ -1578,7 +1750,7 @@ type streamKey struct{} // NewContextWithServerTransportStream creates a new context from ctx and // attaches stream to it. // -// Experimental +// # Experimental // // Notice: This API is EXPERIMENTAL and may be changed or removed in a // later release. @@ -1593,7 +1765,7 @@ func NewContextWithServerTransportStream(ctx context.Context, stream ServerTrans // // See also NewContextWithServerTransportStream. // -// Experimental +// # Experimental // // Notice: This type is EXPERIMENTAL and may be changed or removed in a // later release. @@ -1608,7 +1780,7 @@ type ServerTransportStream interface { // ctx. Returns nil if the given context has no stream associated with it // (which implies it is not an RPC invocation context). // -// Experimental +// # Experimental // // Notice: This API is EXPERIMENTAL and may be changed or removed in a // later release. @@ -1630,16 +1802,12 @@ func (s *Server) Stop() { s.done.Fire() }() - s.channelzRemoveOnce.Do(func() { - if channelz.IsOn() { - channelz.RemoveEntry(s.channelzID) - } - }) + s.channelzRemoveOnce.Do(func() { channelz.RemoveEntry(s.channelzID) }) s.mu.Lock() listeners := s.lis s.lis = nil - st := s.conns + conns := s.conns s.conns = nil // interrupt GracefulStop if Stop and GracefulStop are called concurrently. s.cv.Broadcast() @@ -1648,8 +1816,10 @@ func (s *Server) Stop() { for lis := range listeners { lis.Close() } - for c := range st { - c.Close() + for _, cs := range conns { + for st := range cs { + st.Close(errors.New("Server.Stop called")) + } } if s.opts.numServerWorkers > 0 { s.stopServerWorkers() @@ -1670,11 +1840,7 @@ func (s *Server) GracefulStop() { s.quit.Fire() defer s.done.Fire() - s.channelzRemoveOnce.Do(func() { - if channelz.IsOn() { - channelz.RemoveEntry(s.channelzID) - } - }) + s.channelzRemoveOnce.Do(func() { channelz.RemoveEntry(s.channelzID) }) s.mu.Lock() if s.conns == nil { s.mu.Unlock() @@ -1686,8 +1852,10 @@ func (s *Server) GracefulStop() { } s.lis = nil if !s.drain { - for st := range s.conns { - st.Drain() + for _, conns := range s.conns { + for st := range conns { + st.Drain("graceful_stop") + } } s.drain = true } @@ -1725,12 +1893,26 @@ func (s *Server) getCodec(contentSubtype string) baseCodec { return codec } -// SetHeader sets the header metadata. -// When called multiple times, all the provided metadata will be merged. -// All the metadata will be sent out when one of the following happens: -// - grpc.SendHeader() is called; -// - The first response is sent out; -// - An RPC status is sent out (error or success). +// SetHeader sets the header metadata to be sent from the server to the client. +// The context provided must be the context passed to the server's handler. +// +// Streaming RPCs should prefer the SetHeader method of the ServerStream. +// +// When called multiple times, all the provided metadata will be merged. All +// the metadata will be sent out when one of the following happens: +// +// - grpc.SendHeader is called, or for streaming handlers, stream.SendHeader. +// - The first response message is sent. For unary handlers, this occurs when +// the handler returns; for streaming handlers, this can happen when stream's +// SendMsg method is called. +// - An RPC status is sent out (error or success). This occurs when the handler +// returns. +// +// SetHeader will fail if called after any of the events above. +// +// The error returned is compatible with the status package. However, the +// status code will often not match the RPC status as seen by the client +// application, and therefore, should not be relied upon for this purpose. func SetHeader(ctx context.Context, md metadata.MD) error { if md.Len() == 0 { return nil @@ -1742,8 +1924,14 @@ func SetHeader(ctx context.Context, md metadata.MD) error { return stream.SetHeader(md) } -// SendHeader sends header metadata. It may be called at most once. -// The provided md and headers set by SetHeader() will be sent. +// SendHeader sends header metadata. It may be called at most once, and may not +// be called after any event that causes headers to be sent (see SetHeader for +// a complete list). The provided md and headers set by SetHeader() will be +// sent. +// +// The error returned is compatible with the status package. However, the +// status code will often not match the RPC status as seen by the client +// application, and therefore, should not be relied upon for this purpose. func SendHeader(ctx context.Context, md metadata.MD) error { stream := ServerTransportStreamFromContext(ctx) if stream == nil { @@ -1755,8 +1943,66 @@ func SendHeader(ctx context.Context, md metadata.MD) error { return nil } +// SetSendCompressor sets a compressor for outbound messages from the server. +// It must not be called after any event that causes headers to be sent +// (see ServerStream.SetHeader for the complete list). Provided compressor is +// used when below conditions are met: +// +// - compressor is registered via encoding.RegisterCompressor +// - compressor name must exist in the client advertised compressor names +// sent in grpc-accept-encoding header. Use ClientSupportedCompressors to +// get client supported compressor names. +// +// The context provided must be the context passed to the server's handler. +// It must be noted that compressor name encoding.Identity disables the +// outbound compression. +// By default, server messages will be sent using the same compressor with +// which request messages were sent. +// +// It is not safe to call SetSendCompressor concurrently with SendHeader and +// SendMsg. +// +// # Experimental +// +// Notice: This function is EXPERIMENTAL and may be changed or removed in a +// later release. +func SetSendCompressor(ctx context.Context, name string) error { + stream, ok := ServerTransportStreamFromContext(ctx).(*transport.Stream) + if !ok || stream == nil { + return fmt.Errorf("failed to fetch the stream from the given context") + } + + if err := validateSendCompressor(name, stream.ClientAdvertisedCompressors()); err != nil { + return fmt.Errorf("unable to set send compressor: %w", err) + } + + return stream.SetSendCompress(name) +} + +// ClientSupportedCompressors returns compressor names advertised by the client +// via grpc-accept-encoding header. +// +// The context provided must be the context passed to the server's handler. +// +// # Experimental +// +// Notice: This function is EXPERIMENTAL and may be changed or removed in a +// later release. +func ClientSupportedCompressors(ctx context.Context) ([]string, error) { + stream, ok := ServerTransportStreamFromContext(ctx).(*transport.Stream) + if !ok || stream == nil { + return nil, fmt.Errorf("failed to fetch the stream from the given context %v", ctx) + } + + return strings.Split(stream.ClientAdvertisedCompressors(), ","), nil +} + // SetTrailer sets the trailer metadata that will be sent when an RPC returns. // When called more than once, all the provided metadata will be merged. +// +// The error returned is compatible with the status package. However, the +// status code will often not match the RPC status as seen by the client +// application, and therefore, should not be relied upon for this purpose. func SetTrailer(ctx context.Context, md metadata.MD) error { if md.Len() == 0 { return nil @@ -1785,3 +2031,51 @@ type channelzServer struct { func (c *channelzServer) ChannelzMetric() *channelz.ServerInternalMetric { return c.s.channelzMetric() } + +// validateSendCompressor returns an error when given compressor name cannot be +// handled by the server or the client based on the advertised compressors. +func validateSendCompressor(name, clientCompressors string) error { + if name == encoding.Identity { + return nil + } + + if !grpcutil.IsCompressorNameRegistered(name) { + return fmt.Errorf("compressor not registered %q", name) + } + + for _, c := range strings.Split(clientCompressors, ",") { + if c == name { + return nil // found match + } + } + return fmt.Errorf("client does not support compressor %q", name) +} + +// atomicSemaphore implements a blocking, counting semaphore. acquire should be +// called synchronously; release may be called asynchronously. +type atomicSemaphore struct { + n int64 + wait chan struct{} +} + +func (q *atomicSemaphore) acquire() { + if atomic.AddInt64(&q.n, -1) < 0 { + // We ran out of quota. Block until a release happens. + <-q.wait + } +} + +func (q *atomicSemaphore) release() { + // N.B. the "<= 0" check below should allow for this to work with multiple + // concurrent calls to acquire, but also note that with synchronous calls to + // acquire, as our system does, n will never be less than -1. There are + // fairness issues (queuing) to consider if this was to be generalized. + if atomic.AddInt64(&q.n, 1) <= 0 { + // An acquire was waiting on us. Unblock it. + q.wait <- struct{}{} + } +} + +func newHandlerQuota(n uint32) *atomicSemaphore { + return &atomicSemaphore{n: int64(n), wait: make(chan struct{}, 1)} +} diff --git a/vendor/google.golang.org/grpc/service_config.go b/vendor/google.golang.org/grpc/service_config.go index 22c4240cf7e..0df11fc0988 100644 --- a/vendor/google.golang.org/grpc/service_config.go +++ b/vendor/google.golang.org/grpc/service_config.go @@ -23,8 +23,6 @@ import ( "errors" "fmt" "reflect" - "strconv" - "strings" "time" "google.golang.org/grpc/codes" @@ -57,10 +55,9 @@ type lbConfig struct { type ServiceConfig struct { serviceconfig.Config - // LB is the load balancer the service providers recommends. The balancer - // specified via grpc.WithBalancerName will override this. This is deprecated; - // lbConfigs is preferred. If lbConfig and LB are both present, lbConfig - // will be used. + // LB is the load balancer the service providers recommends. This is + // deprecated; lbConfigs is preferred. If lbConfig and LB are both present, + // lbConfig will be used. LB *string // lbConfig is the service config's load balancing configuration. If @@ -107,8 +104,8 @@ type healthCheckConfig struct { type jsonRetryPolicy struct { MaxAttempts int - InitialBackoff string - MaxBackoff string + InitialBackoff internalserviceconfig.Duration + MaxBackoff internalserviceconfig.Duration BackoffMultiplier float64 RetryableStatusCodes []codes.Code } @@ -130,50 +127,6 @@ type retryThrottlingPolicy struct { TokenRatio float64 } -func parseDuration(s *string) (*time.Duration, error) { - if s == nil { - return nil, nil - } - if !strings.HasSuffix(*s, "s") { - return nil, fmt.Errorf("malformed duration %q", *s) - } - ss := strings.SplitN((*s)[:len(*s)-1], ".", 3) - if len(ss) > 2 { - return nil, fmt.Errorf("malformed duration %q", *s) - } - // hasDigits is set if either the whole or fractional part of the number is - // present, since both are optional but one is required. - hasDigits := false - var d time.Duration - if len(ss[0]) > 0 { - i, err := strconv.ParseInt(ss[0], 10, 32) - if err != nil { - return nil, fmt.Errorf("malformed duration %q: %v", *s, err) - } - d = time.Duration(i) * time.Second - hasDigits = true - } - if len(ss) == 2 && len(ss[1]) > 0 { - if len(ss[1]) > 9 { - return nil, fmt.Errorf("malformed duration %q", *s) - } - f, err := strconv.ParseInt(ss[1], 10, 64) - if err != nil { - return nil, fmt.Errorf("malformed duration %q: %v", *s, err) - } - for i := 9; i > len(ss[1]); i-- { - f *= 10 - } - d += time.Duration(f) - hasDigits = true - } - if !hasDigits { - return nil, fmt.Errorf("malformed duration %q", *s) - } - - return &d, nil -} - type jsonName struct { Service string Method string @@ -202,7 +155,7 @@ func (j jsonName) generatePath() (string, error) { type jsonMC struct { Name *[]jsonName WaitForReady *bool - Timeout *string + Timeout *internalserviceconfig.Duration MaxRequestMessageBytes *int64 MaxResponseMessageBytes *int64 RetryPolicy *jsonRetryPolicy @@ -218,7 +171,7 @@ type jsonSC struct { } func init() { - internal.ParseServiceConfigForTesting = parseServiceConfig + internal.ParseServiceConfig = parseServiceConfig } func parseServiceConfig(js string) *serviceconfig.ParseResult { if len(js) == 0 { @@ -227,7 +180,7 @@ func parseServiceConfig(js string) *serviceconfig.ParseResult { var rsc jsonSC err := json.Unmarshal([]byte(js), &rsc) if err != nil { - logger.Warningf("grpc: parseServiceConfig error unmarshaling %s due to %v", js, err) + logger.Warningf("grpc: unmarshaling service config %s: %v", js, err) return &serviceconfig.ParseResult{Err: err} } sc := ServiceConfig{ @@ -253,18 +206,13 @@ func parseServiceConfig(js string) *serviceconfig.ParseResult { if m.Name == nil { continue } - d, err := parseDuration(m.Timeout) - if err != nil { - logger.Warningf("grpc: parseServiceConfig error unmarshaling %s due to %v", js, err) - return &serviceconfig.ParseResult{Err: err} - } mc := MethodConfig{ WaitForReady: m.WaitForReady, - Timeout: d, + Timeout: (*time.Duration)(m.Timeout), } if mc.RetryPolicy, err = convertRetryPolicy(m.RetryPolicy); err != nil { - logger.Warningf("grpc: parseServiceConfig error unmarshaling %s due to %v", js, err) + logger.Warningf("grpc: unmarshaling service config %s: %v", js, err) return &serviceconfig.ParseResult{Err: err} } if m.MaxRequestMessageBytes != nil { @@ -284,13 +232,13 @@ func parseServiceConfig(js string) *serviceconfig.ParseResult { for i, n := range *m.Name { path, err := n.generatePath() if err != nil { - logger.Warningf("grpc: parseServiceConfig error unmarshaling %s due to methodConfig[%d]: %v", js, i, err) + logger.Warningf("grpc: error unmarshaling service config %s due to methodConfig[%d]: %v", js, i, err) return &serviceconfig.ParseResult{Err: err} } if _, ok := paths[path]; ok { err = errDuplicatedName - logger.Warningf("grpc: parseServiceConfig error unmarshaling %s due to methodConfig[%d]: %v", js, i, err) + logger.Warningf("grpc: error unmarshaling service config %s due to methodConfig[%d]: %v", js, i, err) return &serviceconfig.ParseResult{Err: err} } paths[path] = struct{}{} @@ -313,18 +261,10 @@ func convertRetryPolicy(jrp *jsonRetryPolicy) (p *internalserviceconfig.RetryPol if jrp == nil { return nil, nil } - ib, err := parseDuration(&jrp.InitialBackoff) - if err != nil { - return nil, err - } - mb, err := parseDuration(&jrp.MaxBackoff) - if err != nil { - return nil, err - } if jrp.MaxAttempts <= 1 || - *ib <= 0 || - *mb <= 0 || + jrp.InitialBackoff <= 0 || + jrp.MaxBackoff <= 0 || jrp.BackoffMultiplier <= 0 || len(jrp.RetryableStatusCodes) == 0 { logger.Warningf("grpc: ignoring retry policy %v due to illegal configuration", jrp) @@ -333,8 +273,8 @@ func convertRetryPolicy(jrp *jsonRetryPolicy) (p *internalserviceconfig.RetryPol rp := &internalserviceconfig.RetryPolicy{ MaxAttempts: jrp.MaxAttempts, - InitialBackoff: *ib, - MaxBackoff: *mb, + InitialBackoff: time.Duration(jrp.InitialBackoff), + MaxBackoff: time.Duration(jrp.MaxBackoff), BackoffMultiplier: jrp.BackoffMultiplier, RetryableStatusCodes: make(map[codes.Code]bool), } @@ -381,6 +321,9 @@ func init() { // // If any of them is NOT *ServiceConfig, return false. func equalServiceConfig(a, b serviceconfig.Config) bool { + if a == nil && b == nil { + return true + } aa, ok := a.(*ServiceConfig) if !ok { return false diff --git a/vendor/google.golang.org/grpc/serviceconfig/serviceconfig.go b/vendor/google.golang.org/grpc/serviceconfig/serviceconfig.go index 73a2f926613..35e7a20a04b 100644 --- a/vendor/google.golang.org/grpc/serviceconfig/serviceconfig.go +++ b/vendor/google.golang.org/grpc/serviceconfig/serviceconfig.go @@ -19,7 +19,7 @@ // Package serviceconfig defines types and methods for operating on gRPC // service configs. // -// Experimental +// # Experimental // // Notice: This package is EXPERIMENTAL and may be changed or removed in a // later release. diff --git a/vendor/google.golang.org/grpc/stats/stats.go b/vendor/google.golang.org/grpc/stats/stats.go index 63e476ee7ff..7a552a9b787 100644 --- a/vendor/google.golang.org/grpc/stats/stats.go +++ b/vendor/google.golang.org/grpc/stats/stats.go @@ -36,15 +36,22 @@ type RPCStats interface { IsClient() bool } -// Begin contains stats when an RPC begins. +// Begin contains stats when an RPC attempt begins. // FailFast is only valid if this Begin is from client side. type Begin struct { // Client is true if this Begin is from client side. Client bool - // BeginTime is the time when the RPC begins. + // BeginTime is the time when the RPC attempt begins. BeginTime time.Time // FailFast indicates if this RPC is failfast. FailFast bool + // IsClientStream indicates whether the RPC is a client streaming RPC. + IsClientStream bool + // IsServerStream indicates whether the RPC is a server streaming RPC. + IsServerStream bool + // IsTransparentRetryAttempt indicates whether this attempt was initiated + // due to transparently retrying a previous attempt. + IsTransparentRetryAttempt bool } // IsClient indicates if the stats information is from client side. @@ -60,10 +67,18 @@ type InPayload struct { Payload interface{} // Data is the serialized message payload. Data []byte - // Length is the length of uncompressed data. + + // Length is the size of the uncompressed payload data. Does not include any + // framing (gRPC or HTTP/2). Length int - // WireLength is the length of data on wire (compressed, signed, encrypted). + // CompressedLength is the size of the compressed payload data. Does not + // include any framing (gRPC or HTTP/2). Same as Length if compression not + // enabled. + CompressedLength int + // WireLength is the size of the compressed payload data plus gRPC framing. + // Does not include HTTP/2 framing. WireLength int + // RecvTime is the time when the payload is received. RecvTime time.Time } @@ -122,9 +137,15 @@ type OutPayload struct { Payload interface{} // Data is the serialized message payload. Data []byte - // Length is the length of uncompressed data. + // Length is the size of the uncompressed payload data. Does not include any + // framing (gRPC or HTTP/2). Length int - // WireLength is the length of data on wire (compressed, signed, encrypted). + // CompressedLength is the size of the compressed payload data. Does not + // include any framing (gRPC or HTTP/2). Same as Length if compression not + // enabled. + CompressedLength int + // WireLength is the size of the compressed payload data plus gRPC framing. + // Does not include HTTP/2 framing. WireLength int // SentTime is the time when the payload is sent. SentTime time.Time diff --git a/vendor/google.golang.org/grpc/status/status.go b/vendor/google.golang.org/grpc/status/status.go index 54d187186b8..bcf2e4d81be 100644 --- a/vendor/google.golang.org/grpc/status/status.go +++ b/vendor/google.golang.org/grpc/status/status.go @@ -29,6 +29,7 @@ package status import ( "context" + "errors" "fmt" spb "google.golang.org/genproto/googleapis/rpc/status" @@ -73,19 +74,52 @@ func FromProto(s *spb.Status) *Status { return status.FromProto(s) } -// FromError returns a Status representing err if it was produced by this -// package or has a method `GRPCStatus() *Status`. -// If err is nil, a Status is returned with codes.OK and no message. -// Otherwise, ok is false and a Status is returned with codes.Unknown and -// the original error message. +// FromError returns a Status representation of err. +// +// - If err was produced by this package or implements the method `GRPCStatus() +// *Status` and `GRPCStatus()` does not return nil, or if err wraps a type +// satisfying this, the Status from `GRPCStatus()` is returned. For wrapped +// errors, the message returned contains the entire err.Error() text and not +// just the wrapped status. In that case, ok is true. +// +// - If err is nil, a Status is returned with codes.OK and no message, and ok +// is true. +// +// - If err implements the method `GRPCStatus() *Status` and `GRPCStatus()` +// returns nil (which maps to Codes.OK), or if err wraps a type +// satisfying this, a Status is returned with codes.Unknown and err's +// Error() message, and ok is false. +// +// - Otherwise, err is an error not compatible with this package. In this +// case, a Status is returned with codes.Unknown and err's Error() message, +// and ok is false. func FromError(err error) (s *Status, ok bool) { if err == nil { return nil, true } - if se, ok := err.(interface { - GRPCStatus() *Status - }); ok { - return se.GRPCStatus(), true + type grpcstatus interface{ GRPCStatus() *Status } + if gs, ok := err.(grpcstatus); ok { + if gs.GRPCStatus() == nil { + // Error has status nil, which maps to codes.OK. There + // is no sensible behavior for this, so we turn it into + // an error with codes.Unknown and discard the existing + // status. + return New(codes.Unknown, err.Error()), false + } + return gs.GRPCStatus(), true + } + var gs grpcstatus + if errors.As(err, &gs) { + if gs.GRPCStatus() == nil { + // Error wraps an error that has status nil, which maps + // to codes.OK. There is no sensible behavior for this, + // so we turn it into an error with codes.Unknown and + // discard the existing status. + return New(codes.Unknown, err.Error()), false + } + p := gs.GRPCStatus().Proto() + p.Message = err.Error() + return status.FromProto(p), true } return New(codes.Unknown, err.Error()), false } @@ -97,33 +131,30 @@ func Convert(err error) *Status { return s } -// Code returns the Code of the error if it is a Status error, codes.OK if err -// is nil, or codes.Unknown otherwise. +// Code returns the Code of the error if it is a Status error or if it wraps a +// Status error. If that is not the case, it returns codes.OK if err is nil, or +// codes.Unknown otherwise. func Code(err error) codes.Code { // Don't use FromError to avoid allocation of OK status. if err == nil { return codes.OK } - if se, ok := err.(interface { - GRPCStatus() *Status - }); ok { - return se.GRPCStatus().Code() - } - return codes.Unknown + + return Convert(err).Code() } -// FromContextError converts a context error into a Status. It returns a -// Status with codes.OK if err is nil, or a Status with codes.Unknown if err is -// non-nil and not a context error. +// FromContextError converts a context error or wrapped context error into a +// Status. It returns a Status with codes.OK if err is nil, or a Status with +// codes.Unknown if err is non-nil and not a context error. func FromContextError(err error) *Status { - switch err { - case nil: + if err == nil { return nil - case context.DeadlineExceeded: + } + if errors.Is(err, context.DeadlineExceeded) { return New(codes.DeadlineExceeded, err.Error()) - case context.Canceled: + } + if errors.Is(err, context.Canceled) { return New(codes.Canceled, err.Error()) - default: - return New(codes.Unknown, err.Error()) } + return New(codes.Unknown, err.Error()) } diff --git a/vendor/google.golang.org/grpc/stream.go b/vendor/google.golang.org/grpc/stream.go index eda1248d60c..10092685b22 100644 --- a/vendor/google.golang.org/grpc/stream.go +++ b/vendor/google.golang.org/grpc/stream.go @@ -36,8 +36,10 @@ import ( "google.golang.org/grpc/internal/channelz" "google.golang.org/grpc/internal/grpcrand" "google.golang.org/grpc/internal/grpcutil" + imetadata "google.golang.org/grpc/internal/metadata" iresolver "google.golang.org/grpc/internal/resolver" "google.golang.org/grpc/internal/serviceconfig" + istatus "google.golang.org/grpc/internal/status" "google.golang.org/grpc/internal/transport" "google.golang.org/grpc/metadata" "google.golang.org/grpc/peer" @@ -46,20 +48,28 @@ import ( ) // StreamHandler defines the handler called by gRPC server to complete the -// execution of a streaming RPC. If a StreamHandler returns an error, it -// should be produced by the status package, or else gRPC will use -// codes.Unknown as the status code and err.Error() as the status message -// of the RPC. +// execution of a streaming RPC. +// +// If a StreamHandler returns an error, it should either be produced by the +// status package, or be one of the context errors. Otherwise, gRPC will use +// codes.Unknown as the status code and err.Error() as the status message of the +// RPC. type StreamHandler func(srv interface{}, stream ServerStream) error -// StreamDesc represents a streaming RPC service's method specification. +// StreamDesc represents a streaming RPC service's method specification. Used +// on the server when registering services and on the client when initiating +// new streams. type StreamDesc struct { - StreamName string - Handler StreamHandler - - // At least one of these is true. - ServerStreams bool - ClientStreams bool + // StreamName and Handler are only used when registering handlers on a + // server. + StreamName string // the name of the method excluding the service + Handler StreamHandler // the handler called for the method + + // ServerStreams and ClientStreams are used for registering handlers on a + // server as well as defining RPC behavior when passed to NewClientStream + // and ClientConn.NewStream. At least one must be true. + ServerStreams bool // indicates the server can perform streaming sends + ClientStreams bool // indicates the client can perform streaming sends } // Stream defines the common interface a client or server stream has to satisfy. @@ -113,6 +123,9 @@ type ClientStream interface { // calling RecvMsg on the same stream at the same time, but it is not safe // to call SendMsg on the same stream in different goroutines. It is also // not safe to call CloseSend concurrently with SendMsg. + // + // It is not safe to modify the message after calling SendMsg. Tracing + // libraries and stats handlers may use the message lazily. SendMsg(m interface{}) error // RecvMsg blocks until it receives a message into m or the stream is // done. It returns io.EOF when the stream completes successfully. On @@ -131,17 +144,22 @@ type ClientStream interface { // To ensure resources are not leaked due to the stream returned, one of the following // actions must be performed: // -// 1. Call Close on the ClientConn. -// 2. Cancel the context provided. -// 3. Call RecvMsg until a non-nil error is returned. A protobuf-generated -// client-streaming RPC, for instance, might use the helper function -// CloseAndRecv (note that CloseSend does not Recv, therefore is not -// guaranteed to release all resources). -// 4. Receive a non-nil, non-io.EOF error from Header or SendMsg. +// 1. Call Close on the ClientConn. +// 2. Cancel the context provided. +// 3. Call RecvMsg until a non-nil error is returned. A protobuf-generated +// client-streaming RPC, for instance, might use the helper function +// CloseAndRecv (note that CloseSend does not Recv, therefore is not +// guaranteed to release all resources). +// 4. Receive a non-nil, non-io.EOF error from Header or SendMsg. // // If none of the above happen, a goroutine and a context will be leaked, and grpc // will not call the optionally-configured stats handler with a stats.End message. func (cc *ClientConn) NewStream(ctx context.Context, desc *StreamDesc, method string, opts ...CallOption) (ClientStream, error) { + if err := cc.idlenessMgr.onCallBegin(); err != nil { + return nil, err + } + defer cc.idlenessMgr.onCallEnd() + // allow interceptor to see all applicable call options, which means those // configured as defaults from dial option as well as per-call options opts = combine(cc.dopts.callOptions, opts) @@ -158,6 +176,20 @@ func NewClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, meth } func newClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, method string, opts ...CallOption) (_ ClientStream, err error) { + if md, added, ok := metadata.FromOutgoingContextRaw(ctx); ok { + // validate md + if err := imetadata.Validate(md); err != nil { + return nil, status.Error(codes.Internal, err.Error()) + } + // validate added + for _, kvs := range added { + for i := 0; i < len(kvs); i += 2 { + if err := imetadata.ValidatePair(kvs[i], kvs[i+1]); err != nil { + return nil, status.Error(codes.Internal, err.Error()) + } + } + } + } if channelz.IsOn() { cc.incrCallsStarted() defer func() { @@ -166,7 +198,6 @@ func newClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, meth } }() } - c := defaultCallInfo() // Provide an opportunity for the first RPC to see the first service config // provided by the resolver. if err := cc.waitForResolvedAddrs(ctx); err != nil { @@ -175,18 +206,47 @@ func newClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, meth var mc serviceconfig.MethodConfig var onCommit func() - rpcConfig, err := cc.safeConfigSelector.SelectConfig(iresolver.RPCInfo{Context: ctx, Method: method}) + var newStream = func(ctx context.Context, done func()) (iresolver.ClientStream, error) { + return newClientStreamWithParams(ctx, desc, cc, method, mc, onCommit, done, opts...) + } + + rpcInfo := iresolver.RPCInfo{Context: ctx, Method: method} + rpcConfig, err := cc.safeConfigSelector.SelectConfig(rpcInfo) if err != nil { - return nil, status.Convert(err).Err() + if st, ok := status.FromError(err); ok { + // Restrict the code to the list allowed by gRFC A54. + if istatus.IsRestrictedControlPlaneCode(st) { + err = status.Errorf(codes.Internal, "config selector returned illegal status: %v", err) + } + return nil, err + } + return nil, toRPCErr(err) } + if rpcConfig != nil { if rpcConfig.Context != nil { ctx = rpcConfig.Context } mc = rpcConfig.MethodConfig onCommit = rpcConfig.OnCommitted + if rpcConfig.Interceptor != nil { + rpcInfo.Context = nil + ns := newStream + newStream = func(ctx context.Context, done func()) (iresolver.ClientStream, error) { + cs, err := rpcConfig.Interceptor.NewStream(ctx, rpcInfo, done, ns) + if err != nil { + return nil, toRPCErr(err) + } + return cs, nil + } + } } + return newStream(ctx, func() {}) +} + +func newClientStreamWithParams(ctx context.Context, desc *StreamDesc, cc *ClientConn, method string, mc serviceconfig.MethodConfig, onCommit, doneFunc func(), opts ...CallOption) (_ iresolver.ClientStream, err error) { + c := defaultCallInfo() if mc.WaitForReady != nil { c.failFast = !*mc.WaitForReady } @@ -223,6 +283,7 @@ func newClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, meth Host: cc.authority, Method: method, ContentSubtype: c.contentSubtype, + DoneFunc: doneFunc, } // Set our outgoing compression according to the UseCompressor CallOption, if @@ -246,33 +307,6 @@ func newClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, meth if c.creds != nil { callHdr.Creds = c.creds } - var trInfo *traceInfo - if EnableTracing { - trInfo = &traceInfo{ - tr: trace.New("grpc.Sent."+methodFamily(method), method), - firstLine: firstLine{ - client: true, - }, - } - if deadline, ok := ctx.Deadline(); ok { - trInfo.firstLine.deadline = time.Until(deadline) - } - trInfo.tr.LazyLog(&trInfo.firstLine, false) - ctx = trace.NewContext(ctx, trInfo.tr) - } - ctx = newContextWithRPCInfo(ctx, c.failFast, c.codec, cp, comp) - sh := cc.dopts.copts.StatsHandler - var beginTime time.Time - if sh != nil { - ctx = sh.TagRPC(ctx, &stats.RPCTagInfo{FullMethodName: method, FailFast: c.failFast}) - beginTime = time.Now() - begin := &stats.Begin{ - Client: true, - BeginTime: beginTime, - FailFast: c.failFast, - } - sh.HandleRPC(ctx, begin) - } cs := &clientStream{ callHdr: callHdr, @@ -286,29 +320,41 @@ func newClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, meth cp: cp, comp: comp, cancel: cancel, - beginTime: beginTime, firstAttempt: true, onCommit: onCommit, } if !cc.dopts.disableRetry { cs.retryThrottler = cc.retryThrottler.Load().(*retryThrottler) } - cs.binlog = binarylog.GetMethodLogger(method) - - // Only this initial attempt has stats/tracing. - // TODO(dfawley): move to newAttempt when per-attempt stats are implemented. - if err := cs.newAttemptLocked(sh, trInfo); err != nil { - cs.finish(err) - return nil, err + if ml := binarylog.GetMethodLogger(method); ml != nil { + cs.binlogs = append(cs.binlogs, ml) + } + if cc.dopts.binaryLogger != nil { + if ml := cc.dopts.binaryLogger.GetMethodLogger(method); ml != nil { + cs.binlogs = append(cs.binlogs, ml) + } } - op := func(a *csAttempt) error { return a.newStream() } + // Pick the transport to use and create a new stream on the transport. + // Assign cs.attempt upon success. + op := func(a *csAttempt) error { + if err := a.getTransport(); err != nil { + return err + } + if err := a.newStream(); err != nil { + return err + } + // Because this operation is always called either here (while creating + // the clientStream) or by the retry code while locked when replaying + // the operation, it is safe to access cs.attempt directly. + cs.attempt = a + return nil + } if err := cs.withRetry(op, func() { cs.bufferForRetryLocked(0, op) }); err != nil { - cs.finish(err) return nil, err } - if cs.binlog != nil { + if len(cs.binlogs) != 0 { md, _ := metadata.FromOutgoingContext(ctx) logEntry := &binarylog.ClientHeader{ OnClientSide: true, @@ -322,7 +368,9 @@ func newClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, meth logEntry.Timeout = 0 } } - cs.binlog.Log(logEntry) + for _, binlog := range cs.binlogs { + binlog.Log(cs.ctx, logEntry) + } } if desc != unaryStreamDesc { @@ -343,63 +391,123 @@ func newClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, meth return cs, nil } -// newAttemptLocked creates a new attempt with a transport. -// If it succeeds, then it replaces clientStream's attempt with this new attempt. -func (cs *clientStream) newAttemptLocked(sh stats.Handler, trInfo *traceInfo) (retErr error) { - newAttempt := &csAttempt{ - cs: cs, - dc: cs.cc.dopts.dc, - statsHandler: sh, - trInfo: trInfo, +// newAttemptLocked creates a new csAttempt without a transport or stream. +func (cs *clientStream) newAttemptLocked(isTransparent bool) (*csAttempt, error) { + if err := cs.ctx.Err(); err != nil { + return nil, toRPCErr(err) } - defer func() { - if retErr != nil { - // This attempt is not set in the clientStream, so it's finish won't - // be called. Call it here for stats and trace in case they are not - // nil. - newAttempt.finish(retErr) + if err := cs.cc.ctx.Err(); err != nil { + return nil, ErrClientConnClosing + } + + ctx := newContextWithRPCInfo(cs.ctx, cs.callInfo.failFast, cs.callInfo.codec, cs.cp, cs.comp) + method := cs.callHdr.Method + var beginTime time.Time + shs := cs.cc.dopts.copts.StatsHandlers + for _, sh := range shs { + ctx = sh.TagRPC(ctx, &stats.RPCTagInfo{FullMethodName: method, FailFast: cs.callInfo.failFast}) + beginTime = time.Now() + begin := &stats.Begin{ + Client: true, + BeginTime: beginTime, + FailFast: cs.callInfo.failFast, + IsClientStream: cs.desc.ClientStreams, + IsServerStream: cs.desc.ServerStreams, + IsTransparentRetryAttempt: isTransparent, } - }() + sh.HandleRPC(ctx, begin) + } - if err := cs.ctx.Err(); err != nil { - return toRPCErr(err) + var trInfo *traceInfo + if EnableTracing { + trInfo = &traceInfo{ + tr: trace.New("grpc.Sent."+methodFamily(method), method), + firstLine: firstLine{ + client: true, + }, + } + if deadline, ok := ctx.Deadline(); ok { + trInfo.firstLine.deadline = time.Until(deadline) + } + trInfo.tr.LazyLog(&trInfo.firstLine, false) + ctx = trace.NewContext(ctx, trInfo.tr) } - ctx := cs.ctx - if cs.cc.parsedTarget.Scheme == "xds" { + if cs.cc.parsedTarget.URL.Scheme == "xds" { // Add extra metadata (metadata that will be added by transport) to context // so the balancer can see them. - ctx = grpcutil.WithExtraMetadata(cs.ctx, metadata.Pairs( + ctx = grpcutil.WithExtraMetadata(ctx, metadata.Pairs( "content-type", grpcutil.ContentType(cs.callHdr.ContentSubtype), )) } - t, done, err := cs.cc.getTransport(ctx, cs.callInfo.failFast, cs.callHdr.Method) + + return &csAttempt{ + ctx: ctx, + beginTime: beginTime, + cs: cs, + dc: cs.cc.dopts.dc, + statsHandlers: shs, + trInfo: trInfo, + }, nil +} + +func (a *csAttempt) getTransport() error { + cs := a.cs + + var err error + a.t, a.pickResult, err = cs.cc.getTransport(a.ctx, cs.callInfo.failFast, cs.callHdr.Method) if err != nil { + if de, ok := err.(dropError); ok { + err = de.error + a.drop = true + } return err } - if trInfo != nil { - trInfo.firstLine.SetRemoteAddr(t.RemoteAddr()) + if a.trInfo != nil { + a.trInfo.firstLine.SetRemoteAddr(a.t.RemoteAddr()) } - newAttempt.t = t - newAttempt.done = done - cs.attempt = newAttempt return nil } func (a *csAttempt) newStream() error { cs := a.cs cs.callHdr.PreviousAttempts = cs.numRetries - s, err := a.t.NewStream(cs.ctx, cs.callHdr) + + // Merge metadata stored in PickResult, if any, with existing call metadata. + // It is safe to overwrite the csAttempt's context here, since all state + // maintained in it are local to the attempt. When the attempt has to be + // retried, a new instance of csAttempt will be created. + if a.pickResult.Metadata != nil { + // We currently do not have a function it the metadata package which + // merges given metadata with existing metadata in a context. Existing + // function `AppendToOutgoingContext()` takes a variadic argument of key + // value pairs. + // + // TODO: Make it possible to retrieve key value pairs from metadata.MD + // in a form passable to AppendToOutgoingContext(), or create a version + // of AppendToOutgoingContext() that accepts a metadata.MD. + md, _ := metadata.FromOutgoingContext(a.ctx) + md = metadata.Join(md, a.pickResult.Metadata) + a.ctx = metadata.NewOutgoingContext(a.ctx, md) + } + + s, err := a.t.NewStream(a.ctx, cs.callHdr) if err != nil { - if _, ok := err.(transport.PerformedIOError); ok { - // Return without converting to an RPC error so retry code can - // inspect. + nse, ok := err.(*transport.NewStreamError) + if !ok { + // Unexpected. return err } - return toRPCErr(err) + + if nse.AllowTransparentRetry { + a.allowTransparentRetry = true + } + + // Unwrap and convert error. + return toRPCErr(nse.Err) } - cs.attempt.s = s - cs.attempt.p = &parser{r: s} + a.s = s + a.p = &parser{r: s} return nil } @@ -417,8 +525,7 @@ type clientStream struct { cancel context.CancelFunc // cancels all attempts - sentLast bool // sent an end stream - beginTime time.Time + sentLast bool // sent an end stream methodConfig *MethodConfig @@ -426,7 +533,7 @@ type clientStream struct { retryThrottler *retryThrottler // The throttler active when the RPC began. - binlog *binarylog.MethodLogger // Binary logger, can be nil. + binlogs []binarylog.MethodLogger // serverHeaderBinlogged is a boolean for whether server header has been // logged. Server header will be logged when the first time one of those // happens: stream.Header(), stream.Recv(). @@ -458,11 +565,12 @@ type clientStream struct { // csAttempt implements a single transport stream attempt within a // clientStream. type csAttempt struct { - cs *clientStream - t transport.ClientTransport - s *transport.Stream - p *parser - done func(balancer.DoneInfo) + ctx context.Context + cs *clientStream + t transport.ClientTransport + s *transport.Stream + p *parser + pickResult balancer.PickResult finished bool dc Decompressor @@ -475,7 +583,13 @@ type csAttempt struct { // and cleared when the finish method is called. trInfo *traceInfo - statsHandler stats.Handler + statsHandlers []stats.Handler + beginTime time.Time + + // set for newStream errors that may be transparently retried + allowTransparentRetry bool + // set for pick errors that are returned as a status + drop bool } func (cs *clientStream) commitAttemptLocked() { @@ -493,85 +607,76 @@ func (cs *clientStream) commitAttempt() { } // shouldRetry returns nil if the RPC should be retried; otherwise it returns -// the error that should be returned by the operation. -func (cs *clientStream) shouldRetry(err error) error { - unprocessed := false - if cs.attempt.s == nil { - pioErr, ok := err.(transport.PerformedIOError) - if ok { - // Unwrap error. - err = toRPCErr(pioErr.Err) - } else { - unprocessed = true - } - if !ok && !cs.callInfo.failFast { - // In the event of a non-IO operation error from NewStream, we - // never attempted to write anything to the wire, so we can retry - // indefinitely for non-fail-fast RPCs. - return nil - } +// the error that should be returned by the operation. If the RPC should be +// retried, the bool indicates whether it is being retried transparently. +func (a *csAttempt) shouldRetry(err error) (bool, error) { + cs := a.cs + + if cs.finished || cs.committed || a.drop { + // RPC is finished or committed or was dropped by the picker; cannot retry. + return false, err } - if cs.finished || cs.committed { - // RPC is finished or committed; cannot retry. - return err + if a.s == nil && a.allowTransparentRetry { + return true, nil } // Wait for the trailers. - if cs.attempt.s != nil { - <-cs.attempt.s.Done() - unprocessed = cs.attempt.s.Unprocessed() + unprocessed := false + if a.s != nil { + <-a.s.Done() + unprocessed = a.s.Unprocessed() } if cs.firstAttempt && unprocessed { // First attempt, stream unprocessed: transparently retry. - return nil + return true, nil } if cs.cc.dopts.disableRetry { - return err + return false, err } pushback := 0 hasPushback := false - if cs.attempt.s != nil { - if !cs.attempt.s.TrailersOnly() { - return err + if a.s != nil { + if !a.s.TrailersOnly() { + return false, err } // TODO(retry): Move down if the spec changes to not check server pushback // before considering this a failure for throttling. - sps := cs.attempt.s.Trailer()["grpc-retry-pushback-ms"] + sps := a.s.Trailer()["grpc-retry-pushback-ms"] if len(sps) == 1 { var e error if pushback, e = strconv.Atoi(sps[0]); e != nil || pushback < 0 { channelz.Infof(logger, cs.cc.channelzID, "Server retry pushback specified to abort (%q).", sps[0]) cs.retryThrottler.throttle() // This counts as a failure for throttling. - return err + return false, err } hasPushback = true } else if len(sps) > 1 { channelz.Warningf(logger, cs.cc.channelzID, "Server retry pushback specified multiple values (%q); not retrying.", sps) cs.retryThrottler.throttle() // This counts as a failure for throttling. - return err + return false, err } } var code codes.Code - if cs.attempt.s != nil { - code = cs.attempt.s.Status().Code() + if a.s != nil { + code = a.s.Status().Code() } else { - code = status.Convert(err).Code() + code = status.Code(err) } rp := cs.methodConfig.RetryPolicy if rp == nil || !rp.RetryableStatusCodes[code] { - return err + return false, err } // Note: the ordering here is important; we count this as a failure // only if the code matched a retryable code. if cs.retryThrottler.throttle() { - return err + return false, err } if cs.numRetries+1 >= rp.MaxAttempts { - return err + return false, err } var dur time.Duration @@ -594,26 +699,32 @@ func (cs *clientStream) shouldRetry(err error) error { select { case <-t.C: cs.numRetries++ - return nil + return false, nil case <-cs.ctx.Done(): t.Stop() - return status.FromContextError(cs.ctx.Err()).Err() + return false, status.FromContextError(cs.ctx.Err()).Err() } } // Returns nil if a retry was performed and succeeded; error otherwise. -func (cs *clientStream) retryLocked(lastErr error) error { +func (cs *clientStream) retryLocked(attempt *csAttempt, lastErr error) error { for { - cs.attempt.finish(lastErr) - if err := cs.shouldRetry(lastErr); err != nil { + attempt.finish(toRPCErr(lastErr)) + isTransparent, err := attempt.shouldRetry(lastErr) + if err != nil { cs.commitAttemptLocked() return err } cs.firstAttempt = false - if err := cs.newAttemptLocked(nil, nil); err != nil { + attempt, err = cs.newAttemptLocked(isTransparent) + if err != nil { + // Only returns error if the clientconn is closed or the context of + // the stream is canceled. return err } - if lastErr = cs.replayBufferLocked(); lastErr == nil { + // Note that the first op in the replay buffer always sets cs.attempt + // if it is able to pick a transport and create a stream. + if lastErr = cs.replayBufferLocked(attempt); lastErr == nil { return nil } } @@ -623,7 +734,10 @@ func (cs *clientStream) Context() context.Context { cs.commitAttempt() // No need to lock before using attempt, since we know it is committed and // cannot change. - return cs.attempt.s.Context() + if cs.attempt.s != nil { + return cs.attempt.s.Context() + } + return cs.ctx } func (cs *clientStream) withRetry(op func(a *csAttempt) error, onSuccess func()) error { @@ -631,7 +745,23 @@ func (cs *clientStream) withRetry(op func(a *csAttempt) error, onSuccess func()) for { if cs.committed { cs.mu.Unlock() - return op(cs.attempt) + // toRPCErr is used in case the error from the attempt comes from + // NewClientStream, which intentionally doesn't return a status + // error to allow for further inspection; all other errors should + // already be status errors. + return toRPCErr(op(cs.attempt)) + } + if len(cs.buffer) == 0 { + // For the first op, which controls creation of the stream and + // assigns cs.attempt, we need to create a new attempt inline + // before executing the first op. On subsequent ops, the attempt + // is created immediately before replaying the ops. + var err error + if cs.attempt, err = cs.newAttemptLocked(false /* isTransparent */); err != nil { + cs.mu.Unlock() + cs.finish(err) + return err + } } a := cs.attempt cs.mu.Unlock() @@ -649,7 +779,7 @@ func (cs *clientStream) withRetry(op func(a *csAttempt) error, onSuccess func()) cs.mu.Unlock() return err } - if err := cs.retryLocked(err); err != nil { + if err := cs.retryLocked(a, err); err != nil { cs.mu.Unlock() return err } @@ -658,17 +788,25 @@ func (cs *clientStream) withRetry(op func(a *csAttempt) error, onSuccess func()) func (cs *clientStream) Header() (metadata.MD, error) { var m metadata.MD + noHeader := false err := cs.withRetry(func(a *csAttempt) error { var err error m, err = a.s.Header() + if err == transport.ErrNoHeaders { + noHeader = true + return nil + } return toRPCErr(err) }, cs.commitAttemptLocked) + if err != nil { cs.finish(err) return nil, err } - if cs.binlog != nil && !cs.serverHeaderBinlogged { - // Only log if binary log is on and header has not been logged. + + if len(cs.binlogs) != 0 && !cs.serverHeaderBinlogged && !noHeader { + // Only log if binary log is on and header has not been logged, and + // there is actually headers to log. logEntry := &binarylog.ServerHeader{ OnClientSide: true, Header: m, @@ -677,10 +815,12 @@ func (cs *clientStream) Header() (metadata.MD, error) { if peer, ok := peer.FromContext(cs.Context()); ok { logEntry.PeerAddr = peer.Addr } - cs.binlog.Log(logEntry) cs.serverHeaderBinlogged = true + for _, binlog := range cs.binlogs { + binlog.Log(cs.ctx, logEntry) + } } - return m, err + return m, nil } func (cs *clientStream) Trailer() metadata.MD { @@ -698,10 +838,9 @@ func (cs *clientStream) Trailer() metadata.MD { return cs.attempt.s.Trailer() } -func (cs *clientStream) replayBufferLocked() error { - a := cs.attempt +func (cs *clientStream) replayBufferLocked(attempt *csAttempt) error { for _, f := range cs.buffer { - if err := f(a); err != nil { + if err := f(attempt); err != nil { return err } } @@ -749,47 +888,48 @@ func (cs *clientStream) SendMsg(m interface{}) (err error) { if len(payload) > *cs.callInfo.maxSendMessageSize { return status.Errorf(codes.ResourceExhausted, "trying to send message larger than max (%d vs. %d)", len(payload), *cs.callInfo.maxSendMessageSize) } - msgBytes := data // Store the pointer before setting to nil. For binary logging. op := func(a *csAttempt) error { - err := a.sendMsg(m, hdr, payload, data) - // nil out the message and uncomp when replaying; they are only needed for - // stats which is disabled for subsequent attempts. - m, data = nil, nil - return err + return a.sendMsg(m, hdr, payload, data) } err = cs.withRetry(op, func() { cs.bufferForRetryLocked(len(hdr)+len(payload), op) }) - if cs.binlog != nil && err == nil { - cs.binlog.Log(&binarylog.ClientMessage{ + if len(cs.binlogs) != 0 && err == nil { + cm := &binarylog.ClientMessage{ OnClientSide: true, - Message: msgBytes, - }) + Message: data, + } + for _, binlog := range cs.binlogs { + binlog.Log(cs.ctx, cm) + } } - return + return err } func (cs *clientStream) RecvMsg(m interface{}) error { - if cs.binlog != nil && !cs.serverHeaderBinlogged { + if len(cs.binlogs) != 0 && !cs.serverHeaderBinlogged { // Call Header() to binary log header if it's not already logged. cs.Header() } var recvInfo *payloadInfo - if cs.binlog != nil { + if len(cs.binlogs) != 0 { recvInfo = &payloadInfo{} } err := cs.withRetry(func(a *csAttempt) error { return a.recvMsg(m, recvInfo) }, cs.commitAttemptLocked) - if cs.binlog != nil && err == nil { - cs.binlog.Log(&binarylog.ServerMessage{ + if len(cs.binlogs) != 0 && err == nil { + sm := &binarylog.ServerMessage{ OnClientSide: true, Message: recvInfo.uncompressedBytes, - }) + } + for _, binlog := range cs.binlogs { + binlog.Log(cs.ctx, sm) + } } if err != nil || !cs.desc.ServerStreams { // err != nil or non-server-streaming indicates end of stream. cs.finish(err) - if cs.binlog != nil { + if len(cs.binlogs) != 0 { // finish will not log Trailer. Log Trailer here. logEntry := &binarylog.ServerTrailer{ OnClientSide: true, @@ -802,7 +942,9 @@ func (cs *clientStream) RecvMsg(m interface{}) error { if peer, ok := peer.FromContext(cs.Context()); ok { logEntry.PeerAddr = peer.Addr } - cs.binlog.Log(logEntry) + for _, binlog := range cs.binlogs { + binlog.Log(cs.ctx, logEntry) + } } } return err @@ -823,10 +965,13 @@ func (cs *clientStream) CloseSend() error { return nil } cs.withRetry(op, func() { cs.bufferForRetryLocked(0, op) }) - if cs.binlog != nil { - cs.binlog.Log(&binarylog.ClientHalfClose{ + if len(cs.binlogs) != 0 { + chc := &binarylog.ClientHalfClose{ OnClientSide: true, - }) + } + for _, binlog := range cs.binlogs { + binlog.Log(cs.ctx, chc) + } } // We never returned an error here for reasons. return nil @@ -843,6 +988,9 @@ func (cs *clientStream) finish(err error) { return } cs.finished = true + for _, onFinish := range cs.callInfo.onFinish { + onFinish(err) + } cs.commitAttemptLocked() if cs.attempt != nil { cs.attempt.finish(err) @@ -859,10 +1007,13 @@ func (cs *clientStream) finish(err error) { // // Only one of cancel or trailer needs to be logged. In the cases where // users don't call RecvMsg, users must have already canceled the RPC. - if cs.binlog != nil && status.Code(err) == codes.Canceled { - cs.binlog.Log(&binarylog.Cancel{ + if len(cs.binlogs) != 0 && status.Code(err) == codes.Canceled { + c := &binarylog.Cancel{ OnClientSide: true, - }) + } + for _, binlog := range cs.binlogs { + binlog.Log(cs.ctx, c) + } } if err == nil { cs.retryThrottler.successfulRPC() @@ -895,8 +1046,8 @@ func (a *csAttempt) sendMsg(m interface{}, hdr, payld, data []byte) error { } return io.EOF } - if a.statsHandler != nil { - a.statsHandler.HandleRPC(cs.ctx, outPayload(true, m, data, payld, time.Now())) + for _, sh := range a.statsHandlers { + sh.HandleRPC(a.ctx, outPayload(true, m, data, payld, time.Now())) } if channelz.IsOn() { a.t.IncrMsgSent() @@ -906,7 +1057,7 @@ func (a *csAttempt) sendMsg(m interface{}, hdr, payld, data []byte) error { func (a *csAttempt) recvMsg(m interface{}, payInfo *payloadInfo) (err error) { cs := a.cs - if a.statsHandler != nil && payInfo == nil { + if len(a.statsHandlers) != 0 && payInfo == nil { payInfo = &payloadInfo{} } @@ -934,6 +1085,7 @@ func (a *csAttempt) recvMsg(m interface{}, payInfo *payloadInfo) (err error) { } return io.EOF // indicates successful end of stream. } + return toRPCErr(err) } if a.trInfo != nil { @@ -943,15 +1095,16 @@ func (a *csAttempt) recvMsg(m interface{}, payInfo *payloadInfo) (err error) { } a.mu.Unlock() } - if a.statsHandler != nil { - a.statsHandler.HandleRPC(cs.ctx, &stats.InPayload{ + for _, sh := range a.statsHandlers { + sh.HandleRPC(a.ctx, &stats.InPayload{ Client: true, RecvTime: time.Now(), Payload: m, // TODO truncate large payload. - Data: payInfo.uncompressedBytes, - WireLength: payInfo.wireLength + headerLen, - Length: len(payInfo.uncompressedBytes), + Data: payInfo.uncompressedBytes, + WireLength: payInfo.compressedLength + headerLen, + CompressedLength: payInfo.compressedLength, + Length: len(payInfo.uncompressedBytes), }) } if channelz.IsOn() { @@ -990,12 +1143,12 @@ func (a *csAttempt) finish(err error) { tr = a.s.Trailer() } - if a.done != nil { + if a.pickResult.Done != nil { br := false if a.s != nil { br = a.s.BytesReceived() } - a.done(balancer.DoneInfo{ + a.pickResult.Done(balancer.DoneInfo{ Err: err, Trailer: tr, BytesSent: a.s != nil, @@ -1003,15 +1156,15 @@ func (a *csAttempt) finish(err error) { ServerLoad: balancerload.Parse(tr), }) } - if a.statsHandler != nil { + for _, sh := range a.statsHandlers { end := &stats.End{ Client: true, - BeginTime: a.cs.beginTime, + BeginTime: a.beginTime, EndTime: time.Now(), Trailer: tr, Error: err, } - a.statsHandler.HandleRPC(a.cs.ctx, end) + sh.HandleRPC(a.ctx, end) } if a.trInfo != nil && a.trInfo.tr != nil { if err == nil { @@ -1120,14 +1273,19 @@ func newNonRetryClientStream(ctx context.Context, desc *StreamDesc, method strin as.p = &parser{r: s} ac.incrCallsStarted() if desc != unaryStreamDesc { - // Listen on cc and stream contexts to cleanup when the user closes the - // ClientConn or cancels the stream context. In all other cases, an error - // should already be injected into the recv buffer by the transport, which - // the client will eventually receive, and then we will cancel the stream's - // context in clientStream.finish. + // Listen on stream context to cleanup when the stream context is + // canceled. Also listen for the addrConn's context in case the + // addrConn is closed or reconnects to a different address. In all + // other cases, an error should already be injected into the recv + // buffer by the transport, which the client will eventually receive, + // and then we will cancel the stream's context in + // addrConnStream.finish. go func() { + ac.mu.Lock() + acCtx := ac.ctx + ac.mu.Unlock() select { - case <-ac.ctx.Done(): + case <-acCtx.Done(): as.finish(status.Error(codes.Canceled, "grpc: the SubConn is closing")) case <-ctx.Done(): as.finish(toRPCErr(ctx.Err())) @@ -1316,8 +1474,10 @@ func (as *addrConnStream) finish(err error) { // ServerStream defines the server-side behavior of a streaming RPC. // -// All errors returned from ServerStream methods are compatible with the -// status package. +// Errors returned from ServerStream methods are compatible with the status +// package. However, the status code will often not match the RPC status as +// seen by the client application, and therefore, should not be relied upon for +// this purpose. type ServerStream interface { // SetHeader sets the header metadata. It may be called multiple times. // When call multiple times, all the provided metadata will be merged. @@ -1349,6 +1509,9 @@ type ServerStream interface { // It is safe to have a goroutine calling SendMsg and another goroutine // calling RecvMsg on the same stream at the same time, but it is not safe // to call SendMsg on the same stream in different goroutines. + // + // It is not safe to modify the message after calling SendMsg. Tracing + // libraries and stats handlers may use the message lazily. SendMsg(m interface{}) error // RecvMsg blocks until it receives a message into m or the stream is // done. It returns io.EOF when the client has performed a CloseSend. On @@ -1374,13 +1537,15 @@ type serverStream struct { comp encoding.Compressor decomp encoding.Compressor + sendCompressorName string + maxReceiveMessageSize int maxSendMessageSize int trInfo *traceInfo - statsHandler stats.Handler + statsHandler []stats.Handler - binlog *binarylog.MethodLogger + binlogs []binarylog.MethodLogger // serverHeaderBinlogged indicates whether server header has been logged. It // will happen when one of the following two happens: stream.SendHeader(), // stream.Send(). @@ -1400,17 +1565,29 @@ func (ss *serverStream) SetHeader(md metadata.MD) error { if md.Len() == 0 { return nil } + err := imetadata.Validate(md) + if err != nil { + return status.Error(codes.Internal, err.Error()) + } return ss.s.SetHeader(md) } func (ss *serverStream) SendHeader(md metadata.MD) error { - err := ss.t.WriteHeader(ss.s, md) - if ss.binlog != nil && !ss.serverHeaderBinlogged { + err := imetadata.Validate(md) + if err != nil { + return status.Error(codes.Internal, err.Error()) + } + + err = ss.t.WriteHeader(ss.s, md) + if len(ss.binlogs) != 0 && !ss.serverHeaderBinlogged { h, _ := ss.s.Header() - ss.binlog.Log(&binarylog.ServerHeader{ + sh := &binarylog.ServerHeader{ Header: h, - }) + } ss.serverHeaderBinlogged = true + for _, binlog := range ss.binlogs { + binlog.Log(ss.ctx, sh) + } } return err } @@ -1419,6 +1596,9 @@ func (ss *serverStream) SetTrailer(md metadata.MD) { if md.Len() == 0 { return } + if err := imetadata.Validate(md); err != nil { + logger.Errorf("stream: failed to validate md when setting trailer, err: %v", err) + } ss.s.SetTrailer(md) } @@ -1451,6 +1631,13 @@ func (ss *serverStream) SendMsg(m interface{}) (err error) { } }() + // Server handler could have set new compressor by calling SetSendCompressor. + // In case it is set, we need to use it for compressing outbound message. + if sendCompressorsName := ss.s.SendCompress(); sendCompressorsName != ss.sendCompressorName { + ss.comp = encoding.GetCompressor(sendCompressorsName) + ss.sendCompressorName = sendCompressorsName + } + // load hdr, payload, data hdr, payload, data, err := prepareMsg(m, ss.codec, ss.cp, ss.comp) if err != nil { @@ -1464,20 +1651,28 @@ func (ss *serverStream) SendMsg(m interface{}) (err error) { if err := ss.t.Write(ss.s, hdr, payload, &transport.Options{Last: false}); err != nil { return toRPCErr(err) } - if ss.binlog != nil { + if len(ss.binlogs) != 0 { if !ss.serverHeaderBinlogged { h, _ := ss.s.Header() - ss.binlog.Log(&binarylog.ServerHeader{ + sh := &binarylog.ServerHeader{ Header: h, - }) + } ss.serverHeaderBinlogged = true + for _, binlog := range ss.binlogs { + binlog.Log(ss.ctx, sh) + } } - ss.binlog.Log(&binarylog.ServerMessage{ + sm := &binarylog.ServerMessage{ Message: data, - }) + } + for _, binlog := range ss.binlogs { + binlog.Log(ss.ctx, sm) + } } - if ss.statsHandler != nil { - ss.statsHandler.HandleRPC(ss.s.Context(), outPayload(false, m, data, payload, time.Now())) + if len(ss.statsHandler) != 0 { + for _, sh := range ss.statsHandler { + sh.HandleRPC(ss.s.Context(), outPayload(false, m, data, payload, time.Now())) + } } return nil } @@ -1511,13 +1706,16 @@ func (ss *serverStream) RecvMsg(m interface{}) (err error) { } }() var payInfo *payloadInfo - if ss.statsHandler != nil || ss.binlog != nil { + if len(ss.statsHandler) != 0 || len(ss.binlogs) != 0 { payInfo = &payloadInfo{} } if err := recv(ss.p, ss.codec, ss.s, ss.dc, m, ss.maxReceiveMessageSize, payInfo, ss.decomp); err != nil { if err == io.EOF { - if ss.binlog != nil { - ss.binlog.Log(&binarylog.ClientHalfClose{}) + if len(ss.binlogs) != 0 { + chc := &binarylog.ClientHalfClose{} + for _, binlog := range ss.binlogs { + binlog.Log(ss.ctx, chc) + } } return err } @@ -1526,20 +1724,26 @@ func (ss *serverStream) RecvMsg(m interface{}) (err error) { } return toRPCErr(err) } - if ss.statsHandler != nil { - ss.statsHandler.HandleRPC(ss.s.Context(), &stats.InPayload{ - RecvTime: time.Now(), - Payload: m, - // TODO truncate large payload. - Data: payInfo.uncompressedBytes, - WireLength: payInfo.wireLength + headerLen, - Length: len(payInfo.uncompressedBytes), - }) + if len(ss.statsHandler) != 0 { + for _, sh := range ss.statsHandler { + sh.HandleRPC(ss.s.Context(), &stats.InPayload{ + RecvTime: time.Now(), + Payload: m, + // TODO truncate large payload. + Data: payInfo.uncompressedBytes, + Length: len(payInfo.uncompressedBytes), + WireLength: payInfo.compressedLength + headerLen, + CompressedLength: payInfo.compressedLength, + }) + } } - if ss.binlog != nil { - ss.binlog.Log(&binarylog.ClientMessage{ + if len(ss.binlogs) != 0 { + cm := &binarylog.ClientMessage{ Message: payInfo.uncompressedBytes, - }) + } + for _, binlog := range ss.binlogs { + binlog.Log(ss.ctx, cm) + } } return nil } diff --git a/vendor/google.golang.org/grpc/tap/tap.go b/vendor/google.golang.org/grpc/tap/tap.go index caea1ebed6e..bfa5dfa40e4 100644 --- a/vendor/google.golang.org/grpc/tap/tap.go +++ b/vendor/google.golang.org/grpc/tap/tap.go @@ -19,7 +19,7 @@ // Package tap defines the function handles which are executed on the transport // layer of gRPC-Go and related information. // -// Experimental +// # Experimental // // Notice: This API is EXPERIMENTAL and may be changed or removed in a // later release. @@ -37,16 +37,16 @@ type Info struct { // TODO: More to be added. } -// ServerInHandle defines the function which runs before a new stream is created -// on the server side. If it returns a non-nil error, the stream will not be -// created and a RST_STREAM will be sent back to the client with REFUSED_STREAM. -// The client will receive an RPC error "code = Unavailable, desc = stream -// terminated by RST_STREAM with error code: REFUSED_STREAM". +// ServerInHandle defines the function which runs before a new stream is +// created on the server side. If it returns a non-nil error, the stream will +// not be created and an error will be returned to the client. If the error +// returned is a status error, that status code and message will be used, +// otherwise PermissionDenied will be the code and err.Error() will be the +// message. // // It's intended to be used in situations where you don't want to waste the -// resources to accept the new stream (e.g. rate-limiting). And the content of -// the error will be ignored and won't be sent back to the client. For other -// general usages, please use interceptors. +// resources to accept the new stream (e.g. rate-limiting). For other general +// usages, please use interceptors. // // Note that it is executed in the per-connection I/O goroutine(s) instead of // per-RPC goroutine. Therefore, users should NOT have any diff --git a/vendor/google.golang.org/grpc/version.go b/vendor/google.golang.org/grpc/version.go index 51024d6b318..3cc75406218 100644 --- a/vendor/google.golang.org/grpc/version.go +++ b/vendor/google.golang.org/grpc/version.go @@ -19,4 +19,4 @@ package grpc // Version is the current grpc version. -const Version = "1.36.0" +const Version = "1.56.3" diff --git a/vendor/google.golang.org/grpc/vet.sh b/vendor/google.golang.org/grpc/vet.sh index b41df6dc860..a8e4732b3d2 100644 --- a/vendor/google.golang.org/grpc/vet.sh +++ b/vendor/google.golang.org/grpc/vet.sh @@ -28,40 +28,21 @@ cleanup() { } trap cleanup EXIT -PATH="${GOPATH}/bin:${GOROOT}/bin:${PATH}" +PATH="${HOME}/go/bin:${GOROOT}/bin:${PATH}" +go version if [[ "$1" = "-install" ]]; then - # Check for module support - if go help mod >& /dev/null; then - # Install the pinned versions as defined in module tools. - pushd ./test/tools - go install \ - golang.org/x/lint/golint \ - golang.org/x/tools/cmd/goimports \ - honnef.co/go/tools/cmd/staticcheck \ - github.com/client9/misspell/cmd/misspell - popd - else - # Ye olde `go get` incantation. - # Note: this gets the latest version of all tools (vs. the pinned versions - # with Go modules). - go get -u \ - golang.org/x/lint/golint \ - golang.org/x/tools/cmd/goimports \ - honnef.co/go/tools/cmd/staticcheck \ - github.com/client9/misspell/cmd/misspell - fi + # Install the pinned versions as defined in module tools. + pushd ./test/tools + go install \ + golang.org/x/lint/golint \ + golang.org/x/tools/cmd/goimports \ + honnef.co/go/tools/cmd/staticcheck \ + github.com/client9/misspell/cmd/misspell + popd if [[ -z "${VET_SKIP_PROTO}" ]]; then - if [[ "${TRAVIS}" = "true" ]]; then - PROTOBUF_VERSION=3.14.0 - PROTOC_FILENAME=protoc-${PROTOBUF_VERSION}-linux-x86_64.zip - pushd /home/travis - wget https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/${PROTOC_FILENAME} - unzip ${PROTOC_FILENAME} - bin/protoc --version - popd - elif [[ "${GITHUB_ACTIONS}" = "true" ]]; then - PROTOBUF_VERSION=3.14.0 + if [[ "${GITHUB_ACTIONS}" = "true" ]]; then + PROTOBUF_VERSION=22.0 # a.k.a v4.22.0 in pb.go files. PROTOC_FILENAME=protoc-${PROTOBUF_VERSION}-linux-x86_64.zip pushd /home/runner/go wget https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/${PROTOC_FILENAME} @@ -77,8 +58,20 @@ elif [[ "$#" -ne 0 ]]; then die "Unknown argument(s): $*" fi +# - Check that generated proto files are up to date. +if [[ -z "${VET_SKIP_PROTO}" ]]; then + make proto && git status --porcelain 2>&1 | fail_on_output || \ + (git status; git --no-pager diff; exit 1) +fi + +if [[ -n "${VET_ONLY_PROTO}" ]]; then + exit 0 +fi + # - Ensure all source files contain a copyright message. -not git grep -L "\(Copyright [0-9]\{4,\} gRPC authors\)\|DO NOT EDIT" -- '*.go' +# (Done in two parts because Darwin "git grep" has broken support for compound +# exclusion matches.) +(grep -L "DO NOT EDIT" $(git grep -L "\(Copyright [0-9]\{4,\} gRPC authors\)" -- '*.go') || true) | fail_on_output # - Make sure all tests in grpc and grpc/test use leakcheck via Teardown. not grep 'func Test[^(]' *_test.go @@ -92,7 +85,7 @@ not git grep -l 'x/net/context' -- "*.go" git grep -l '"math/rand"' -- "*.go" 2>&1 | not grep -v '^examples\|^stress\|grpcrand\|^benchmark\|wrr_test' # - Do not call grpclog directly. Use grpclog.Component instead. -git grep -l 'grpclog.I\|grpclog.W\|grpclog.E\|grpclog.F\|grpclog.V' -- "*.go" | not grep -v '^grpclog/component.go\|^internal/grpctest/tlogger_test.go' +git grep -l -e 'grpclog.I' --or -e 'grpclog.W' --or -e 'grpclog.E' --or -e 'grpclog.F' --or -e 'grpclog.V' -- "*.go" | not grep -v '^grpclog/component.go\|^internal/grpctest/tlogger_test.go' # - Ensure all ptypes proto packages are renamed when importing. not git grep "\(import \|^\s*\)\"github.com/golang/protobuf/ptypes/" -- "*.go" @@ -100,38 +93,32 @@ not git grep "\(import \|^\s*\)\"github.com/golang/protobuf/ptypes/" -- "*.go" # - Ensure all xds proto imports are renamed to *pb or *grpc. git grep '"github.com/envoyproxy/go-control-plane/envoy' -- '*.go' ':(exclude)*.pb.go' | not grep -v 'pb "\|grpc "' -# - Check imports that are illegal in appengine (until Go 1.11). -# TODO: Remove when we drop Go 1.10 support -go list -f {{.Dir}} ./... | xargs go run test/go_vet/vet.go - -# - gofmt, goimports, golint (with exceptions for generated code), go vet. -gofmt -s -d -l . 2>&1 | fail_on_output -goimports -l . 2>&1 | not grep -vE "\.pb\.go" -golint ./... 2>&1 | not grep -vE "\.pb\.go:" -go vet -all ./... - misspell -error . -# - Check that generated proto files are up to date. -if [[ -z "${VET_SKIP_PROTO}" ]]; then - PATH="/home/travis/bin:${PATH}" make proto && \ - git status --porcelain 2>&1 | fail_on_output || \ - (git status; git --no-pager diff; exit 1) -fi - -# - Check that our modules are tidy. -if go help mod >& /dev/null; then - find . -name 'go.mod' | xargs -IXXX bash -c 'cd $(dirname XXX); go mod tidy' +# - gofmt, goimports, golint (with exceptions for generated code), go vet, +# go mod tidy. +# Perform these checks on each module inside gRPC. +for MOD_FILE in $(find . -name 'go.mod'); do + MOD_DIR=$(dirname ${MOD_FILE}) + pushd ${MOD_DIR} + go vet -all ./... | fail_on_output + gofmt -s -d -l . 2>&1 | fail_on_output + goimports -l . 2>&1 | not grep -vE "\.pb\.go" + golint ./... 2>&1 | not grep -vE "/grpc_testing_not_regenerate/.*\.pb\.go:" + + go mod tidy -compat=1.17 git status --porcelain 2>&1 | fail_on_output || \ (git status; git --no-pager diff; exit 1) -fi + popd +done # - Collection of static analysis checks # # TODO(dfawley): don't use deprecated functions in examples or first-party # plugins. +# TODO(dfawley): enable ST1019 (duplicate imports) but allow for protobufs. SC_OUT="$(mktemp)" -staticcheck -go 1.9 -checks 'inherit,-ST1015' ./... > "${SC_OUT}" || true +staticcheck -go 1.19 -checks 'inherit,-ST1015,-ST1019,-SA1019' ./... > "${SC_OUT}" || true # Error if anything other than deprecation warnings are printed. not grep -v "is deprecated:.*SA1019" "${SC_OUT}" # Only ignore the following deprecated types/fields/functions. @@ -141,8 +128,11 @@ not grep -Fv '.CredsBundle .NewAddress .NewServiceConfig .Type is deprecated: use Attributes +BuildVersion is deprecated balancer.ErrTransientFailure balancer.Picker +extDesc.Filename is deprecated +github.com/golang/protobuf/jsonpb is deprecated grpc.CallCustomCodec grpc.Code grpc.Compressor @@ -155,7 +145,6 @@ grpc.NewGZIPDecompressor grpc.RPCCompressor grpc.RPCDecompressor grpc.ServiceConfig -grpc.WithBalancerName grpc.WithCompressor grpc.WithDecompressor grpc.WithDialer @@ -164,13 +153,7 @@ grpc.WithServiceConfig grpc.WithTimeout http.CloseNotifier info.SecurityVersion -resolver.Backend -resolver.GRPCLB -extDesc.Filename is deprecated -BuildVersion is deprecated -github.com/golang/protobuf/jsonpb is deprecated proto is deprecated -xxx_messageInfo_ proto.InternalMessageInfo is deprecated proto.EnumName is deprecated proto.ErrInternalBadWireType is deprecated @@ -184,7 +167,12 @@ proto.RegisterExtension is deprecated proto.RegisteredExtension is deprecated proto.RegisteredExtensions is deprecated proto.RegisterMapType is deprecated -proto.Unmarshaler is deprecated' "${SC_OUT}" +proto.Unmarshaler is deprecated +resolver.Backend +resolver.GRPCLB +Target is deprecated: Use the Target field in the BuildOptions instead. +xxx_messageInfo_ +' "${SC_OUT}" # - special golint on package comments. lint_package_comment_per_package() { diff --git a/vendor/google.golang.org/protobuf/cmd/protoc-gen-go/internal_gengo/init.go b/vendor/google.golang.org/protobuf/cmd/protoc-gen-go/internal_gengo/init.go deleted file mode 100644 index 369df13da27..00000000000 --- a/vendor/google.golang.org/protobuf/cmd/protoc-gen-go/internal_gengo/init.go +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package internal_gengo - -import ( - "unicode" - "unicode/utf8" - - "google.golang.org/protobuf/compiler/protogen" - "google.golang.org/protobuf/encoding/protowire" - - "google.golang.org/protobuf/types/descriptorpb" -) - -type fileInfo struct { - *protogen.File - - allEnums []*enumInfo - allMessages []*messageInfo - allExtensions []*extensionInfo - - allEnumsByPtr map[*enumInfo]int // value is index into allEnums - allMessagesByPtr map[*messageInfo]int // value is index into allMessages - allMessageFieldsByPtr map[*messageInfo]*structFields - - // needRawDesc specifies whether the generator should emit logic to provide - // the legacy raw descriptor in GZIP'd form. - // This is updated by enum and message generation logic as necessary, - // and checked at the end of file generation. - needRawDesc bool -} - -type structFields struct { - count int - unexported map[int]string -} - -func (sf *structFields) append(name string) { - if r, _ := utf8.DecodeRuneInString(name); !unicode.IsUpper(r) { - if sf.unexported == nil { - sf.unexported = make(map[int]string) - } - sf.unexported[sf.count] = name - } - sf.count++ -} - -func newFileInfo(file *protogen.File) *fileInfo { - f := &fileInfo{File: file} - - // Collect all enums, messages, and extensions in "flattened ordering". - // See filetype.TypeBuilder. - var walkMessages func([]*protogen.Message, func(*protogen.Message)) - walkMessages = func(messages []*protogen.Message, f func(*protogen.Message)) { - for _, m := range messages { - f(m) - walkMessages(m.Messages, f) - } - } - initEnumInfos := func(enums []*protogen.Enum) { - for _, enum := range enums { - f.allEnums = append(f.allEnums, newEnumInfo(f, enum)) - } - } - initMessageInfos := func(messages []*protogen.Message) { - for _, message := range messages { - f.allMessages = append(f.allMessages, newMessageInfo(f, message)) - } - } - initExtensionInfos := func(extensions []*protogen.Extension) { - for _, extension := range extensions { - f.allExtensions = append(f.allExtensions, newExtensionInfo(f, extension)) - } - } - initEnumInfos(f.Enums) - initMessageInfos(f.Messages) - initExtensionInfos(f.Extensions) - walkMessages(f.Messages, func(m *protogen.Message) { - initEnumInfos(m.Enums) - initMessageInfos(m.Messages) - initExtensionInfos(m.Extensions) - }) - - // Derive a reverse mapping of enum and message pointers to their index - // in allEnums and allMessages. - if len(f.allEnums) > 0 { - f.allEnumsByPtr = make(map[*enumInfo]int) - for i, e := range f.allEnums { - f.allEnumsByPtr[e] = i - } - } - if len(f.allMessages) > 0 { - f.allMessagesByPtr = make(map[*messageInfo]int) - f.allMessageFieldsByPtr = make(map[*messageInfo]*structFields) - for i, m := range f.allMessages { - f.allMessagesByPtr[m] = i - f.allMessageFieldsByPtr[m] = new(structFields) - } - } - - return f -} - -type enumInfo struct { - *protogen.Enum - - genJSONMethod bool - genRawDescMethod bool -} - -func newEnumInfo(f *fileInfo, enum *protogen.Enum) *enumInfo { - e := &enumInfo{Enum: enum} - e.genJSONMethod = true - e.genRawDescMethod = true - return e -} - -type messageInfo struct { - *protogen.Message - - genRawDescMethod bool - genExtRangeMethod bool - - isTracked bool - hasWeak bool -} - -func newMessageInfo(f *fileInfo, message *protogen.Message) *messageInfo { - m := &messageInfo{Message: message} - m.genRawDescMethod = true - m.genExtRangeMethod = true - m.isTracked = isTrackedMessage(m) - for _, field := range m.Fields { - m.hasWeak = m.hasWeak || field.Desc.IsWeak() - } - return m -} - -// isTrackedMessage reports whether field tracking is enabled on the message. -func isTrackedMessage(m *messageInfo) (tracked bool) { - const trackFieldUse_fieldNumber = 37383685 - - // Decode the option from unknown fields to avoid a dependency on the - // annotation proto from protoc-gen-go. - b := m.Desc.Options().(*descriptorpb.MessageOptions).ProtoReflect().GetUnknown() - for len(b) > 0 { - num, typ, n := protowire.ConsumeTag(b) - b = b[n:] - if num == trackFieldUse_fieldNumber && typ == protowire.VarintType { - v, _ := protowire.ConsumeVarint(b) - tracked = protowire.DecodeBool(v) - } - m := protowire.ConsumeFieldValue(num, typ, b) - b = b[m:] - } - return tracked -} - -type extensionInfo struct { - *protogen.Extension -} - -func newExtensionInfo(f *fileInfo, extension *protogen.Extension) *extensionInfo { - x := &extensionInfo{Extension: extension} - return x -} diff --git a/vendor/google.golang.org/protobuf/cmd/protoc-gen-go/internal_gengo/main.go b/vendor/google.golang.org/protobuf/cmd/protoc-gen-go/internal_gengo/main.go deleted file mode 100644 index 78a985f17fb..00000000000 --- a/vendor/google.golang.org/protobuf/cmd/protoc-gen-go/internal_gengo/main.go +++ /dev/null @@ -1,904 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package internal_gengo is internal to the protobuf module. -package internal_gengo - -import ( - "fmt" - "go/ast" - "go/parser" - "go/token" - "math" - "strconv" - "strings" - "unicode" - "unicode/utf8" - - "google.golang.org/protobuf/compiler/protogen" - "google.golang.org/protobuf/internal/encoding/tag" - "google.golang.org/protobuf/internal/filedesc" - "google.golang.org/protobuf/internal/genid" - "google.golang.org/protobuf/internal/version" - "google.golang.org/protobuf/reflect/protoreflect" - "google.golang.org/protobuf/runtime/protoimpl" - - "google.golang.org/protobuf/types/descriptorpb" - "google.golang.org/protobuf/types/pluginpb" -) - -// SupportedFeatures reports the set of supported protobuf language features. -var SupportedFeatures = uint64(pluginpb.CodeGeneratorResponse_FEATURE_PROTO3_OPTIONAL) - -// GenerateVersionMarkers specifies whether to generate version markers. -var GenerateVersionMarkers = true - -// Standard library dependencies. -const ( - base64Package = protogen.GoImportPath("encoding/base64") - mathPackage = protogen.GoImportPath("math") - reflectPackage = protogen.GoImportPath("reflect") - sortPackage = protogen.GoImportPath("sort") - stringsPackage = protogen.GoImportPath("strings") - syncPackage = protogen.GoImportPath("sync") - timePackage = protogen.GoImportPath("time") - utf8Package = protogen.GoImportPath("unicode/utf8") -) - -// Protobuf library dependencies. -// -// These are declared as an interface type so that they can be more easily -// patched to support unique build environments that impose restrictions -// on the dependencies of generated source code. -var ( - protoPackage goImportPath = protogen.GoImportPath("google.golang.org/protobuf/proto") - protoifacePackage goImportPath = protogen.GoImportPath("google.golang.org/protobuf/runtime/protoiface") - protoimplPackage goImportPath = protogen.GoImportPath("google.golang.org/protobuf/runtime/protoimpl") - protojsonPackage goImportPath = protogen.GoImportPath("google.golang.org/protobuf/encoding/protojson") - protoreflectPackage goImportPath = protogen.GoImportPath("google.golang.org/protobuf/reflect/protoreflect") - protoregistryPackage goImportPath = protogen.GoImportPath("google.golang.org/protobuf/reflect/protoregistry") -) - -type goImportPath interface { - String() string - Ident(string) protogen.GoIdent -} - -// GenerateFile generates the contents of a .pb.go file. -func GenerateFile(gen *protogen.Plugin, file *protogen.File) *protogen.GeneratedFile { - filename := file.GeneratedFilenamePrefix + ".pb.go" - g := gen.NewGeneratedFile(filename, file.GoImportPath) - f := newFileInfo(file) - - genStandaloneComments(g, f, int32(genid.FileDescriptorProto_Syntax_field_number)) - genGeneratedHeader(gen, g, f) - genStandaloneComments(g, f, int32(genid.FileDescriptorProto_Package_field_number)) - - packageDoc := genPackageKnownComment(f) - g.P(packageDoc, "package ", f.GoPackageName) - g.P() - - // Emit a static check that enforces a minimum version of the proto package. - if GenerateVersionMarkers { - g.P("const (") - g.P("// Verify that this generated code is sufficiently up-to-date.") - g.P("_ = ", protoimplPackage.Ident("EnforceVersion"), "(", protoimpl.GenVersion, " - ", protoimplPackage.Ident("MinVersion"), ")") - g.P("// Verify that runtime/protoimpl is sufficiently up-to-date.") - g.P("_ = ", protoimplPackage.Ident("EnforceVersion"), "(", protoimplPackage.Ident("MaxVersion"), " - ", protoimpl.GenVersion, ")") - g.P(")") - g.P() - } - - for i, imps := 0, f.Desc.Imports(); i < imps.Len(); i++ { - genImport(gen, g, f, imps.Get(i)) - } - for _, enum := range f.allEnums { - genEnum(g, f, enum) - } - for _, message := range f.allMessages { - genMessage(g, f, message) - } - genExtensions(g, f) - - genReflectFileDescriptor(gen, g, f) - - return g -} - -// genStandaloneComments prints all leading comments for a FileDescriptorProto -// location identified by the field number n. -func genStandaloneComments(g *protogen.GeneratedFile, f *fileInfo, n int32) { - loc := f.Desc.SourceLocations().ByPath(protoreflect.SourcePath{n}) - for _, s := range loc.LeadingDetachedComments { - g.P(protogen.Comments(s)) - g.P() - } - if s := loc.LeadingComments; s != "" { - g.P(protogen.Comments(s)) - g.P() - } -} - -func genGeneratedHeader(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo) { - g.P("// Code generated by protoc-gen-go. DO NOT EDIT.") - - if GenerateVersionMarkers { - g.P("// versions:") - protocGenGoVersion := version.String() - protocVersion := "(unknown)" - if v := gen.Request.GetCompilerVersion(); v != nil { - protocVersion = fmt.Sprintf("v%v.%v.%v", v.GetMajor(), v.GetMinor(), v.GetPatch()) - if s := v.GetSuffix(); s != "" { - protocVersion += "-" + s - } - } - g.P("// \tprotoc-gen-go ", protocGenGoVersion) - g.P("// \tprotoc ", protocVersion) - } - - if f.Proto.GetOptions().GetDeprecated() { - g.P("// ", f.Desc.Path(), " is a deprecated file.") - } else { - g.P("// source: ", f.Desc.Path()) - } - g.P() -} - -func genImport(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo, imp protoreflect.FileImport) { - impFile, ok := gen.FilesByPath[imp.Path()] - if !ok { - return - } - if impFile.GoImportPath == f.GoImportPath { - // Don't generate imports or aliases for types in the same Go package. - return - } - // Generate imports for all non-weak dependencies, even if they are not - // referenced, because other code and tools depend on having the - // full transitive closure of protocol buffer types in the binary. - if !imp.IsWeak { - g.Import(impFile.GoImportPath) - } - if !imp.IsPublic { - return - } - - // Generate public imports by generating the imported file, parsing it, - // and extracting every symbol that should receive a forwarding declaration. - impGen := GenerateFile(gen, impFile) - impGen.Skip() - b, err := impGen.Content() - if err != nil { - gen.Error(err) - return - } - fset := token.NewFileSet() - astFile, err := parser.ParseFile(fset, "", b, parser.ParseComments) - if err != nil { - gen.Error(err) - return - } - genForward := func(tok token.Token, name string, expr ast.Expr) { - // Don't import unexported symbols. - r, _ := utf8.DecodeRuneInString(name) - if !unicode.IsUpper(r) { - return - } - // Don't import the FileDescriptor. - if name == impFile.GoDescriptorIdent.GoName { - return - } - // Don't import decls referencing a symbol defined in another package. - // i.e., don't import decls which are themselves public imports: - // - // type T = somepackage.T - if _, ok := expr.(*ast.SelectorExpr); ok { - return - } - g.P(tok, " ", name, " = ", impFile.GoImportPath.Ident(name)) - } - g.P("// Symbols defined in public import of ", imp.Path(), ".") - g.P() - for _, decl := range astFile.Decls { - switch decl := decl.(type) { - case *ast.GenDecl: - for _, spec := range decl.Specs { - switch spec := spec.(type) { - case *ast.TypeSpec: - genForward(decl.Tok, spec.Name.Name, spec.Type) - case *ast.ValueSpec: - for i, name := range spec.Names { - var expr ast.Expr - if i < len(spec.Values) { - expr = spec.Values[i] - } - genForward(decl.Tok, name.Name, expr) - } - case *ast.ImportSpec: - default: - panic(fmt.Sprintf("can't generate forward for spec type %T", spec)) - } - } - } - } - g.P() -} - -func genEnum(g *protogen.GeneratedFile, f *fileInfo, e *enumInfo) { - // Enum type declaration. - g.Annotate(e.GoIdent.GoName, e.Location) - leadingComments := appendDeprecationSuffix(e.Comments.Leading, - e.Desc.ParentFile(), - e.Desc.Options().(*descriptorpb.EnumOptions).GetDeprecated()) - g.P(leadingComments, - "type ", e.GoIdent, " int32") - - // Enum value constants. - g.P("const (") - for _, value := range e.Values { - g.Annotate(value.GoIdent.GoName, value.Location) - leadingComments := appendDeprecationSuffix(value.Comments.Leading, - value.Desc.ParentFile(), - value.Desc.Options().(*descriptorpb.EnumValueOptions).GetDeprecated()) - g.P(leadingComments, - value.GoIdent, " ", e.GoIdent, " = ", value.Desc.Number(), - trailingComment(value.Comments.Trailing)) - } - g.P(")") - g.P() - - // Enum value maps. - g.P("// Enum value maps for ", e.GoIdent, ".") - g.P("var (") - g.P(e.GoIdent.GoName+"_name", " = map[int32]string{") - for _, value := range e.Values { - duplicate := "" - if value.Desc != e.Desc.Values().ByNumber(value.Desc.Number()) { - duplicate = "// Duplicate value: " - } - g.P(duplicate, value.Desc.Number(), ": ", strconv.Quote(string(value.Desc.Name())), ",") - } - g.P("}") - g.P(e.GoIdent.GoName+"_value", " = map[string]int32{") - for _, value := range e.Values { - g.P(strconv.Quote(string(value.Desc.Name())), ": ", value.Desc.Number(), ",") - } - g.P("}") - g.P(")") - g.P() - - // Enum method. - // - // NOTE: A pointer value is needed to represent presence in proto2. - // Since a proto2 message can reference a proto3 enum, it is useful to - // always generate this method (even on proto3 enums) to support that case. - g.P("func (x ", e.GoIdent, ") Enum() *", e.GoIdent, " {") - g.P("p := new(", e.GoIdent, ")") - g.P("*p = x") - g.P("return p") - g.P("}") - g.P() - - // String method. - g.P("func (x ", e.GoIdent, ") String() string {") - g.P("return ", protoimplPackage.Ident("X"), ".EnumStringOf(x.Descriptor(), ", protoreflectPackage.Ident("EnumNumber"), "(x))") - g.P("}") - g.P() - - genEnumReflectMethods(g, f, e) - - // UnmarshalJSON method. - needsUnmarshalJSONMethod := e.genJSONMethod && e.Desc.Syntax() == protoreflect.Proto2 - if fde, ok := e.Desc.(*filedesc.Enum); ok && fde.L1.EditionFeatures.GenerateLegacyUnmarshalJSON { - needsUnmarshalJSONMethod = true - } - if needsUnmarshalJSONMethod { - g.P("// Deprecated: Do not use.") - g.P("func (x *", e.GoIdent, ") UnmarshalJSON(b []byte) error {") - g.P("num, err := ", protoimplPackage.Ident("X"), ".UnmarshalJSONEnum(x.Descriptor(), b)") - g.P("if err != nil {") - g.P("return err") - g.P("}") - g.P("*x = ", e.GoIdent, "(num)") - g.P("return nil") - g.P("}") - g.P() - } - - // EnumDescriptor method. - if e.genRawDescMethod { - var indexes []string - for i := 1; i < len(e.Location.Path); i += 2 { - indexes = append(indexes, strconv.Itoa(int(e.Location.Path[i]))) - } - g.P("// Deprecated: Use ", e.GoIdent, ".Descriptor instead.") - g.P("func (", e.GoIdent, ") EnumDescriptor() ([]byte, []int) {") - g.P("return ", rawDescVarName(f), "GZIP(), []int{", strings.Join(indexes, ","), "}") - g.P("}") - g.P() - f.needRawDesc = true - } -} - -func genMessage(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) { - if m.Desc.IsMapEntry() { - return - } - - // Message type declaration. - g.Annotate(m.GoIdent.GoName, m.Location) - leadingComments := appendDeprecationSuffix(m.Comments.Leading, - m.Desc.ParentFile(), - m.Desc.Options().(*descriptorpb.MessageOptions).GetDeprecated()) - g.P(leadingComments, - "type ", m.GoIdent, " struct {") - genMessageFields(g, f, m) - g.P("}") - g.P() - - genMessageKnownFunctions(g, f, m) - genMessageDefaultDecls(g, f, m) - genMessageMethods(g, f, m) - genMessageOneofWrapperTypes(g, f, m) -} - -func genMessageFields(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) { - sf := f.allMessageFieldsByPtr[m] - genMessageInternalFields(g, f, m, sf) - for _, field := range m.Fields { - genMessageField(g, f, m, field, sf) - } -} - -func genMessageInternalFields(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo, sf *structFields) { - g.P(genid.State_goname, " ", protoimplPackage.Ident("MessageState")) - sf.append(genid.State_goname) - g.P(genid.SizeCache_goname, " ", protoimplPackage.Ident("SizeCache")) - sf.append(genid.SizeCache_goname) - if m.hasWeak { - g.P(genid.WeakFields_goname, " ", protoimplPackage.Ident("WeakFields")) - sf.append(genid.WeakFields_goname) - } - g.P(genid.UnknownFields_goname, " ", protoimplPackage.Ident("UnknownFields")) - sf.append(genid.UnknownFields_goname) - if m.Desc.ExtensionRanges().Len() > 0 { - g.P(genid.ExtensionFields_goname, " ", protoimplPackage.Ident("ExtensionFields")) - sf.append(genid.ExtensionFields_goname) - } - if sf.count > 0 { - g.P() - } -} - -func genMessageField(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo, field *protogen.Field, sf *structFields) { - if oneof := field.Oneof; oneof != nil && !oneof.Desc.IsSynthetic() { - // It would be a bit simpler to iterate over the oneofs below, - // but generating the field here keeps the contents of the Go - // struct in the same order as the contents of the source - // .proto file. - if oneof.Fields[0] != field { - return // only generate for first appearance - } - - tags := structTags{ - {"protobuf_oneof", string(oneof.Desc.Name())}, - } - if m.isTracked { - tags = append(tags, gotrackTags...) - } - - g.Annotate(m.GoIdent.GoName+"."+oneof.GoName, oneof.Location) - leadingComments := oneof.Comments.Leading - if leadingComments != "" { - leadingComments += "\n" - } - ss := []string{fmt.Sprintf(" Types that are assignable to %s:\n", oneof.GoName)} - for _, field := range oneof.Fields { - ss = append(ss, "\t*"+field.GoIdent.GoName+"\n") - } - leadingComments += protogen.Comments(strings.Join(ss, "")) - g.P(leadingComments, - oneof.GoName, " ", oneofInterfaceName(oneof), tags) - sf.append(oneof.GoName) - return - } - goType, pointer := fieldGoType(g, f, field) - if pointer { - goType = "*" + goType - } - tags := structTags{ - {"protobuf", fieldProtobufTagValue(field)}, - {"json", fieldJSONTagValue(field)}, - } - if field.Desc.IsMap() { - key := field.Message.Fields[0] - val := field.Message.Fields[1] - tags = append(tags, structTags{ - {"protobuf_key", fieldProtobufTagValue(key)}, - {"protobuf_val", fieldProtobufTagValue(val)}, - }...) - } - if m.isTracked { - tags = append(tags, gotrackTags...) - } - - name := field.GoName - if field.Desc.IsWeak() { - name = genid.WeakFieldPrefix_goname + name - } - g.Annotate(m.GoIdent.GoName+"."+name, field.Location) - leadingComments := appendDeprecationSuffix(field.Comments.Leading, - field.Desc.ParentFile(), - field.Desc.Options().(*descriptorpb.FieldOptions).GetDeprecated()) - g.P(leadingComments, - name, " ", goType, tags, - trailingComment(field.Comments.Trailing)) - sf.append(field.GoName) -} - -// genMessageDefaultDecls generates consts and vars holding the default -// values of fields. -func genMessageDefaultDecls(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) { - var consts, vars []string - for _, field := range m.Fields { - if !field.Desc.HasDefault() { - continue - } - name := "Default_" + m.GoIdent.GoName + "_" + field.GoName - goType, _ := fieldGoType(g, f, field) - defVal := field.Desc.Default() - switch field.Desc.Kind() { - case protoreflect.StringKind: - consts = append(consts, fmt.Sprintf("%s = %s(%q)", name, goType, defVal.String())) - case protoreflect.BytesKind: - vars = append(vars, fmt.Sprintf("%s = %s(%q)", name, goType, defVal.Bytes())) - case protoreflect.EnumKind: - idx := field.Desc.DefaultEnumValue().Index() - val := field.Enum.Values[idx] - if val.GoIdent.GoImportPath == f.GoImportPath { - consts = append(consts, fmt.Sprintf("%s = %s", name, g.QualifiedGoIdent(val.GoIdent))) - } else { - // If the enum value is declared in a different Go package, - // reference it by number since the name may not be correct. - // See https://github.com/golang/protobuf/issues/513. - consts = append(consts, fmt.Sprintf("%s = %s(%d) // %s", - name, g.QualifiedGoIdent(field.Enum.GoIdent), val.Desc.Number(), g.QualifiedGoIdent(val.GoIdent))) - } - case protoreflect.FloatKind, protoreflect.DoubleKind: - if f := defVal.Float(); math.IsNaN(f) || math.IsInf(f, 0) { - var fn, arg string - switch f := defVal.Float(); { - case math.IsInf(f, -1): - fn, arg = g.QualifiedGoIdent(mathPackage.Ident("Inf")), "-1" - case math.IsInf(f, +1): - fn, arg = g.QualifiedGoIdent(mathPackage.Ident("Inf")), "+1" - case math.IsNaN(f): - fn, arg = g.QualifiedGoIdent(mathPackage.Ident("NaN")), "" - } - vars = append(vars, fmt.Sprintf("%s = %s(%s(%s))", name, goType, fn, arg)) - } else { - consts = append(consts, fmt.Sprintf("%s = %s(%v)", name, goType, f)) - } - default: - consts = append(consts, fmt.Sprintf("%s = %s(%v)", name, goType, defVal.Interface())) - } - } - if len(consts) > 0 { - g.P("// Default values for ", m.GoIdent, " fields.") - g.P("const (") - for _, s := range consts { - g.P(s) - } - g.P(")") - } - if len(vars) > 0 { - g.P("// Default values for ", m.GoIdent, " fields.") - g.P("var (") - for _, s := range vars { - g.P(s) - } - g.P(")") - } - g.P() -} - -func genMessageMethods(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) { - genMessageBaseMethods(g, f, m) - genMessageGetterMethods(g, f, m) - genMessageSetterMethods(g, f, m) -} - -func genMessageBaseMethods(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) { - // Reset method. - g.P("func (x *", m.GoIdent, ") Reset() {") - g.P("*x = ", m.GoIdent, "{}") - g.P("if ", protoimplPackage.Ident("UnsafeEnabled"), " {") - g.P("mi := &", messageTypesVarName(f), "[", f.allMessagesByPtr[m], "]") - g.P("ms := ", protoimplPackage.Ident("X"), ".MessageStateOf(", protoimplPackage.Ident("Pointer"), "(x))") - g.P("ms.StoreMessageInfo(mi)") - g.P("}") - g.P("}") - g.P() - - // String method. - g.P("func (x *", m.GoIdent, ") String() string {") - g.P("return ", protoimplPackage.Ident("X"), ".MessageStringOf(x)") - g.P("}") - g.P() - - // ProtoMessage method. - g.P("func (*", m.GoIdent, ") ProtoMessage() {}") - g.P() - - // ProtoReflect method. - genMessageReflectMethods(g, f, m) - - // Descriptor method. - if m.genRawDescMethod { - var indexes []string - for i := 1; i < len(m.Location.Path); i += 2 { - indexes = append(indexes, strconv.Itoa(int(m.Location.Path[i]))) - } - g.P("// Deprecated: Use ", m.GoIdent, ".ProtoReflect.Descriptor instead.") - g.P("func (*", m.GoIdent, ") Descriptor() ([]byte, []int) {") - g.P("return ", rawDescVarName(f), "GZIP(), []int{", strings.Join(indexes, ","), "}") - g.P("}") - g.P() - f.needRawDesc = true - } -} - -func genMessageGetterMethods(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) { - for _, field := range m.Fields { - genNoInterfacePragma(g, m.isTracked) - - // Getter for parent oneof. - if oneof := field.Oneof; oneof != nil && oneof.Fields[0] == field && !oneof.Desc.IsSynthetic() { - g.Annotate(m.GoIdent.GoName+".Get"+oneof.GoName, oneof.Location) - g.P("func (m *", m.GoIdent.GoName, ") Get", oneof.GoName, "() ", oneofInterfaceName(oneof), " {") - g.P("if m != nil {") - g.P("return m.", oneof.GoName) - g.P("}") - g.P("return nil") - g.P("}") - g.P() - } - - // Getter for message field. - goType, pointer := fieldGoType(g, f, field) - defaultValue := fieldDefaultValue(g, f, m, field) - g.Annotate(m.GoIdent.GoName+".Get"+field.GoName, field.Location) - leadingComments := appendDeprecationSuffix("", - field.Desc.ParentFile(), - field.Desc.Options().(*descriptorpb.FieldOptions).GetDeprecated()) - switch { - case field.Desc.IsWeak(): - g.P(leadingComments, "func (x *", m.GoIdent, ") Get", field.GoName, "() ", protoPackage.Ident("Message"), "{") - g.P("var w ", protoimplPackage.Ident("WeakFields")) - g.P("if x != nil {") - g.P("w = x.", genid.WeakFields_goname) - if m.isTracked { - g.P("_ = x.", genid.WeakFieldPrefix_goname+field.GoName) - } - g.P("}") - g.P("return ", protoimplPackage.Ident("X"), ".GetWeak(w, ", field.Desc.Number(), ", ", strconv.Quote(string(field.Message.Desc.FullName())), ")") - g.P("}") - case field.Oneof != nil && !field.Oneof.Desc.IsSynthetic(): - g.P(leadingComments, "func (x *", m.GoIdent, ") Get", field.GoName, "() ", goType, " {") - g.P("if x, ok := x.Get", field.Oneof.GoName, "().(*", field.GoIdent, "); ok {") - g.P("return x.", field.GoName) - g.P("}") - g.P("return ", defaultValue) - g.P("}") - default: - g.P(leadingComments, "func (x *", m.GoIdent, ") Get", field.GoName, "() ", goType, " {") - if !field.Desc.HasPresence() || defaultValue == "nil" { - g.P("if x != nil {") - } else { - g.P("if x != nil && x.", field.GoName, " != nil {") - } - star := "" - if pointer { - star = "*" - } - g.P("return ", star, " x.", field.GoName) - g.P("}") - g.P("return ", defaultValue) - g.P("}") - } - g.P() - } -} - -func genMessageSetterMethods(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) { - for _, field := range m.Fields { - if !field.Desc.IsWeak() { - continue - } - - genNoInterfacePragma(g, m.isTracked) - - g.AnnotateSymbol(m.GoIdent.GoName+".Set"+field.GoName, protogen.Annotation{ - Location: field.Location, - Semantic: descriptorpb.GeneratedCodeInfo_Annotation_SET.Enum(), - }) - leadingComments := appendDeprecationSuffix("", - field.Desc.ParentFile(), - field.Desc.Options().(*descriptorpb.FieldOptions).GetDeprecated()) - g.P(leadingComments, "func (x *", m.GoIdent, ") Set", field.GoName, "(v ", protoPackage.Ident("Message"), ") {") - g.P("var w *", protoimplPackage.Ident("WeakFields")) - g.P("if x != nil {") - g.P("w = &x.", genid.WeakFields_goname) - if m.isTracked { - g.P("_ = x.", genid.WeakFieldPrefix_goname+field.GoName) - } - g.P("}") - g.P(protoimplPackage.Ident("X"), ".SetWeak(w, ", field.Desc.Number(), ", ", strconv.Quote(string(field.Message.Desc.FullName())), ", v)") - g.P("}") - g.P() - } -} - -// fieldGoType returns the Go type used for a field. -// -// If it returns pointer=true, the struct field is a pointer to the type. -func fieldGoType(g *protogen.GeneratedFile, f *fileInfo, field *protogen.Field) (goType string, pointer bool) { - if field.Desc.IsWeak() { - return "struct{}", false - } - - pointer = field.Desc.HasPresence() - switch field.Desc.Kind() { - case protoreflect.BoolKind: - goType = "bool" - case protoreflect.EnumKind: - goType = g.QualifiedGoIdent(field.Enum.GoIdent) - case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind: - goType = "int32" - case protoreflect.Uint32Kind, protoreflect.Fixed32Kind: - goType = "uint32" - case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: - goType = "int64" - case protoreflect.Uint64Kind, protoreflect.Fixed64Kind: - goType = "uint64" - case protoreflect.FloatKind: - goType = "float32" - case protoreflect.DoubleKind: - goType = "float64" - case protoreflect.StringKind: - goType = "string" - case protoreflect.BytesKind: - goType = "[]byte" - pointer = false // rely on nullability of slices for presence - case protoreflect.MessageKind, protoreflect.GroupKind: - goType = "*" + g.QualifiedGoIdent(field.Message.GoIdent) - pointer = false // pointer captured as part of the type - } - switch { - case field.Desc.IsList(): - return "[]" + goType, false - case field.Desc.IsMap(): - keyType, _ := fieldGoType(g, f, field.Message.Fields[0]) - valType, _ := fieldGoType(g, f, field.Message.Fields[1]) - return fmt.Sprintf("map[%v]%v", keyType, valType), false - } - return goType, pointer -} - -func fieldProtobufTagValue(field *protogen.Field) string { - var enumName string - if field.Desc.Kind() == protoreflect.EnumKind { - enumName = protoimpl.X.LegacyEnumName(field.Enum.Desc) - } - return tag.Marshal(field.Desc, enumName) -} - -func fieldDefaultValue(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo, field *protogen.Field) string { - if field.Desc.IsList() { - return "nil" - } - if field.Desc.HasDefault() { - defVarName := "Default_" + m.GoIdent.GoName + "_" + field.GoName - if field.Desc.Kind() == protoreflect.BytesKind { - return "append([]byte(nil), " + defVarName + "...)" - } - return defVarName - } - switch field.Desc.Kind() { - case protoreflect.BoolKind: - return "false" - case protoreflect.StringKind: - return `""` - case protoreflect.MessageKind, protoreflect.GroupKind, protoreflect.BytesKind: - return "nil" - case protoreflect.EnumKind: - val := field.Enum.Values[0] - if val.GoIdent.GoImportPath == f.GoImportPath { - return g.QualifiedGoIdent(val.GoIdent) - } else { - // If the enum value is declared in a different Go package, - // reference it by number since the name may not be correct. - // See https://github.com/golang/protobuf/issues/513. - return g.QualifiedGoIdent(field.Enum.GoIdent) + "(" + strconv.FormatInt(int64(val.Desc.Number()), 10) + ")" - } - default: - return "0" - } -} - -func fieldJSONTagValue(field *protogen.Field) string { - return string(field.Desc.Name()) + ",omitempty" -} - -func genExtensions(g *protogen.GeneratedFile, f *fileInfo) { - if len(f.allExtensions) == 0 { - return - } - - g.P("var ", extensionTypesVarName(f), " = []", protoimplPackage.Ident("ExtensionInfo"), "{") - for _, x := range f.allExtensions { - g.P("{") - g.P("ExtendedType: (*", x.Extendee.GoIdent, ")(nil),") - goType, pointer := fieldGoType(g, f, x.Extension) - if pointer { - goType = "*" + goType - } - g.P("ExtensionType: (", goType, ")(nil),") - g.P("Field: ", x.Desc.Number(), ",") - g.P("Name: ", strconv.Quote(string(x.Desc.FullName())), ",") - g.P("Tag: ", strconv.Quote(fieldProtobufTagValue(x.Extension)), ",") - g.P("Filename: ", strconv.Quote(f.Desc.Path()), ",") - g.P("},") - } - g.P("}") - g.P() - - // Group extensions by the target message. - var orderedTargets []protogen.GoIdent - allExtensionsByTarget := make(map[protogen.GoIdent][]*extensionInfo) - allExtensionsByPtr := make(map[*extensionInfo]int) - for i, x := range f.allExtensions { - target := x.Extendee.GoIdent - if len(allExtensionsByTarget[target]) == 0 { - orderedTargets = append(orderedTargets, target) - } - allExtensionsByTarget[target] = append(allExtensionsByTarget[target], x) - allExtensionsByPtr[x] = i - } - for _, target := range orderedTargets { - g.P("// Extension fields to ", target, ".") - g.P("var (") - for _, x := range allExtensionsByTarget[target] { - xd := x.Desc - typeName := xd.Kind().String() - switch xd.Kind() { - case protoreflect.EnumKind: - typeName = string(xd.Enum().FullName()) - case protoreflect.MessageKind, protoreflect.GroupKind: - typeName = string(xd.Message().FullName()) - } - fieldName := string(xd.Name()) - - leadingComments := x.Comments.Leading - if leadingComments != "" { - leadingComments += "\n" - } - leadingComments += protogen.Comments(fmt.Sprintf(" %v %v %v = %v;\n", - xd.Cardinality(), typeName, fieldName, xd.Number())) - leadingComments = appendDeprecationSuffix(leadingComments, - x.Desc.ParentFile(), - x.Desc.Options().(*descriptorpb.FieldOptions).GetDeprecated()) - g.P(leadingComments, - "E_", x.GoIdent, " = &", extensionTypesVarName(f), "[", allExtensionsByPtr[x], "]", - trailingComment(x.Comments.Trailing)) - } - g.P(")") - g.P() - } -} - -// genMessageOneofWrapperTypes generates the oneof wrapper types and -// associates the types with the parent message type. -func genMessageOneofWrapperTypes(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) { - for _, oneof := range m.Oneofs { - if oneof.Desc.IsSynthetic() { - continue - } - ifName := oneofInterfaceName(oneof) - g.P("type ", ifName, " interface {") - g.P(ifName, "()") - g.P("}") - g.P() - for _, field := range oneof.Fields { - g.Annotate(field.GoIdent.GoName, field.Location) - g.Annotate(field.GoIdent.GoName+"."+field.GoName, field.Location) - g.P("type ", field.GoIdent, " struct {") - goType, _ := fieldGoType(g, f, field) - tags := structTags{ - {"protobuf", fieldProtobufTagValue(field)}, - } - if m.isTracked { - tags = append(tags, gotrackTags...) - } - leadingComments := appendDeprecationSuffix(field.Comments.Leading, - field.Desc.ParentFile(), - field.Desc.Options().(*descriptorpb.FieldOptions).GetDeprecated()) - g.P(leadingComments, - field.GoName, " ", goType, tags, - trailingComment(field.Comments.Trailing)) - g.P("}") - g.P() - } - for _, field := range oneof.Fields { - g.P("func (*", field.GoIdent, ") ", ifName, "() {}") - g.P() - } - } -} - -// oneofInterfaceName returns the name of the interface type implemented by -// the oneof field value types. -func oneofInterfaceName(oneof *protogen.Oneof) string { - return "is" + oneof.GoIdent.GoName -} - -// genNoInterfacePragma generates a standalone "nointerface" pragma to -// decorate methods with field-tracking support. -func genNoInterfacePragma(g *protogen.GeneratedFile, tracked bool) { - if tracked { - g.P("//go:nointerface") - g.P() - } -} - -var gotrackTags = structTags{{"go", "track"}} - -// structTags is a data structure for build idiomatic Go struct tags. -// Each [2]string is a key-value pair, where value is the unescaped string. -// -// Example: structTags{{"key", "value"}}.String() -> `key:"value"` -type structTags [][2]string - -func (tags structTags) String() string { - if len(tags) == 0 { - return "" - } - var ss []string - for _, tag := range tags { - // NOTE: When quoting the value, we need to make sure the backtick - // character does not appear. Convert all cases to the escaped hex form. - key := tag[0] - val := strings.Replace(strconv.Quote(tag[1]), "`", `\x60`, -1) - ss = append(ss, fmt.Sprintf("%s:%s", key, val)) - } - return "`" + strings.Join(ss, " ") + "`" -} - -// appendDeprecationSuffix optionally appends a deprecation notice as a suffix. -func appendDeprecationSuffix(prefix protogen.Comments, parentFile protoreflect.FileDescriptor, deprecated bool) protogen.Comments { - fileDeprecated := parentFile.Options().(*descriptorpb.FileOptions).GetDeprecated() - if !deprecated && !fileDeprecated { - return prefix - } - if prefix != "" { - prefix += "\n" - } - if fileDeprecated { - return prefix + " Deprecated: The entire proto file " + protogen.Comments(parentFile.Path()) + " is marked as deprecated.\n" - } - return prefix + " Deprecated: Marked as deprecated in " + protogen.Comments(parentFile.Path()) + ".\n" -} - -// trailingComment is like protogen.Comments, but lacks a trailing newline. -type trailingComment protogen.Comments - -func (c trailingComment) String() string { - s := strings.TrimSuffix(protogen.Comments(c).String(), "\n") - if strings.Contains(s, "\n") { - // We don't support multi-lined trailing comments as it is unclear - // how to best render them in the generated code. - return "" - } - return s -} diff --git a/vendor/google.golang.org/protobuf/cmd/protoc-gen-go/internal_gengo/reflect.go b/vendor/google.golang.org/protobuf/cmd/protoc-gen-go/internal_gengo/reflect.go deleted file mode 100644 index 0048beb1e32..00000000000 --- a/vendor/google.golang.org/protobuf/cmd/protoc-gen-go/internal_gengo/reflect.go +++ /dev/null @@ -1,372 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package internal_gengo - -import ( - "fmt" - "math" - "strings" - "unicode/utf8" - - "google.golang.org/protobuf/compiler/protogen" - "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/reflect/protopath" - "google.golang.org/protobuf/reflect/protorange" - "google.golang.org/protobuf/reflect/protoreflect" - - "google.golang.org/protobuf/types/descriptorpb" -) - -func genReflectFileDescriptor(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo) { - g.P("var ", f.GoDescriptorIdent, " ", protoreflectPackage.Ident("FileDescriptor")) - g.P() - - genFileDescriptor(gen, g, f) - if len(f.allEnums) > 0 { - g.P("var ", enumTypesVarName(f), " = make([]", protoimplPackage.Ident("EnumInfo"), ",", len(f.allEnums), ")") - } - if len(f.allMessages) > 0 { - g.P("var ", messageTypesVarName(f), " = make([]", protoimplPackage.Ident("MessageInfo"), ",", len(f.allMessages), ")") - } - - // Generate a unique list of Go types for all declarations and dependencies, - // and the associated index into the type list for all dependencies. - var goTypes []string - var depIdxs []string - seen := map[protoreflect.FullName]int{} - genDep := func(name protoreflect.FullName, depSource string) { - if depSource != "" { - line := fmt.Sprintf("%d, // %d: %s -> %s", seen[name], len(depIdxs), depSource, name) - depIdxs = append(depIdxs, line) - } - } - genEnum := func(e *protogen.Enum, depSource string) { - if e != nil { - name := e.Desc.FullName() - if _, ok := seen[name]; !ok { - line := fmt.Sprintf("(%s)(0), // %d: %s", g.QualifiedGoIdent(e.GoIdent), len(goTypes), name) - goTypes = append(goTypes, line) - seen[name] = len(seen) - } - if depSource != "" { - genDep(name, depSource) - } - } - } - genMessage := func(m *protogen.Message, depSource string) { - if m != nil { - name := m.Desc.FullName() - if _, ok := seen[name]; !ok { - line := fmt.Sprintf("(*%s)(nil), // %d: %s", g.QualifiedGoIdent(m.GoIdent), len(goTypes), name) - if m.Desc.IsMapEntry() { - // Map entry messages have no associated Go type. - line = fmt.Sprintf("nil, // %d: %s", len(goTypes), name) - } - goTypes = append(goTypes, line) - seen[name] = len(seen) - } - if depSource != "" { - genDep(name, depSource) - } - } - } - - // This ordering is significant. - // See filetype.TypeBuilder.DependencyIndexes. - type offsetEntry struct { - start int - name string - } - var depOffsets []offsetEntry - for _, enum := range f.allEnums { - genEnum(enum.Enum, "") - } - for _, message := range f.allMessages { - genMessage(message.Message, "") - } - depOffsets = append(depOffsets, offsetEntry{len(depIdxs), "field type_name"}) - for _, message := range f.allMessages { - for _, field := range message.Fields { - if field.Desc.IsWeak() { - continue - } - source := string(field.Desc.FullName()) - genEnum(field.Enum, source+":type_name") - genMessage(field.Message, source+":type_name") - } - } - depOffsets = append(depOffsets, offsetEntry{len(depIdxs), "extension extendee"}) - for _, extension := range f.allExtensions { - source := string(extension.Desc.FullName()) - genMessage(extension.Extendee, source+":extendee") - } - depOffsets = append(depOffsets, offsetEntry{len(depIdxs), "extension type_name"}) - for _, extension := range f.allExtensions { - source := string(extension.Desc.FullName()) - genEnum(extension.Enum, source+":type_name") - genMessage(extension.Message, source+":type_name") - } - depOffsets = append(depOffsets, offsetEntry{len(depIdxs), "method input_type"}) - for _, service := range f.Services { - for _, method := range service.Methods { - source := string(method.Desc.FullName()) - genMessage(method.Input, source+":input_type") - } - } - depOffsets = append(depOffsets, offsetEntry{len(depIdxs), "method output_type"}) - for _, service := range f.Services { - for _, method := range service.Methods { - source := string(method.Desc.FullName()) - genMessage(method.Output, source+":output_type") - } - } - depOffsets = append(depOffsets, offsetEntry{len(depIdxs), ""}) - for i := len(depOffsets) - 2; i >= 0; i-- { - curr, next := depOffsets[i], depOffsets[i+1] - depIdxs = append(depIdxs, fmt.Sprintf("%d, // [%d:%d] is the sub-list for %s", - curr.start, curr.start, next.start, curr.name)) - } - if len(depIdxs) > math.MaxInt32 { - panic("too many dependencies") // sanity check - } - - g.P("var ", goTypesVarName(f), " = []interface{}{") - for _, s := range goTypes { - g.P(s) - } - g.P("}") - - g.P("var ", depIdxsVarName(f), " = []int32{") - for _, s := range depIdxs { - g.P(s) - } - g.P("}") - - g.P("func init() { ", initFuncName(f.File), "() }") - - g.P("func ", initFuncName(f.File), "() {") - g.P("if ", f.GoDescriptorIdent, " != nil {") - g.P("return") - g.P("}") - - // Ensure that initialization functions for different files in the same Go - // package run in the correct order: Call the init funcs for every .proto file - // imported by this one that is in the same Go package. - for i, imps := 0, f.Desc.Imports(); i < imps.Len(); i++ { - impFile := gen.FilesByPath[imps.Get(i).Path()] - if impFile.GoImportPath != f.GoImportPath { - continue - } - g.P(initFuncName(impFile), "()") - } - - if len(f.allMessages) > 0 { - // Populate MessageInfo.Exporters. - g.P("if !", protoimplPackage.Ident("UnsafeEnabled"), " {") - for _, message := range f.allMessages { - if sf := f.allMessageFieldsByPtr[message]; len(sf.unexported) > 0 { - idx := f.allMessagesByPtr[message] - typesVar := messageTypesVarName(f) - - g.P(typesVar, "[", idx, "].Exporter = func(v interface{}, i int) interface{} {") - g.P("switch v := v.(*", message.GoIdent, "); i {") - for i := 0; i < sf.count; i++ { - if name := sf.unexported[i]; name != "" { - g.P("case ", i, ": return &v.", name) - } - } - g.P("default: return nil") - g.P("}") - g.P("}") - } - } - g.P("}") - - // Populate MessageInfo.OneofWrappers. - for _, message := range f.allMessages { - if len(message.Oneofs) > 0 { - idx := f.allMessagesByPtr[message] - typesVar := messageTypesVarName(f) - - // Associate the wrapper types by directly passing them to the MessageInfo. - g.P(typesVar, "[", idx, "].OneofWrappers = []interface{} {") - for _, oneof := range message.Oneofs { - if !oneof.Desc.IsSynthetic() { - for _, field := range oneof.Fields { - g.P("(*", field.GoIdent, ")(nil),") - } - } - } - g.P("}") - } - } - } - - g.P("type x struct{}") - g.P("out := ", protoimplPackage.Ident("TypeBuilder"), "{") - g.P("File: ", protoimplPackage.Ident("DescBuilder"), "{") - g.P("GoPackagePath: ", reflectPackage.Ident("TypeOf"), "(x{}).PkgPath(),") - g.P("RawDescriptor: ", rawDescVarName(f), ",") - g.P("NumEnums: ", len(f.allEnums), ",") - g.P("NumMessages: ", len(f.allMessages), ",") - g.P("NumExtensions: ", len(f.allExtensions), ",") - g.P("NumServices: ", len(f.Services), ",") - g.P("},") - g.P("GoTypes: ", goTypesVarName(f), ",") - g.P("DependencyIndexes: ", depIdxsVarName(f), ",") - if len(f.allEnums) > 0 { - g.P("EnumInfos: ", enumTypesVarName(f), ",") - } - if len(f.allMessages) > 0 { - g.P("MessageInfos: ", messageTypesVarName(f), ",") - } - if len(f.allExtensions) > 0 { - g.P("ExtensionInfos: ", extensionTypesVarName(f), ",") - } - g.P("}.Build()") - g.P(f.GoDescriptorIdent, " = out.File") - - // Set inputs to nil to allow GC to reclaim resources. - g.P(rawDescVarName(f), " = nil") - g.P(goTypesVarName(f), " = nil") - g.P(depIdxsVarName(f), " = nil") - g.P("}") -} - -// stripSourceRetentionFieldsFromMessage walks the given message tree recursively -// and clears any fields with the field option: [retention = RETENTION_SOURCE] -func stripSourceRetentionFieldsFromMessage(m protoreflect.Message) { - protorange.Range(m, func(ppv protopath.Values) error { - m2, ok := ppv.Index(-1).Value.Interface().(protoreflect.Message) - if !ok { - return nil - } - m2.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool { - fdo, ok := fd.Options().(*descriptorpb.FieldOptions) - if ok && fdo.GetRetention() == descriptorpb.FieldOptions_RETENTION_SOURCE { - m2.Clear(fd) - } - return true - }) - return nil - }) -} - -func genFileDescriptor(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo) { - descProto := proto.Clone(f.Proto).(*descriptorpb.FileDescriptorProto) - descProto.SourceCodeInfo = nil // drop source code information - stripSourceRetentionFieldsFromMessage(descProto.ProtoReflect()) - b, err := proto.MarshalOptions{AllowPartial: true, Deterministic: true}.Marshal(descProto) - if err != nil { - gen.Error(err) - return - } - - g.P("var ", rawDescVarName(f), " = []byte{") - for len(b) > 0 { - n := 16 - if n > len(b) { - n = len(b) - } - - s := "" - for _, c := range b[:n] { - s += fmt.Sprintf("0x%02x,", c) - } - g.P(s) - - b = b[n:] - } - g.P("}") - g.P() - - if f.needRawDesc { - onceVar := rawDescVarName(f) + "Once" - dataVar := rawDescVarName(f) + "Data" - g.P("var (") - g.P(onceVar, " ", syncPackage.Ident("Once")) - g.P(dataVar, " = ", rawDescVarName(f)) - g.P(")") - g.P() - - g.P("func ", rawDescVarName(f), "GZIP() []byte {") - g.P(onceVar, ".Do(func() {") - g.P(dataVar, " = ", protoimplPackage.Ident("X"), ".CompressGZIP(", dataVar, ")") - g.P("})") - g.P("return ", dataVar) - g.P("}") - g.P() - } -} - -func genEnumReflectMethods(g *protogen.GeneratedFile, f *fileInfo, e *enumInfo) { - idx := f.allEnumsByPtr[e] - typesVar := enumTypesVarName(f) - - // Descriptor method. - g.P("func (", e.GoIdent, ") Descriptor() ", protoreflectPackage.Ident("EnumDescriptor"), " {") - g.P("return ", typesVar, "[", idx, "].Descriptor()") - g.P("}") - g.P() - - // Type method. - g.P("func (", e.GoIdent, ") Type() ", protoreflectPackage.Ident("EnumType"), " {") - g.P("return &", typesVar, "[", idx, "]") - g.P("}") - g.P() - - // Number method. - g.P("func (x ", e.GoIdent, ") Number() ", protoreflectPackage.Ident("EnumNumber"), " {") - g.P("return ", protoreflectPackage.Ident("EnumNumber"), "(x)") - g.P("}") - g.P() -} - -func genMessageReflectMethods(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) { - idx := f.allMessagesByPtr[m] - typesVar := messageTypesVarName(f) - - // ProtoReflect method. - g.P("func (x *", m.GoIdent, ") ProtoReflect() ", protoreflectPackage.Ident("Message"), " {") - g.P("mi := &", typesVar, "[", idx, "]") - g.P("if ", protoimplPackage.Ident("UnsafeEnabled"), " && x != nil {") - g.P("ms := ", protoimplPackage.Ident("X"), ".MessageStateOf(", protoimplPackage.Ident("Pointer"), "(x))") - g.P("if ms.LoadMessageInfo() == nil {") - g.P("ms.StoreMessageInfo(mi)") - g.P("}") - g.P("return ms") - g.P("}") - g.P("return mi.MessageOf(x)") - g.P("}") - g.P() -} - -func fileVarName(f *protogen.File, suffix string) string { - prefix := f.GoDescriptorIdent.GoName - _, n := utf8.DecodeRuneInString(prefix) - prefix = strings.ToLower(prefix[:n]) + prefix[n:] - return prefix + "_" + suffix -} -func rawDescVarName(f *fileInfo) string { - return fileVarName(f.File, "rawDesc") -} -func goTypesVarName(f *fileInfo) string { - return fileVarName(f.File, "goTypes") -} -func depIdxsVarName(f *fileInfo) string { - return fileVarName(f.File, "depIdxs") -} -func enumTypesVarName(f *fileInfo) string { - return fileVarName(f.File, "enumTypes") -} -func messageTypesVarName(f *fileInfo) string { - return fileVarName(f.File, "msgTypes") -} -func extensionTypesVarName(f *fileInfo) string { - return fileVarName(f.File, "extTypes") -} -func initFuncName(f *protogen.File) string { - return fileVarName(f, "init") -} diff --git a/vendor/google.golang.org/protobuf/cmd/protoc-gen-go/internal_gengo/well_known_types.go b/vendor/google.golang.org/protobuf/cmd/protoc-gen-go/internal_gengo/well_known_types.go deleted file mode 100644 index 47c4fa18f95..00000000000 --- a/vendor/google.golang.org/protobuf/cmd/protoc-gen-go/internal_gengo/well_known_types.go +++ /dev/null @@ -1,1079 +0,0 @@ -// Copyright 2020 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package internal_gengo - -import ( - "strings" - - "google.golang.org/protobuf/compiler/protogen" - "google.golang.org/protobuf/internal/genid" -) - -// Specialized support for well-known types are hard-coded into the generator -// as opposed to being injected in adjacent .go sources in the generated package -// in order to support specialized build systems like Bazel that always generate -// dynamically from the source .proto files. - -func genPackageKnownComment(f *fileInfo) protogen.Comments { - switch f.Desc.Path() { - case genid.File_google_protobuf_any_proto: - return ` Package anypb contains generated types for ` + genid.File_google_protobuf_any_proto + `. - - The Any message is a dynamic representation of any other message value. - It is functionally a tuple of the full name of the remote message type and - the serialized bytes of the remote message value. - - - Constructing an Any - - An Any message containing another message value is constructed using New: - - any, err := anypb.New(m) - if err != nil { - ... // handle error - } - ... // make use of any - - - Unmarshaling an Any - - With a populated Any message, the underlying message can be serialized into - a remote concrete message value in a few ways. - - If the exact concrete type is known, then a new (or pre-existing) instance - of that message can be passed to the UnmarshalTo method: - - m := new(foopb.MyMessage) - if err := any.UnmarshalTo(m); err != nil { - ... // handle error - } - ... // make use of m - - If the exact concrete type is not known, then the UnmarshalNew method can be - used to unmarshal the contents into a new instance of the remote message type: - - m, err := any.UnmarshalNew() - if err != nil { - ... // handle error - } - ... // make use of m - - UnmarshalNew uses the global type registry to resolve the message type and - construct a new instance of that message to unmarshal into. In order for a - message type to appear in the global registry, the Go type representing that - protobuf message type must be linked into the Go binary. For messages - generated by protoc-gen-go, this is achieved through an import of the - generated Go package representing a .proto file. - - A common pattern with UnmarshalNew is to use a type switch with the resulting - proto.Message value: - - switch m := m.(type) { - case *foopb.MyMessage: - ... // make use of m as a *foopb.MyMessage - case *barpb.OtherMessage: - ... // make use of m as a *barpb.OtherMessage - case *bazpb.SomeMessage: - ... // make use of m as a *bazpb.SomeMessage - } - - This pattern ensures that the generated packages containing the message types - listed in the case clauses are linked into the Go binary and therefore also - registered in the global registry. - - - Type checking an Any - - In order to type check whether an Any message represents some other message, - then use the MessageIs method: - - if any.MessageIs((*foopb.MyMessage)(nil)) { - ... // make use of any, knowing that it contains a foopb.MyMessage - } - - The MessageIs method can also be used with an allocated instance of the target - message type if the intention is to unmarshal into it if the type matches: - - m := new(foopb.MyMessage) - if any.MessageIs(m) { - if err := any.UnmarshalTo(m); err != nil { - ... // handle error - } - ... // make use of m - } - -` - case genid.File_google_protobuf_timestamp_proto: - return ` Package timestamppb contains generated types for ` + genid.File_google_protobuf_timestamp_proto + `. - - The Timestamp message represents a timestamp, - an instant in time since the Unix epoch (January 1st, 1970). - - - Conversion to a Go Time - - The AsTime method can be used to convert a Timestamp message to a - standard Go time.Time value in UTC: - - t := ts.AsTime() - ... // make use of t as a time.Time - - Converting to a time.Time is a common operation so that the extensive - set of time-based operations provided by the time package can be leveraged. - See https://golang.org/pkg/time for more information. - - The AsTime method performs the conversion on a best-effort basis. Timestamps - with denormal values (e.g., nanoseconds beyond 0 and 99999999, inclusive) - are normalized during the conversion to a time.Time. To manually check for - invalid Timestamps per the documented limitations in timestamp.proto, - additionally call the CheckValid method: - - if err := ts.CheckValid(); err != nil { - ... // handle error - } - - - Conversion from a Go Time - - The timestamppb.New function can be used to construct a Timestamp message - from a standard Go time.Time value: - - ts := timestamppb.New(t) - ... // make use of ts as a *timestamppb.Timestamp - - In order to construct a Timestamp representing the current time, use Now: - - ts := timestamppb.Now() - ... // make use of ts as a *timestamppb.Timestamp - -` - case genid.File_google_protobuf_duration_proto: - return ` Package durationpb contains generated types for ` + genid.File_google_protobuf_duration_proto + `. - - The Duration message represents a signed span of time. - - - Conversion to a Go Duration - - The AsDuration method can be used to convert a Duration message to a - standard Go time.Duration value: - - d := dur.AsDuration() - ... // make use of d as a time.Duration - - Converting to a time.Duration is a common operation so that the extensive - set of time-based operations provided by the time package can be leveraged. - See https://golang.org/pkg/time for more information. - - The AsDuration method performs the conversion on a best-effort basis. - Durations with denormal values (e.g., nanoseconds beyond -99999999 and - +99999999, inclusive; or seconds and nanoseconds with opposite signs) - are normalized during the conversion to a time.Duration. To manually check for - invalid Duration per the documented limitations in duration.proto, - additionally call the CheckValid method: - - if err := dur.CheckValid(); err != nil { - ... // handle error - } - - Note that the documented limitations in duration.proto does not protect a - Duration from overflowing the representable range of a time.Duration in Go. - The AsDuration method uses saturation arithmetic such that an overflow clamps - the resulting value to the closest representable value (e.g., math.MaxInt64 - for positive overflow and math.MinInt64 for negative overflow). - - - Conversion from a Go Duration - - The durationpb.New function can be used to construct a Duration message - from a standard Go time.Duration value: - - dur := durationpb.New(d) - ... // make use of d as a *durationpb.Duration - -` - case genid.File_google_protobuf_struct_proto: - return ` Package structpb contains generated types for ` + genid.File_google_protobuf_struct_proto + `. - - The messages (i.e., Value, Struct, and ListValue) defined in struct.proto are - used to represent arbitrary JSON. The Value message represents a JSON value, - the Struct message represents a JSON object, and the ListValue message - represents a JSON array. See https://json.org for more information. - - The Value, Struct, and ListValue types have generated MarshalJSON and - UnmarshalJSON methods such that they serialize JSON equivalent to what the - messages themselves represent. Use of these types with the - "google.golang.org/protobuf/encoding/protojson" package - ensures that they will be serialized as their JSON equivalent. - - # Conversion to and from a Go interface - - The standard Go "encoding/json" package has functionality to serialize - arbitrary types to a large degree. The Value.AsInterface, Struct.AsMap, and - ListValue.AsSlice methods can convert the protobuf message representation into - a form represented by interface{}, map[string]interface{}, and []interface{}. - This form can be used with other packages that operate on such data structures - and also directly with the standard json package. - - In order to convert the interface{}, map[string]interface{}, and []interface{} - forms back as Value, Struct, and ListValue messages, use the NewStruct, - NewList, and NewValue constructor functions. - - # Example usage - - Consider the following example JSON object: - - { - "firstName": "John", - "lastName": "Smith", - "isAlive": true, - "age": 27, - "address": { - "streetAddress": "21 2nd Street", - "city": "New York", - "state": "NY", - "postalCode": "10021-3100" - }, - "phoneNumbers": [ - { - "type": "home", - "number": "212 555-1234" - }, - { - "type": "office", - "number": "646 555-4567" - } - ], - "children": [], - "spouse": null - } - - To construct a Value message representing the above JSON object: - - m, err := structpb.NewValue(map[string]interface{}{ - "firstName": "John", - "lastName": "Smith", - "isAlive": true, - "age": 27, - "address": map[string]interface{}{ - "streetAddress": "21 2nd Street", - "city": "New York", - "state": "NY", - "postalCode": "10021-3100", - }, - "phoneNumbers": []interface{}{ - map[string]interface{}{ - "type": "home", - "number": "212 555-1234", - }, - map[string]interface{}{ - "type": "office", - "number": "646 555-4567", - }, - }, - "children": []interface{}{}, - "spouse": nil, - }) - if err != nil { - ... // handle error - } - ... // make use of m as a *structpb.Value -` - case genid.File_google_protobuf_field_mask_proto: - return ` Package fieldmaskpb contains generated types for ` + genid.File_google_protobuf_field_mask_proto + `. - - The FieldMask message represents a set of symbolic field paths. - The paths are specific to some target message type, - which is not stored within the FieldMask message itself. - - - Constructing a FieldMask - - The New function is used construct a FieldMask: - - var messageType *descriptorpb.DescriptorProto - fm, err := fieldmaskpb.New(messageType, "field.name", "field.number") - if err != nil { - ... // handle error - } - ... // make use of fm - - The "field.name" and "field.number" paths are valid paths according to the - google.protobuf.DescriptorProto message. Use of a path that does not correlate - to valid fields reachable from DescriptorProto would result in an error. - - Once a FieldMask message has been constructed, - the Append method can be used to insert additional paths to the path set: - - var messageType *descriptorpb.DescriptorProto - if err := fm.Append(messageType, "options"); err != nil { - ... // handle error - } - - - Type checking a FieldMask - - In order to verify that a FieldMask represents a set of fields that are - reachable from some target message type, use the IsValid method: - - var messageType *descriptorpb.DescriptorProto - if fm.IsValid(messageType) { - ... // make use of fm - } - - IsValid needs to be passed the target message type as an input since the - FieldMask message itself does not store the message type that the set of paths - are for. -` - default: - return "" - } -} - -func genMessageKnownFunctions(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) { - switch m.Desc.FullName() { - case genid.Any_message_fullname: - g.P("// New marshals src into a new Any instance.") - g.P("func New(src ", protoPackage.Ident("Message"), ") (*Any, error) {") - g.P(" dst := new(Any)") - g.P(" if err := dst.MarshalFrom(src); err != nil {") - g.P(" return nil, err") - g.P(" }") - g.P(" return dst, nil") - g.P("}") - g.P() - - g.P("// MarshalFrom marshals src into dst as the underlying message") - g.P("// using the provided marshal options.") - g.P("//") - g.P("// If no options are specified, call dst.MarshalFrom instead.") - g.P("func MarshalFrom(dst *Any, src ", protoPackage.Ident("Message"), ", opts ", protoPackage.Ident("MarshalOptions"), ") error {") - g.P(" const urlPrefix = \"type.googleapis.com/\"") - g.P(" if src == nil {") - g.P(" return ", protoimplPackage.Ident("X"), ".NewError(\"invalid nil source message\")") - g.P(" }") - g.P(" b, err := opts.Marshal(src)") - g.P(" if err != nil {") - g.P(" return err") - g.P(" }") - g.P(" dst.TypeUrl = urlPrefix + string(src.ProtoReflect().Descriptor().FullName())") - g.P(" dst.Value = b") - g.P(" return nil") - g.P("}") - g.P() - - g.P("// UnmarshalTo unmarshals the underlying message from src into dst") - g.P("// using the provided unmarshal options.") - g.P("// It reports an error if dst is not of the right message type.") - g.P("//") - g.P("// If no options are specified, call src.UnmarshalTo instead.") - g.P("func UnmarshalTo(src *Any, dst ", protoPackage.Ident("Message"), ", opts ", protoPackage.Ident("UnmarshalOptions"), ") error {") - g.P(" if src == nil {") - g.P(" return ", protoimplPackage.Ident("X"), ".NewError(\"invalid nil source message\")") - g.P(" }") - g.P(" if !src.MessageIs(dst) {") - g.P(" got := dst.ProtoReflect().Descriptor().FullName()") - g.P(" want := src.MessageName()") - g.P(" return ", protoimplPackage.Ident("X"), ".NewError(\"mismatched message type: got %q, want %q\", got, want)") - g.P(" }") - g.P(" return opts.Unmarshal(src.GetValue(), dst)") - g.P("}") - g.P() - - g.P("// UnmarshalNew unmarshals the underlying message from src into dst,") - g.P("// which is newly created message using a type resolved from the type URL.") - g.P("// The message type is resolved according to opt.Resolver,") - g.P("// which should implement protoregistry.MessageTypeResolver.") - g.P("// It reports an error if the underlying message type could not be resolved.") - g.P("//") - g.P("// If no options are specified, call src.UnmarshalNew instead.") - g.P("func UnmarshalNew(src *Any, opts ", protoPackage.Ident("UnmarshalOptions"), ") (dst ", protoPackage.Ident("Message"), ", err error) {") - g.P(" if src.GetTypeUrl() == \"\" {") - g.P(" return nil, ", protoimplPackage.Ident("X"), ".NewError(\"invalid empty type URL\")") - g.P(" }") - g.P(" if opts.Resolver == nil {") - g.P(" opts.Resolver = ", protoregistryPackage.Ident("GlobalTypes")) - g.P(" }") - g.P(" r, ok := opts.Resolver.(", protoregistryPackage.Ident("MessageTypeResolver"), ")") - g.P(" if !ok {") - g.P(" return nil, ", protoregistryPackage.Ident("NotFound")) - g.P(" }") - g.P(" mt, err := r.FindMessageByURL(src.GetTypeUrl())") - g.P(" if err != nil {") - g.P(" if err == ", protoregistryPackage.Ident("NotFound"), " {") - g.P(" return nil, err") - g.P(" }") - g.P(" return nil, ", protoimplPackage.Ident("X"), ".NewError(\"could not resolve %q: %v\", src.GetTypeUrl(), err)") - g.P(" }") - g.P(" dst = mt.New().Interface()") - g.P(" return dst, opts.Unmarshal(src.GetValue(), dst)") - g.P("}") - g.P() - - g.P("// MessageIs reports whether the underlying message is of the same type as m.") - g.P("func (x *Any) MessageIs(m ", protoPackage.Ident("Message"), ") bool {") - g.P(" if m == nil {") - g.P(" return false") - g.P(" }") - g.P(" url := x.GetTypeUrl()") - g.P(" name := string(m.ProtoReflect().Descriptor().FullName())") - g.P(" if !", stringsPackage.Ident("HasSuffix"), "(url, name) {") - g.P(" return false") - g.P(" }") - g.P(" return len(url) == len(name) || url[len(url)-len(name)-1] == '/'") - g.P("}") - g.P() - - g.P("// MessageName reports the full name of the underlying message,") - g.P("// returning an empty string if invalid.") - g.P("func (x *Any) MessageName() ", protoreflectPackage.Ident("FullName"), " {") - g.P(" url := x.GetTypeUrl()") - g.P(" name := ", protoreflectPackage.Ident("FullName"), "(url)") - g.P(" if i := ", stringsPackage.Ident("LastIndexByte"), "(url, '/'); i >= 0 {") - g.P(" name = name[i+len(\"/\"):]") - g.P(" }") - g.P(" if !name.IsValid() {") - g.P(" return \"\"") - g.P(" }") - g.P(" return name") - g.P("}") - g.P() - - g.P("// MarshalFrom marshals m into x as the underlying message.") - g.P("func (x *Any) MarshalFrom(m ", protoPackage.Ident("Message"), ") error {") - g.P(" return MarshalFrom(x, m, ", protoPackage.Ident("MarshalOptions"), "{})") - g.P("}") - g.P() - - g.P("// UnmarshalTo unmarshals the contents of the underlying message of x into m.") - g.P("// It resets m before performing the unmarshal operation.") - g.P("// It reports an error if m is not of the right message type.") - g.P("func (x *Any) UnmarshalTo(m ", protoPackage.Ident("Message"), ") error {") - g.P(" return UnmarshalTo(x, m, ", protoPackage.Ident("UnmarshalOptions"), "{})") - g.P("}") - g.P() - - g.P("// UnmarshalNew unmarshals the contents of the underlying message of x into") - g.P("// a newly allocated message of the specified type.") - g.P("// It reports an error if the underlying message type could not be resolved.") - g.P("func (x *Any) UnmarshalNew() (", protoPackage.Ident("Message"), ", error) {") - g.P(" return UnmarshalNew(x, ", protoPackage.Ident("UnmarshalOptions"), "{})") - g.P("}") - g.P() - - case genid.Timestamp_message_fullname: - g.P("// Now constructs a new Timestamp from the current time.") - g.P("func Now() *Timestamp {") - g.P(" return New(", timePackage.Ident("Now"), "())") - g.P("}") - g.P() - - g.P("// New constructs a new Timestamp from the provided time.Time.") - g.P("func New(t ", timePackage.Ident("Time"), ") *Timestamp {") - g.P(" return &Timestamp{Seconds: int64(t.Unix()), Nanos: int32(t.Nanosecond())}") - g.P("}") - g.P() - - g.P("// AsTime converts x to a time.Time.") - g.P("func (x *Timestamp) AsTime() ", timePackage.Ident("Time"), " {") - g.P(" return ", timePackage.Ident("Unix"), "(int64(x.GetSeconds()), int64(x.GetNanos())).UTC()") - g.P("}") - g.P() - - g.P("// IsValid reports whether the timestamp is valid.") - g.P("// It is equivalent to CheckValid == nil.") - g.P("func (x *Timestamp) IsValid() bool {") - g.P(" return x.check() == 0") - g.P("}") - g.P() - - g.P("// CheckValid returns an error if the timestamp is invalid.") - g.P("// In particular, it checks whether the value represents a date that is") - g.P("// in the range of 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z inclusive.") - g.P("// An error is reported for a nil Timestamp.") - g.P("func (x *Timestamp) CheckValid() error {") - g.P(" switch x.check() {") - g.P(" case invalidNil:") - g.P(" return ", protoimplPackage.Ident("X"), ".NewError(\"invalid nil Timestamp\")") - g.P(" case invalidUnderflow:") - g.P(" return ", protoimplPackage.Ident("X"), ".NewError(\"timestamp (%v) before 0001-01-01\", x)") - g.P(" case invalidOverflow:") - g.P(" return ", protoimplPackage.Ident("X"), ".NewError(\"timestamp (%v) after 9999-12-31\", x)") - g.P(" case invalidNanos:") - g.P(" return ", protoimplPackage.Ident("X"), ".NewError(\"timestamp (%v) has out-of-range nanos\", x)") - g.P(" default:") - g.P(" return nil") - g.P(" }") - g.P("}") - g.P() - - g.P("const (") - g.P(" _ = iota") - g.P(" invalidNil") - g.P(" invalidUnderflow") - g.P(" invalidOverflow") - g.P(" invalidNanos") - g.P(")") - g.P() - - g.P("func (x *Timestamp) check() uint {") - g.P(" const minTimestamp = -62135596800 // Seconds between 1970-01-01T00:00:00Z and 0001-01-01T00:00:00Z, inclusive") - g.P(" const maxTimestamp = +253402300799 // Seconds between 1970-01-01T00:00:00Z and 9999-12-31T23:59:59Z, inclusive") - g.P(" secs := x.GetSeconds()") - g.P(" nanos := x.GetNanos()") - g.P(" switch {") - g.P(" case x == nil:") - g.P(" return invalidNil") - g.P(" case secs < minTimestamp:") - g.P(" return invalidUnderflow") - g.P(" case secs > maxTimestamp:") - g.P(" return invalidOverflow") - g.P(" case nanos < 0 || nanos >= 1e9:") - g.P(" return invalidNanos") - g.P(" default:") - g.P(" return 0") - g.P(" }") - g.P("}") - g.P() - - case genid.Duration_message_fullname: - g.P("// New constructs a new Duration from the provided time.Duration.") - g.P("func New(d ", timePackage.Ident("Duration"), ") *Duration {") - g.P(" nanos := d.Nanoseconds()") - g.P(" secs := nanos / 1e9") - g.P(" nanos -= secs * 1e9") - g.P(" return &Duration{Seconds: int64(secs), Nanos: int32(nanos)}") - g.P("}") - g.P() - - g.P("// AsDuration converts x to a time.Duration,") - g.P("// returning the closest duration value in the event of overflow.") - g.P("func (x *Duration) AsDuration() ", timePackage.Ident("Duration"), " {") - g.P(" secs := x.GetSeconds()") - g.P(" nanos := x.GetNanos()") - g.P(" d := ", timePackage.Ident("Duration"), "(secs) * ", timePackage.Ident("Second")) - g.P(" overflow := d/", timePackage.Ident("Second"), " != ", timePackage.Ident("Duration"), "(secs)") - g.P(" d += ", timePackage.Ident("Duration"), "(nanos) * ", timePackage.Ident("Nanosecond")) - g.P(" overflow = overflow || (secs < 0 && nanos < 0 && d > 0)") - g.P(" overflow = overflow || (secs > 0 && nanos > 0 && d < 0)") - g.P(" if overflow {") - g.P(" switch {") - g.P(" case secs < 0:") - g.P(" return ", timePackage.Ident("Duration"), "(", mathPackage.Ident("MinInt64"), ")") - g.P(" case secs > 0:") - g.P(" return ", timePackage.Ident("Duration"), "(", mathPackage.Ident("MaxInt64"), ")") - g.P(" }") - g.P(" }") - g.P(" return d") - g.P("}") - g.P() - - g.P("// IsValid reports whether the duration is valid.") - g.P("// It is equivalent to CheckValid == nil.") - g.P("func (x *Duration) IsValid() bool {") - g.P(" return x.check() == 0") - g.P("}") - g.P() - - g.P("// CheckValid returns an error if the duration is invalid.") - g.P("// In particular, it checks whether the value is within the range of") - g.P("// -10000 years to +10000 years inclusive.") - g.P("// An error is reported for a nil Duration.") - g.P("func (x *Duration) CheckValid() error {") - g.P(" switch x.check() {") - g.P(" case invalidNil:") - g.P(" return ", protoimplPackage.Ident("X"), ".NewError(\"invalid nil Duration\")") - g.P(" case invalidUnderflow:") - g.P(" return ", protoimplPackage.Ident("X"), ".NewError(\"duration (%v) exceeds -10000 years\", x)") - g.P(" case invalidOverflow:") - g.P(" return ", protoimplPackage.Ident("X"), ".NewError(\"duration (%v) exceeds +10000 years\", x)") - g.P(" case invalidNanosRange:") - g.P(" return ", protoimplPackage.Ident("X"), ".NewError(\"duration (%v) has out-of-range nanos\", x)") - g.P(" case invalidNanosSign:") - g.P(" return ", protoimplPackage.Ident("X"), ".NewError(\"duration (%v) has seconds and nanos with different signs\", x)") - g.P(" default:") - g.P(" return nil") - g.P(" }") - g.P("}") - g.P() - - g.P("const (") - g.P(" _ = iota") - g.P(" invalidNil") - g.P(" invalidUnderflow") - g.P(" invalidOverflow") - g.P(" invalidNanosRange") - g.P(" invalidNanosSign") - g.P(")") - g.P() - - g.P("func (x *Duration) check() uint {") - g.P(" const absDuration = 315576000000 // 10000yr * 365.25day/yr * 24hr/day * 60min/hr * 60sec/min") - g.P(" secs := x.GetSeconds()") - g.P(" nanos := x.GetNanos()") - g.P(" switch {") - g.P(" case x == nil:") - g.P(" return invalidNil") - g.P(" case secs < -absDuration:") - g.P(" return invalidUnderflow") - g.P(" case secs > +absDuration:") - g.P(" return invalidOverflow") - g.P(" case nanos <= -1e9 || nanos >= +1e9:") - g.P(" return invalidNanosRange") - g.P(" case (secs > 0 && nanos < 0) || (secs < 0 && nanos > 0):") - g.P(" return invalidNanosSign") - g.P(" default:") - g.P(" return 0") - g.P(" }") - g.P("}") - g.P() - - case genid.Struct_message_fullname: - g.P("// NewStruct constructs a Struct from a general-purpose Go map.") - g.P("// The map keys must be valid UTF-8.") - g.P("// The map values are converted using NewValue.") - g.P("func NewStruct(v map[string]interface{}) (*Struct, error) {") - g.P(" x := &Struct{Fields: make(map[string]*Value, len(v))}") - g.P(" for k, v := range v {") - g.P(" if !", utf8Package.Ident("ValidString"), "(k) {") - g.P(" return nil, ", protoimplPackage.Ident("X"), ".NewError(\"invalid UTF-8 in string: %q\", k)") - g.P(" }") - g.P(" var err error") - g.P(" x.Fields[k], err = NewValue(v)") - g.P(" if err != nil {") - g.P(" return nil, err") - g.P(" }") - g.P(" }") - g.P(" return x, nil") - g.P("}") - g.P() - - g.P("// AsMap converts x to a general-purpose Go map.") - g.P("// The map values are converted by calling Value.AsInterface.") - g.P("func (x *Struct) AsMap() map[string]interface{} {") - g.P(" f := x.GetFields()") - g.P(" vs := make(map[string]interface{}, len(f))") - g.P(" for k, v := range f {") - g.P(" vs[k] = v.AsInterface()") - g.P(" }") - g.P(" return vs") - g.P("}") - g.P() - - g.P("func (x *Struct) MarshalJSON() ([]byte, error) {") - g.P(" return ", protojsonPackage.Ident("Marshal"), "(x)") - g.P("}") - g.P() - - g.P("func (x *Struct) UnmarshalJSON(b []byte) error {") - g.P(" return ", protojsonPackage.Ident("Unmarshal"), "(b, x)") - g.P("}") - g.P() - - case genid.ListValue_message_fullname: - g.P("// NewList constructs a ListValue from a general-purpose Go slice.") - g.P("// The slice elements are converted using NewValue.") - g.P("func NewList(v []interface{}) (*ListValue, error) {") - g.P(" x := &ListValue{Values: make([]*Value, len(v))}") - g.P(" for i, v := range v {") - g.P(" var err error") - g.P(" x.Values[i], err = NewValue(v)") - g.P(" if err != nil {") - g.P(" return nil, err") - g.P(" }") - g.P(" }") - g.P(" return x, nil") - g.P("}") - g.P() - - g.P("// AsSlice converts x to a general-purpose Go slice.") - g.P("// The slice elements are converted by calling Value.AsInterface.") - g.P("func (x *ListValue) AsSlice() []interface{} {") - g.P(" vals := x.GetValues()") - g.P(" vs := make([]interface{}, len(vals))") - g.P(" for i, v := range vals {") - g.P(" vs[i] = v.AsInterface()") - g.P(" }") - g.P(" return vs") - g.P("}") - g.P() - - g.P("func (x *ListValue) MarshalJSON() ([]byte, error) {") - g.P(" return ", protojsonPackage.Ident("Marshal"), "(x)") - g.P("}") - g.P() - - g.P("func (x *ListValue) UnmarshalJSON(b []byte) error {") - g.P(" return ", protojsonPackage.Ident("Unmarshal"), "(b, x)") - g.P("}") - g.P() - - case genid.Value_message_fullname: - g.P("// NewValue constructs a Value from a general-purpose Go interface.") - g.P("//") - g.P("// ╔════════════════════════╤════════════════════════════════════════════╗") - g.P("// ║ Go type │ Conversion ║") - g.P("// ╠════════════════════════╪════════════════════════════════════════════╣") - g.P("// ║ nil │ stored as NullValue ║") - g.P("// ║ bool │ stored as BoolValue ║") - g.P("// ║ int, int32, int64 │ stored as NumberValue ║") - g.P("// ║ uint, uint32, uint64 │ stored as NumberValue ║") - g.P("// ║ float32, float64 │ stored as NumberValue ║") - g.P("// ║ string │ stored as StringValue; must be valid UTF-8 ║") - g.P("// ║ []byte │ stored as StringValue; base64-encoded ║") - g.P("// ║ map[string]interface{} │ stored as StructValue ║") - g.P("// ║ []interface{} │ stored as ListValue ║") - g.P("// ╚════════════════════════╧════════════════════════════════════════════╝") - g.P("//") - g.P("// When converting an int64 or uint64 to a NumberValue, numeric precision loss") - g.P("// is possible since they are stored as a float64.") - g.P("func NewValue(v interface{}) (*Value, error) {") - g.P(" switch v := v.(type) {") - g.P(" case nil:") - g.P(" return NewNullValue(), nil") - g.P(" case bool:") - g.P(" return NewBoolValue(v), nil") - g.P(" case int:") - g.P(" return NewNumberValue(float64(v)), nil") - g.P(" case int32:") - g.P(" return NewNumberValue(float64(v)), nil") - g.P(" case int64:") - g.P(" return NewNumberValue(float64(v)), nil") - g.P(" case uint:") - g.P(" return NewNumberValue(float64(v)), nil") - g.P(" case uint32:") - g.P(" return NewNumberValue(float64(v)), nil") - g.P(" case uint64:") - g.P(" return NewNumberValue(float64(v)), nil") - g.P(" case float32:") - g.P(" return NewNumberValue(float64(v)), nil") - g.P(" case float64:") - g.P(" return NewNumberValue(float64(v)), nil") - g.P(" case string:") - g.P(" if !", utf8Package.Ident("ValidString"), "(v) {") - g.P(" return nil, ", protoimplPackage.Ident("X"), ".NewError(\"invalid UTF-8 in string: %q\", v)") - g.P(" }") - g.P(" return NewStringValue(v), nil") - g.P(" case []byte:") - g.P(" s := ", base64Package.Ident("StdEncoding"), ".EncodeToString(v)") - g.P(" return NewStringValue(s), nil") - g.P(" case map[string]interface{}:") - g.P(" v2, err := NewStruct(v)") - g.P(" if err != nil {") - g.P(" return nil, err") - g.P(" }") - g.P(" return NewStructValue(v2), nil") - g.P(" case []interface{}:") - g.P(" v2, err := NewList(v)") - g.P(" if err != nil {") - g.P(" return nil, err") - g.P(" }") - g.P(" return NewListValue(v2), nil") - g.P(" default:") - g.P(" return nil, ", protoimplPackage.Ident("X"), ".NewError(\"invalid type: %T\", v)") - g.P(" }") - g.P("}") - g.P() - - g.P("// NewNullValue constructs a new null Value.") - g.P("func NewNullValue() *Value {") - g.P(" return &Value{Kind: &Value_NullValue{NullValue: NullValue_NULL_VALUE}}") - g.P("}") - g.P() - - g.P("// NewBoolValue constructs a new boolean Value.") - g.P("func NewBoolValue(v bool) *Value {") - g.P(" return &Value{Kind: &Value_BoolValue{BoolValue: v}}") - g.P("}") - g.P() - - g.P("// NewNumberValue constructs a new number Value.") - g.P("func NewNumberValue(v float64) *Value {") - g.P(" return &Value{Kind: &Value_NumberValue{NumberValue: v}}") - g.P("}") - g.P() - - g.P("// NewStringValue constructs a new string Value.") - g.P("func NewStringValue(v string) *Value {") - g.P(" return &Value{Kind: &Value_StringValue{StringValue: v}}") - g.P("}") - g.P() - - g.P("// NewStructValue constructs a new struct Value.") - g.P("func NewStructValue(v *Struct) *Value {") - g.P(" return &Value{Kind: &Value_StructValue{StructValue: v}}") - g.P("}") - g.P() - - g.P("// NewListValue constructs a new list Value.") - g.P("func NewListValue(v *ListValue) *Value {") - g.P(" return &Value{Kind: &Value_ListValue{ListValue: v}}") - g.P("}") - g.P() - - g.P("// AsInterface converts x to a general-purpose Go interface.") - g.P("//") - g.P("// Calling Value.MarshalJSON and \"encoding/json\".Marshal on this output produce") - g.P("// semantically equivalent JSON (assuming no errors occur).") - g.P("//") - g.P("// Floating-point values (i.e., \"NaN\", \"Infinity\", and \"-Infinity\") are") - g.P("// converted as strings to remain compatible with MarshalJSON.") - g.P("func (x *Value) AsInterface() interface{} {") - g.P(" switch v := x.GetKind().(type) {") - g.P(" case *Value_NumberValue:") - g.P(" if v != nil {") - g.P(" switch {") - g.P(" case ", mathPackage.Ident("IsNaN"), "(v.NumberValue):") - g.P(" return \"NaN\"") - g.P(" case ", mathPackage.Ident("IsInf"), "(v.NumberValue, +1):") - g.P(" return \"Infinity\"") - g.P(" case ", mathPackage.Ident("IsInf"), "(v.NumberValue, -1):") - g.P(" return \"-Infinity\"") - g.P(" default:") - g.P(" return v.NumberValue") - g.P(" }") - g.P(" }") - g.P(" case *Value_StringValue:") - g.P(" if v != nil {") - g.P(" return v.StringValue") - g.P(" }") - g.P(" case *Value_BoolValue:") - g.P(" if v != nil {") - g.P(" return v.BoolValue") - g.P(" }") - g.P(" case *Value_StructValue:") - g.P(" if v != nil {") - g.P(" return v.StructValue.AsMap()") - g.P(" }") - g.P(" case *Value_ListValue:") - g.P(" if v != nil {") - g.P(" return v.ListValue.AsSlice()") - g.P(" }") - g.P(" }") - g.P(" return nil") - g.P("}") - g.P() - - g.P("func (x *Value) MarshalJSON() ([]byte, error) {") - g.P(" return ", protojsonPackage.Ident("Marshal"), "(x)") - g.P("}") - g.P() - - g.P("func (x *Value) UnmarshalJSON(b []byte) error {") - g.P(" return ", protojsonPackage.Ident("Unmarshal"), "(b, x)") - g.P("}") - g.P() - - case genid.FieldMask_message_fullname: - g.P("// New constructs a field mask from a list of paths and verifies that") - g.P("// each one is valid according to the specified message type.") - g.P("func New(m ", protoPackage.Ident("Message"), ", paths ...string) (*FieldMask, error) {") - g.P(" x := new(FieldMask)") - g.P(" return x, x.Append(m, paths...)") - g.P("}") - g.P() - - g.P("// Union returns the union of all the paths in the input field masks.") - g.P("func Union(mx *FieldMask, my *FieldMask, ms ...*FieldMask) *FieldMask {") - g.P(" var out []string") - g.P(" out = append(out, mx.GetPaths()...)") - g.P(" out = append(out, my.GetPaths()...)") - g.P(" for _, m := range ms {") - g.P(" out = append(out, m.GetPaths()...)") - g.P(" }") - g.P(" return &FieldMask{Paths: normalizePaths(out)}") - g.P("}") - g.P() - - g.P("// Intersect returns the intersection of all the paths in the input field masks.") - g.P("func Intersect(mx *FieldMask, my *FieldMask, ms ...*FieldMask) *FieldMask {") - g.P(" var ss1, ss2 []string // reused buffers for performance") - g.P(" intersect := func(out, in []string) []string {") - g.P(" ss1 = normalizePaths(append(ss1[:0], in...))") - g.P(" ss2 = normalizePaths(append(ss2[:0], out...))") - g.P(" out = out[:0]") - g.P(" for i1, i2 := 0, 0; i1 < len(ss1) && i2 < len(ss2); {") - g.P(" switch s1, s2 := ss1[i1], ss2[i2]; {") - g.P(" case hasPathPrefix(s1, s2):") - g.P(" out = append(out, s1)") - g.P(" i1++") - g.P(" case hasPathPrefix(s2, s1):") - g.P(" out = append(out, s2)") - g.P(" i2++") - g.P(" case lessPath(s1, s2):") - g.P(" i1++") - g.P(" case lessPath(s2, s1):") - g.P(" i2++") - g.P(" }") - g.P(" }") - g.P(" return out") - g.P(" }") - g.P() - g.P(" out := Union(mx, my, ms...).GetPaths()") - g.P(" out = intersect(out, mx.GetPaths())") - g.P(" out = intersect(out, my.GetPaths())") - g.P(" for _, m := range ms {") - g.P(" out = intersect(out, m.GetPaths())") - g.P(" }") - g.P(" return &FieldMask{Paths: normalizePaths(out)}") - g.P("}") - g.P() - - g.P("// IsValid reports whether all the paths are syntactically valid and") - g.P("// refer to known fields in the specified message type.") - g.P("// It reports false for a nil FieldMask.") - g.P("func (x *FieldMask) IsValid(m ", protoPackage.Ident("Message"), ") bool {") - g.P(" paths := x.GetPaths()") - g.P(" return x != nil && numValidPaths(m, paths) == len(paths)") - g.P("}") - g.P() - - g.P("// Append appends a list of paths to the mask and verifies that each one") - g.P("// is valid according to the specified message type.") - g.P("// An invalid path is not appended and breaks insertion of subsequent paths.") - g.P("func (x *FieldMask) Append(m ", protoPackage.Ident("Message"), ", paths ...string) error {") - g.P(" numValid := numValidPaths(m, paths)") - g.P(" x.Paths = append(x.Paths, paths[:numValid]...)") - g.P(" paths = paths[numValid:]") - g.P(" if len(paths) > 0 {") - g.P(" name := m.ProtoReflect().Descriptor().FullName()") - g.P(" return ", protoimplPackage.Ident("X"), ".NewError(\"invalid path %q for message %q\", paths[0], name)") - g.P(" }") - g.P(" return nil") - g.P("}") - g.P() - - g.P("func numValidPaths(m ", protoPackage.Ident("Message"), ", paths []string) int {") - g.P(" md0 := m.ProtoReflect().Descriptor()") - g.P(" for i, path := range paths {") - g.P(" md := md0") - g.P(" if !rangeFields(path, func(field string) bool {") - g.P(" // Search the field within the message.") - g.P(" if md == nil {") - g.P(" return false // not within a message") - g.P(" }") - g.P(" fd := md.Fields().ByName(", protoreflectPackage.Ident("Name"), "(field))") - g.P(" // The real field name of a group is the message name.") - g.P(" if fd == nil {") - g.P(" gd := md.Fields().ByName(", protoreflectPackage.Ident("Name"), "(", stringsPackage.Ident("ToLower"), "(field)))") - g.P(" if gd != nil && gd.Kind() == ", protoreflectPackage.Ident("GroupKind"), " && string(gd.Message().Name()) == field {") - g.P(" fd = gd") - g.P(" }") - g.P(" } else if fd.Kind() == ", protoreflectPackage.Ident("GroupKind"), " && string(fd.Message().Name()) != field {") - g.P(" fd = nil") - g.P(" }") - g.P(" if fd == nil {") - g.P(" return false // message has does not have this field") - g.P(" }") - g.P() - g.P(" // Identify the next message to search within.") - g.P(" md = fd.Message() // may be nil") - g.P() - g.P(" // Repeated fields are only allowed at the last position.") - g.P(" if fd.IsList() || fd.IsMap() {") - g.P(" md = nil") - g.P(" }") - g.P() - g.P(" return true") - g.P(" }) {") - g.P(" return i") - g.P(" }") - g.P(" }") - g.P(" return len(paths)") - g.P("}") - g.P() - - g.P("// Normalize converts the mask to its canonical form where all paths are sorted") - g.P("// and redundant paths are removed.") - g.P("func (x *FieldMask) Normalize() {") - g.P(" x.Paths = normalizePaths(x.Paths)") - g.P("}") - g.P() - g.P("func normalizePaths(paths []string) []string {") - g.P(" ", sortPackage.Ident("Slice"), "(paths, func(i, j int) bool {") - g.P(" return lessPath(paths[i], paths[j])") - g.P(" })") - g.P() - g.P(" // Elide any path that is a prefix match on the previous.") - g.P(" out := paths[:0]") - g.P(" for _, path := range paths {") - g.P(" if len(out) > 0 && hasPathPrefix(path, out[len(out)-1]) {") - g.P(" continue") - g.P(" }") - g.P(" out = append(out, path)") - g.P(" }") - g.P(" return out") - g.P("}") - g.P() - - g.P("// hasPathPrefix is like strings.HasPrefix, but further checks for either") - g.P("// an exact matche or that the prefix is delimited by a dot.") - g.P("func hasPathPrefix(path, prefix string) bool {") - g.P(" return ", stringsPackage.Ident("HasPrefix"), "(path, prefix) && (len(path) == len(prefix) || path[len(prefix)] == '.')") - g.P("}") - g.P() - - g.P("// lessPath is a lexicographical comparison where dot is specially treated") - g.P("// as the smallest symbol.") - g.P("func lessPath(x, y string) bool {") - g.P(" for i := 0; i < len(x) && i < len(y); i++ {") - g.P(" if x[i] != y[i] {") - g.P(" return (x[i] - '.') < (y[i] - '.')") - g.P(" }") - g.P(" }") - g.P(" return len(x) < len(y)") - g.P("}") - g.P() - - g.P("// rangeFields is like strings.Split(path, \".\"), but avoids allocations by") - g.P("// iterating over each field in place and calling a iterator function.") - g.P("func rangeFields(path string, f func(field string) bool) bool {") - g.P(" for {") - g.P(" var field string") - g.P(" if i := ", stringsPackage.Ident("IndexByte"), "(path, '.'); i >= 0 {") - g.P(" field, path = path[:i], path[i:]") - g.P(" } else {") - g.P(" field, path = path, \"\"") - g.P(" }") - g.P() - g.P(" if !f(field) {") - g.P(" return false") - g.P(" }") - g.P() - g.P(" if len(path) == 0 {") - g.P(" return true") - g.P(" }") - g.P(" path = ", stringsPackage.Ident("TrimPrefix"), "(path, \".\")") - g.P(" }") - g.P("}") - g.P() - - case genid.BoolValue_message_fullname, - genid.Int32Value_message_fullname, - genid.Int64Value_message_fullname, - genid.UInt32Value_message_fullname, - genid.UInt64Value_message_fullname, - genid.FloatValue_message_fullname, - genid.DoubleValue_message_fullname, - genid.StringValue_message_fullname, - genid.BytesValue_message_fullname: - funcName := strings.TrimSuffix(m.GoIdent.GoName, "Value") - typeName := strings.ToLower(funcName) - switch typeName { - case "float": - typeName = "float32" - case "double": - typeName = "float64" - case "bytes": - typeName = "[]byte" - } - - g.P("// ", funcName, " stores v in a new ", m.GoIdent, " and returns a pointer to it.") - g.P("func ", funcName, "(v ", typeName, ") *", m.GoIdent, " {") - g.P(" return &", m.GoIdent, "{Value: v}") - g.P("}") - g.P() - } -} diff --git a/vendor/google.golang.org/protobuf/compiler/protogen/protogen.go b/vendor/google.golang.org/protobuf/compiler/protogen/protogen.go deleted file mode 100644 index 914c57b1b25..00000000000 --- a/vendor/google.golang.org/protobuf/compiler/protogen/protogen.go +++ /dev/null @@ -1,1391 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package protogen provides support for writing protoc plugins. -// -// Plugins for protoc, the Protocol Buffer compiler, -// are programs which read a [pluginpb.CodeGeneratorRequest] message from standard input -// and write a [pluginpb.CodeGeneratorResponse] message to standard output. -// This package provides support for writing plugins which generate Go code. -package protogen - -import ( - "bufio" - "bytes" - "fmt" - "go/ast" - "go/parser" - "go/printer" - "go/token" - "go/types" - "io/ioutil" - "os" - "path" - "path/filepath" - "sort" - "strconv" - "strings" - - "google.golang.org/protobuf/encoding/prototext" - "google.golang.org/protobuf/internal/genid" - "google.golang.org/protobuf/internal/strs" - "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/reflect/protodesc" - "google.golang.org/protobuf/reflect/protoreflect" - "google.golang.org/protobuf/reflect/protoregistry" - - "google.golang.org/protobuf/types/descriptorpb" - "google.golang.org/protobuf/types/dynamicpb" - "google.golang.org/protobuf/types/pluginpb" -) - -const goPackageDocURL = "https://protobuf.dev/reference/go/go-generated#package" - -// Run executes a function as a protoc plugin. -// -// It reads a [pluginpb.CodeGeneratorRequest] message from [os.Stdin], invokes the plugin -// function, and writes a [pluginpb.CodeGeneratorResponse] message to [os.Stdout]. -// -// If a failure occurs while reading or writing, Run prints an error to -// [os.Stderr] and calls [os.Exit](1). -func (opts Options) Run(f func(*Plugin) error) { - if err := run(opts, f); err != nil { - fmt.Fprintf(os.Stderr, "%s: %v\n", filepath.Base(os.Args[0]), err) - os.Exit(1) - } -} - -func run(opts Options, f func(*Plugin) error) error { - if len(os.Args) > 1 { - return fmt.Errorf("unknown argument %q (this program should be run by protoc, not directly)", os.Args[1]) - } - in, err := ioutil.ReadAll(os.Stdin) - if err != nil { - return err - } - req := &pluginpb.CodeGeneratorRequest{} - if err := proto.Unmarshal(in, req); err != nil { - return err - } - gen, err := opts.New(req) - if err != nil { - return err - } - if err := f(gen); err != nil { - // Errors from the plugin function are reported by setting the - // error field in the CodeGeneratorResponse. - // - // In contrast, errors that indicate a problem in protoc - // itself (unparsable input, I/O errors, etc.) are reported - // to stderr. - gen.Error(err) - } - resp := gen.Response() - out, err := proto.Marshal(resp) - if err != nil { - return err - } - if _, err := os.Stdout.Write(out); err != nil { - return err - } - return nil -} - -// A Plugin is a protoc plugin invocation. -type Plugin struct { - // Request is the CodeGeneratorRequest provided by protoc. - Request *pluginpb.CodeGeneratorRequest - - // Files is the set of files to generate and everything they import. - // Files appear in topological order, so each file appears before any - // file that imports it. - Files []*File - FilesByPath map[string]*File - - // SupportedFeatures is the set of protobuf language features supported by - // this generator plugin. See the documentation for - // google.protobuf.CodeGeneratorResponse.supported_features for details. - SupportedFeatures uint64 - - fileReg *protoregistry.Files - enumsByName map[protoreflect.FullName]*Enum - messagesByName map[protoreflect.FullName]*Message - annotateCode bool - pathType pathType - module string - genFiles []*GeneratedFile - opts Options - err error -} - -type Options struct { - // If ParamFunc is non-nil, it will be called with each unknown - // generator parameter. - // - // Plugins for protoc can accept parameters from the command line, - // passed in the --_out protoc, separated from the output - // directory with a colon; e.g., - // - // --go_out==,=: - // - // Parameters passed in this fashion as a comma-separated list of - // key=value pairs will be passed to the ParamFunc. - // - // The (flag.FlagSet).Set method matches this function signature, - // so parameters can be converted into flags as in the following: - // - // var flags flag.FlagSet - // value := flags.Bool("param", false, "") - // opts := &protogen.Options{ - // ParamFunc: flags.Set, - // } - // protogen.Run(opts, func(p *protogen.Plugin) error { - // if *value { ... } - // }) - ParamFunc func(name, value string) error - - // ImportRewriteFunc is called with the import path of each package - // imported by a generated file. It returns the import path to use - // for this package. - ImportRewriteFunc func(GoImportPath) GoImportPath -} - -// New returns a new Plugin. -func (opts Options) New(req *pluginpb.CodeGeneratorRequest) (*Plugin, error) { - gen := &Plugin{ - Request: req, - FilesByPath: make(map[string]*File), - fileReg: new(protoregistry.Files), - enumsByName: make(map[protoreflect.FullName]*Enum), - messagesByName: make(map[protoreflect.FullName]*Message), - opts: opts, - } - - packageNames := make(map[string]GoPackageName) // filename -> package name - importPaths := make(map[string]GoImportPath) // filename -> import path - for _, param := range strings.Split(req.GetParameter(), ",") { - var value string - if i := strings.Index(param, "="); i >= 0 { - value = param[i+1:] - param = param[0:i] - } - switch param { - case "": - // Ignore. - case "module": - gen.module = value - case "paths": - switch value { - case "import": - gen.pathType = pathTypeImport - case "source_relative": - gen.pathType = pathTypeSourceRelative - default: - return nil, fmt.Errorf(`unknown path type %q: want "import" or "source_relative"`, value) - } - case "annotate_code": - switch value { - case "true", "": - gen.annotateCode = true - case "false": - default: - return nil, fmt.Errorf(`bad value for parameter %q: want "true" or "false"`, param) - } - default: - if param[0] == 'M' { - impPath, pkgName := splitImportPathAndPackageName(value) - if pkgName != "" { - packageNames[param[1:]] = pkgName - } - if impPath != "" { - importPaths[param[1:]] = impPath - } - continue - } - if opts.ParamFunc != nil { - if err := opts.ParamFunc(param, value); err != nil { - return nil, err - } - } - } - } - - // When the module= option is provided, we strip the module name - // prefix from generated files. This only makes sense if generated - // filenames are based on the import path. - if gen.module != "" && gen.pathType == pathTypeSourceRelative { - return nil, fmt.Errorf("cannot use module= with paths=source_relative") - } - - // Figure out the import path and package name for each file. - // - // The rules here are complicated and have grown organically over time. - // Interactions between different ways of specifying package information - // may be surprising. - // - // The recommended approach is to include a go_package option in every - // .proto source file specifying the full import path of the Go package - // associated with this file. - // - // option go_package = "google.golang.org/protobuf/types/known/anypb"; - // - // Alternatively, build systems which want to exert full control over - // import paths may specify M= flags. - for _, fdesc := range gen.Request.ProtoFile { - // The "M" command-line flags take precedence over - // the "go_package" option in the .proto source file. - filename := fdesc.GetName() - impPath, pkgName := splitImportPathAndPackageName(fdesc.GetOptions().GetGoPackage()) - if importPaths[filename] == "" && impPath != "" { - importPaths[filename] = impPath - } - if packageNames[filename] == "" && pkgName != "" { - packageNames[filename] = pkgName - } - switch { - case importPaths[filename] == "": - // The import path must be specified one way or another. - return nil, fmt.Errorf( - "unable to determine Go import path for %q\n\n"+ - "Please specify either:\n"+ - "\t• a \"go_package\" option in the .proto source file, or\n"+ - "\t• a \"M\" argument on the command line.\n\n"+ - "See %v for more information.\n", - fdesc.GetName(), goPackageDocURL) - case !strings.Contains(string(importPaths[filename]), ".") && - !strings.Contains(string(importPaths[filename]), "/"): - // Check that import paths contain at least a dot or slash to avoid - // a common mistake where import path is confused with package name. - return nil, fmt.Errorf( - "invalid Go import path %q for %q\n\n"+ - "The import path must contain at least one period ('.') or forward slash ('/') character.\n\n"+ - "See %v for more information.\n", - string(importPaths[filename]), fdesc.GetName(), goPackageDocURL) - case packageNames[filename] == "": - // If the package name is not explicitly specified, - // then derive a reasonable package name from the import path. - // - // NOTE: The package name is derived first from the import path in - // the "go_package" option (if present) before trying the "M" flag. - // The inverted order for this is because the primary use of the "M" - // flag is by build systems that have full control over the - // import paths all packages, where it is generally expected that - // the Go package name still be identical for the Go toolchain and - // for custom build systems like Bazel. - if impPath == "" { - impPath = importPaths[filename] - } - packageNames[filename] = cleanPackageName(path.Base(string(impPath))) - } - } - - // Consistency check: Every file with the same Go import path should have - // the same Go package name. - packageFiles := make(map[GoImportPath][]string) - for filename, importPath := range importPaths { - if _, ok := packageNames[filename]; !ok { - // Skip files mentioned in a M= parameter - // but which do not appear in the CodeGeneratorRequest. - continue - } - packageFiles[importPath] = append(packageFiles[importPath], filename) - } - for importPath, filenames := range packageFiles { - for i := 1; i < len(filenames); i++ { - if a, b := packageNames[filenames[0]], packageNames[filenames[i]]; a != b { - return nil, fmt.Errorf("Go package %v has inconsistent names %v (%v) and %v (%v)", - importPath, a, filenames[0], b, filenames[i]) - } - } - } - - // The extracted types from the full import set - typeRegistry := newExtensionRegistry() - for _, fdesc := range gen.Request.ProtoFile { - filename := fdesc.GetName() - if gen.FilesByPath[filename] != nil { - return nil, fmt.Errorf("duplicate file name: %q", filename) - } - f, err := newFile(gen, fdesc, packageNames[filename], importPaths[filename]) - if err != nil { - return nil, err - } - gen.Files = append(gen.Files, f) - gen.FilesByPath[filename] = f - if err = typeRegistry.registerAllExtensionsFromFile(f.Desc); err != nil { - return nil, err - } - } - for _, filename := range gen.Request.FileToGenerate { - f, ok := gen.FilesByPath[filename] - if !ok { - return nil, fmt.Errorf("no descriptor for generated file: %v", filename) - } - f.Generate = true - } - - // Create fully-linked descriptors if new extensions were found - if typeRegistry.hasNovelExtensions() { - for _, f := range gen.Files { - b, err := proto.Marshal(f.Proto.ProtoReflect().Interface()) - if err != nil { - return nil, err - } - err = proto.UnmarshalOptions{Resolver: typeRegistry}.Unmarshal(b, f.Proto) - if err != nil { - return nil, err - } - } - } - return gen, nil -} - -// Error records an error in code generation. The generator will report the -// error back to protoc and will not produce output. -func (gen *Plugin) Error(err error) { - if gen.err == nil { - gen.err = err - } -} - -// Response returns the generator output. -func (gen *Plugin) Response() *pluginpb.CodeGeneratorResponse { - resp := &pluginpb.CodeGeneratorResponse{} - if gen.err != nil { - resp.Error = proto.String(gen.err.Error()) - return resp - } - for _, g := range gen.genFiles { - if g.skip { - continue - } - content, err := g.Content() - if err != nil { - return &pluginpb.CodeGeneratorResponse{ - Error: proto.String(err.Error()), - } - } - filename := g.filename - if gen.module != "" { - trim := gen.module + "/" - if !strings.HasPrefix(filename, trim) { - return &pluginpb.CodeGeneratorResponse{ - Error: proto.String(fmt.Sprintf("%v: generated file does not match prefix %q", filename, gen.module)), - } - } - filename = strings.TrimPrefix(filename, trim) - } - resp.File = append(resp.File, &pluginpb.CodeGeneratorResponse_File{ - Name: proto.String(filename), - Content: proto.String(string(content)), - }) - if gen.annotateCode && strings.HasSuffix(g.filename, ".go") { - meta, err := g.metaFile(content) - if err != nil { - return &pluginpb.CodeGeneratorResponse{ - Error: proto.String(err.Error()), - } - } - resp.File = append(resp.File, &pluginpb.CodeGeneratorResponse_File{ - Name: proto.String(filename + ".meta"), - Content: proto.String(meta), - }) - } - } - if gen.SupportedFeatures > 0 { - resp.SupportedFeatures = proto.Uint64(gen.SupportedFeatures) - } - return resp -} - -// A File describes a .proto source file. -type File struct { - Desc protoreflect.FileDescriptor - Proto *descriptorpb.FileDescriptorProto - - GoDescriptorIdent GoIdent // name of Go variable for the file descriptor - GoPackageName GoPackageName // name of this file's Go package - GoImportPath GoImportPath // import path of this file's Go package - - Enums []*Enum // top-level enum declarations - Messages []*Message // top-level message declarations - Extensions []*Extension // top-level extension declarations - Services []*Service // top-level service declarations - - Generate bool // true if we should generate code for this file - - // GeneratedFilenamePrefix is used to construct filenames for generated - // files associated with this source file. - // - // For example, the source file "dir/foo.proto" might have a filename prefix - // of "dir/foo". Appending ".pb.go" produces an output file of "dir/foo.pb.go". - GeneratedFilenamePrefix string - - location Location -} - -func newFile(gen *Plugin, p *descriptorpb.FileDescriptorProto, packageName GoPackageName, importPath GoImportPath) (*File, error) { - desc, err := protodesc.NewFile(p, gen.fileReg) - if err != nil { - return nil, fmt.Errorf("invalid FileDescriptorProto %q: %v", p.GetName(), err) - } - if err := gen.fileReg.RegisterFile(desc); err != nil { - return nil, fmt.Errorf("cannot register descriptor %q: %v", p.GetName(), err) - } - f := &File{ - Desc: desc, - Proto: p, - GoPackageName: packageName, - GoImportPath: importPath, - location: Location{SourceFile: desc.Path()}, - } - - // Determine the prefix for generated Go files. - prefix := p.GetName() - if ext := path.Ext(prefix); ext == ".proto" || ext == ".protodevel" { - prefix = prefix[:len(prefix)-len(ext)] - } - switch gen.pathType { - case pathTypeImport: - // If paths=import, the output filename is derived from the Go import path. - prefix = path.Join(string(f.GoImportPath), path.Base(prefix)) - case pathTypeSourceRelative: - // If paths=source_relative, the output filename is derived from - // the input filename. - } - f.GoDescriptorIdent = GoIdent{ - GoName: "File_" + strs.GoSanitized(p.GetName()), - GoImportPath: f.GoImportPath, - } - f.GeneratedFilenamePrefix = prefix - - for i, eds := 0, desc.Enums(); i < eds.Len(); i++ { - f.Enums = append(f.Enums, newEnum(gen, f, nil, eds.Get(i))) - } - for i, mds := 0, desc.Messages(); i < mds.Len(); i++ { - f.Messages = append(f.Messages, newMessage(gen, f, nil, mds.Get(i))) - } - for i, xds := 0, desc.Extensions(); i < xds.Len(); i++ { - f.Extensions = append(f.Extensions, newField(gen, f, nil, xds.Get(i))) - } - for i, sds := 0, desc.Services(); i < sds.Len(); i++ { - f.Services = append(f.Services, newService(gen, f, sds.Get(i))) - } - for _, message := range f.Messages { - if err := message.resolveDependencies(gen); err != nil { - return nil, err - } - } - for _, extension := range f.Extensions { - if err := extension.resolveDependencies(gen); err != nil { - return nil, err - } - } - for _, service := range f.Services { - for _, method := range service.Methods { - if err := method.resolveDependencies(gen); err != nil { - return nil, err - } - } - } - return f, nil -} - -// splitImportPathAndPackageName splits off the optional Go package name -// from the Go import path when separated by a ';' delimiter. -func splitImportPathAndPackageName(s string) (GoImportPath, GoPackageName) { - if i := strings.Index(s, ";"); i >= 0 { - return GoImportPath(s[:i]), GoPackageName(s[i+1:]) - } - return GoImportPath(s), "" -} - -// An Enum describes an enum. -type Enum struct { - Desc protoreflect.EnumDescriptor - - GoIdent GoIdent // name of the generated Go type - - Values []*EnumValue // enum value declarations - - Location Location // location of this enum - Comments CommentSet // comments associated with this enum -} - -func newEnum(gen *Plugin, f *File, parent *Message, desc protoreflect.EnumDescriptor) *Enum { - var loc Location - if parent != nil { - loc = parent.Location.appendPath(genid.DescriptorProto_EnumType_field_number, desc.Index()) - } else { - loc = f.location.appendPath(genid.FileDescriptorProto_EnumType_field_number, desc.Index()) - } - enum := &Enum{ - Desc: desc, - GoIdent: newGoIdent(f, desc), - Location: loc, - Comments: makeCommentSet(f.Desc.SourceLocations().ByDescriptor(desc)), - } - gen.enumsByName[desc.FullName()] = enum - for i, vds := 0, enum.Desc.Values(); i < vds.Len(); i++ { - enum.Values = append(enum.Values, newEnumValue(gen, f, parent, enum, vds.Get(i))) - } - return enum -} - -// An EnumValue describes an enum value. -type EnumValue struct { - Desc protoreflect.EnumValueDescriptor - - GoIdent GoIdent // name of the generated Go declaration - - Parent *Enum // enum in which this value is declared - - Location Location // location of this enum value - Comments CommentSet // comments associated with this enum value -} - -func newEnumValue(gen *Plugin, f *File, message *Message, enum *Enum, desc protoreflect.EnumValueDescriptor) *EnumValue { - // A top-level enum value's name is: EnumName_ValueName - // An enum value contained in a message is: MessageName_ValueName - // - // For historical reasons, enum value names are not camel-cased. - parentIdent := enum.GoIdent - if message != nil { - parentIdent = message.GoIdent - } - name := parentIdent.GoName + "_" + string(desc.Name()) - loc := enum.Location.appendPath(genid.EnumDescriptorProto_Value_field_number, desc.Index()) - return &EnumValue{ - Desc: desc, - GoIdent: f.GoImportPath.Ident(name), - Parent: enum, - Location: loc, - Comments: makeCommentSet(f.Desc.SourceLocations().ByDescriptor(desc)), - } -} - -// A Message describes a message. -type Message struct { - Desc protoreflect.MessageDescriptor - - GoIdent GoIdent // name of the generated Go type - - Fields []*Field // message field declarations - Oneofs []*Oneof // message oneof declarations - - Enums []*Enum // nested enum declarations - Messages []*Message // nested message declarations - Extensions []*Extension // nested extension declarations - - Location Location // location of this message - Comments CommentSet // comments associated with this message -} - -func newMessage(gen *Plugin, f *File, parent *Message, desc protoreflect.MessageDescriptor) *Message { - var loc Location - if parent != nil { - loc = parent.Location.appendPath(genid.DescriptorProto_NestedType_field_number, desc.Index()) - } else { - loc = f.location.appendPath(genid.FileDescriptorProto_MessageType_field_number, desc.Index()) - } - message := &Message{ - Desc: desc, - GoIdent: newGoIdent(f, desc), - Location: loc, - Comments: makeCommentSet(f.Desc.SourceLocations().ByDescriptor(desc)), - } - gen.messagesByName[desc.FullName()] = message - for i, eds := 0, desc.Enums(); i < eds.Len(); i++ { - message.Enums = append(message.Enums, newEnum(gen, f, message, eds.Get(i))) - } - for i, mds := 0, desc.Messages(); i < mds.Len(); i++ { - message.Messages = append(message.Messages, newMessage(gen, f, message, mds.Get(i))) - } - for i, fds := 0, desc.Fields(); i < fds.Len(); i++ { - message.Fields = append(message.Fields, newField(gen, f, message, fds.Get(i))) - } - for i, ods := 0, desc.Oneofs(); i < ods.Len(); i++ { - message.Oneofs = append(message.Oneofs, newOneof(gen, f, message, ods.Get(i))) - } - for i, xds := 0, desc.Extensions(); i < xds.Len(); i++ { - message.Extensions = append(message.Extensions, newField(gen, f, message, xds.Get(i))) - } - - // Resolve local references between fields and oneofs. - for _, field := range message.Fields { - if od := field.Desc.ContainingOneof(); od != nil { - oneof := message.Oneofs[od.Index()] - field.Oneof = oneof - oneof.Fields = append(oneof.Fields, field) - } - } - - // Field name conflict resolution. - // - // We assume well-known method names that may be attached to a generated - // message type, as well as a 'Get*' method for each field. For each - // field in turn, we add _s to its name until there are no conflicts. - // - // Any change to the following set of method names is a potential - // incompatible API change because it may change generated field names. - // - // TODO: If we ever support a 'go_name' option to set the Go name of a - // field, we should consider dropping this entirely. The conflict - // resolution algorithm is subtle and surprising (changing the order - // in which fields appear in the .proto source file can change the - // names of fields in generated code), and does not adapt well to - // adding new per-field methods such as setters. - usedNames := map[string]bool{ - "Reset": true, - "String": true, - "ProtoMessage": true, - "Marshal": true, - "Unmarshal": true, - "ExtensionRangeArray": true, - "ExtensionMap": true, - "Descriptor": true, - } - makeNameUnique := func(name string, hasGetter bool) string { - for usedNames[name] || (hasGetter && usedNames["Get"+name]) { - name += "_" - } - usedNames[name] = true - usedNames["Get"+name] = hasGetter - return name - } - for _, field := range message.Fields { - field.GoName = makeNameUnique(field.GoName, true) - field.GoIdent.GoName = message.GoIdent.GoName + "_" + field.GoName - if field.Oneof != nil && field.Oneof.Fields[0] == field { - // Make the name for a oneof unique as well. For historical reasons, - // this assumes that a getter method is not generated for oneofs. - // This is incorrect, but fixing it breaks existing code. - field.Oneof.GoName = makeNameUnique(field.Oneof.GoName, false) - field.Oneof.GoIdent.GoName = message.GoIdent.GoName + "_" + field.Oneof.GoName - } - } - - // Oneof field name conflict resolution. - // - // This conflict resolution is incomplete as it does not consider collisions - // with other oneof field types, but fixing it breaks existing code. - for _, field := range message.Fields { - if field.Oneof != nil { - Loop: - for { - for _, nestedMessage := range message.Messages { - if nestedMessage.GoIdent == field.GoIdent { - field.GoIdent.GoName += "_" - continue Loop - } - } - for _, nestedEnum := range message.Enums { - if nestedEnum.GoIdent == field.GoIdent { - field.GoIdent.GoName += "_" - continue Loop - } - } - break Loop - } - } - } - - return message -} - -func (message *Message) resolveDependencies(gen *Plugin) error { - for _, field := range message.Fields { - if err := field.resolveDependencies(gen); err != nil { - return err - } - } - for _, message := range message.Messages { - if err := message.resolveDependencies(gen); err != nil { - return err - } - } - for _, extension := range message.Extensions { - if err := extension.resolveDependencies(gen); err != nil { - return err - } - } - return nil -} - -// A Field describes a message field. -type Field struct { - Desc protoreflect.FieldDescriptor - - // GoName is the base name of this field's Go field and methods. - // For code generated by protoc-gen-go, this means a field named - // '{{GoName}}' and a getter method named 'Get{{GoName}}'. - GoName string // e.g., "FieldName" - - // GoIdent is the base name of a top-level declaration for this field. - // For code generated by protoc-gen-go, this means a wrapper type named - // '{{GoIdent}}' for members fields of a oneof, and a variable named - // 'E_{{GoIdent}}' for extension fields. - GoIdent GoIdent // e.g., "MessageName_FieldName" - - Parent *Message // message in which this field is declared; nil if top-level extension - Oneof *Oneof // containing oneof; nil if not part of a oneof - Extendee *Message // extended message for extension fields; nil otherwise - - Enum *Enum // type for enum fields; nil otherwise - Message *Message // type for message or group fields; nil otherwise - - Location Location // location of this field - Comments CommentSet // comments associated with this field -} - -func newField(gen *Plugin, f *File, message *Message, desc protoreflect.FieldDescriptor) *Field { - var loc Location - switch { - case desc.IsExtension() && message == nil: - loc = f.location.appendPath(genid.FileDescriptorProto_Extension_field_number, desc.Index()) - case desc.IsExtension() && message != nil: - loc = message.Location.appendPath(genid.DescriptorProto_Extension_field_number, desc.Index()) - default: - loc = message.Location.appendPath(genid.DescriptorProto_Field_field_number, desc.Index()) - } - camelCased := strs.GoCamelCase(string(desc.Name())) - var parentPrefix string - if message != nil { - parentPrefix = message.GoIdent.GoName + "_" - } - field := &Field{ - Desc: desc, - GoName: camelCased, - GoIdent: GoIdent{ - GoImportPath: f.GoImportPath, - GoName: parentPrefix + camelCased, - }, - Parent: message, - Location: loc, - Comments: makeCommentSet(f.Desc.SourceLocations().ByDescriptor(desc)), - } - return field -} - -func (field *Field) resolveDependencies(gen *Plugin) error { - desc := field.Desc - switch desc.Kind() { - case protoreflect.EnumKind: - name := field.Desc.Enum().FullName() - enum, ok := gen.enumsByName[name] - if !ok { - return fmt.Errorf("field %v: no descriptor for enum %v", desc.FullName(), name) - } - field.Enum = enum - case protoreflect.MessageKind, protoreflect.GroupKind: - name := desc.Message().FullName() - message, ok := gen.messagesByName[name] - if !ok { - return fmt.Errorf("field %v: no descriptor for type %v", desc.FullName(), name) - } - field.Message = message - } - if desc.IsExtension() { - name := desc.ContainingMessage().FullName() - message, ok := gen.messagesByName[name] - if !ok { - return fmt.Errorf("field %v: no descriptor for type %v", desc.FullName(), name) - } - field.Extendee = message - } - return nil -} - -// A Oneof describes a message oneof. -type Oneof struct { - Desc protoreflect.OneofDescriptor - - // GoName is the base name of this oneof's Go field and methods. - // For code generated by protoc-gen-go, this means a field named - // '{{GoName}}' and a getter method named 'Get{{GoName}}'. - GoName string // e.g., "OneofName" - - // GoIdent is the base name of a top-level declaration for this oneof. - GoIdent GoIdent // e.g., "MessageName_OneofName" - - Parent *Message // message in which this oneof is declared - - Fields []*Field // fields that are part of this oneof - - Location Location // location of this oneof - Comments CommentSet // comments associated with this oneof -} - -func newOneof(gen *Plugin, f *File, message *Message, desc protoreflect.OneofDescriptor) *Oneof { - loc := message.Location.appendPath(genid.DescriptorProto_OneofDecl_field_number, desc.Index()) - camelCased := strs.GoCamelCase(string(desc.Name())) - parentPrefix := message.GoIdent.GoName + "_" - return &Oneof{ - Desc: desc, - Parent: message, - GoName: camelCased, - GoIdent: GoIdent{ - GoImportPath: f.GoImportPath, - GoName: parentPrefix + camelCased, - }, - Location: loc, - Comments: makeCommentSet(f.Desc.SourceLocations().ByDescriptor(desc)), - } -} - -// Extension is an alias of [Field] for documentation. -type Extension = Field - -// A Service describes a service. -type Service struct { - Desc protoreflect.ServiceDescriptor - - GoName string - - Methods []*Method // service method declarations - - Location Location // location of this service - Comments CommentSet // comments associated with this service -} - -func newService(gen *Plugin, f *File, desc protoreflect.ServiceDescriptor) *Service { - loc := f.location.appendPath(genid.FileDescriptorProto_Service_field_number, desc.Index()) - service := &Service{ - Desc: desc, - GoName: strs.GoCamelCase(string(desc.Name())), - Location: loc, - Comments: makeCommentSet(f.Desc.SourceLocations().ByDescriptor(desc)), - } - for i, mds := 0, desc.Methods(); i < mds.Len(); i++ { - service.Methods = append(service.Methods, newMethod(gen, f, service, mds.Get(i))) - } - return service -} - -// A Method describes a method in a service. -type Method struct { - Desc protoreflect.MethodDescriptor - - GoName string - - Parent *Service // service in which this method is declared - - Input *Message - Output *Message - - Location Location // location of this method - Comments CommentSet // comments associated with this method -} - -func newMethod(gen *Plugin, f *File, service *Service, desc protoreflect.MethodDescriptor) *Method { - loc := service.Location.appendPath(genid.ServiceDescriptorProto_Method_field_number, desc.Index()) - method := &Method{ - Desc: desc, - GoName: strs.GoCamelCase(string(desc.Name())), - Parent: service, - Location: loc, - Comments: makeCommentSet(f.Desc.SourceLocations().ByDescriptor(desc)), - } - return method -} - -func (method *Method) resolveDependencies(gen *Plugin) error { - desc := method.Desc - - inName := desc.Input().FullName() - in, ok := gen.messagesByName[inName] - if !ok { - return fmt.Errorf("method %v: no descriptor for type %v", desc.FullName(), inName) - } - method.Input = in - - outName := desc.Output().FullName() - out, ok := gen.messagesByName[outName] - if !ok { - return fmt.Errorf("method %v: no descriptor for type %v", desc.FullName(), outName) - } - method.Output = out - - return nil -} - -// A GeneratedFile is a generated file. -type GeneratedFile struct { - gen *Plugin - skip bool - filename string - goImportPath GoImportPath - buf bytes.Buffer - packageNames map[GoImportPath]GoPackageName - usedPackageNames map[GoPackageName]bool - manualImports map[GoImportPath]bool - annotations map[string][]Annotation -} - -// NewGeneratedFile creates a new generated file with the given filename -// and import path. -func (gen *Plugin) NewGeneratedFile(filename string, goImportPath GoImportPath) *GeneratedFile { - g := &GeneratedFile{ - gen: gen, - filename: filename, - goImportPath: goImportPath, - packageNames: make(map[GoImportPath]GoPackageName), - usedPackageNames: make(map[GoPackageName]bool), - manualImports: make(map[GoImportPath]bool), - annotations: make(map[string][]Annotation), - } - - // All predeclared identifiers in Go are already used. - for _, s := range types.Universe.Names() { - g.usedPackageNames[GoPackageName(s)] = true - } - - gen.genFiles = append(gen.genFiles, g) - return g -} - -// P prints a line to the generated output. It converts each parameter to a -// string following the same rules as [fmt.Print]. It never inserts spaces -// between parameters. -func (g *GeneratedFile) P(v ...interface{}) { - for _, x := range v { - switch x := x.(type) { - case GoIdent: - fmt.Fprint(&g.buf, g.QualifiedGoIdent(x)) - default: - fmt.Fprint(&g.buf, x) - } - } - fmt.Fprintln(&g.buf) -} - -// QualifiedGoIdent returns the string to use for a Go identifier. -// -// If the identifier is from a different Go package than the generated file, -// the returned name will be qualified (package.name) and an import statement -// for the identifier's package will be included in the file. -func (g *GeneratedFile) QualifiedGoIdent(ident GoIdent) string { - if ident.GoImportPath == g.goImportPath { - return ident.GoName - } - if packageName, ok := g.packageNames[ident.GoImportPath]; ok { - return string(packageName) + "." + ident.GoName - } - packageName := cleanPackageName(path.Base(string(ident.GoImportPath))) - for i, orig := 1, packageName; g.usedPackageNames[packageName]; i++ { - packageName = orig + GoPackageName(strconv.Itoa(i)) - } - g.packageNames[ident.GoImportPath] = packageName - g.usedPackageNames[packageName] = true - return string(packageName) + "." + ident.GoName -} - -// Import ensures a package is imported by the generated file. -// -// Packages referenced by [GeneratedFile.QualifiedGoIdent] are automatically imported. -// Explicitly importing a package with Import is generally only necessary -// when the import will be blank (import _ "package"). -func (g *GeneratedFile) Import(importPath GoImportPath) { - g.manualImports[importPath] = true -} - -// Write implements [io.Writer]. -func (g *GeneratedFile) Write(p []byte) (n int, err error) { - return g.buf.Write(p) -} - -// Skip removes the generated file from the plugin output. -func (g *GeneratedFile) Skip() { - g.skip = true -} - -// Unskip reverts a previous call to [GeneratedFile.Skip], -// re-including the generated file in the plugin output. -func (g *GeneratedFile) Unskip() { - g.skip = false -} - -// Annotate associates a symbol in a generated Go file with a location in a -// source .proto file. -// -// The symbol may refer to a type, constant, variable, function, method, or -// struct field. The "T.sel" syntax is used to identify the method or field -// 'sel' on type 'T'. -// -// Deprecated: Use the [GeneratedFile.AnnotateSymbol] method instead. -func (g *GeneratedFile) Annotate(symbol string, loc Location) { - g.AnnotateSymbol(symbol, Annotation{Location: loc}) -} - -// An Annotation provides semantic detail for a generated proto element. -// -// See the google.protobuf.GeneratedCodeInfo.Annotation documentation in -// descriptor.proto for details. -type Annotation struct { - // Location is the source .proto file for the element. - Location Location - - // Semantic is the symbol's effect on the element in the original .proto file. - Semantic *descriptorpb.GeneratedCodeInfo_Annotation_Semantic -} - -// AnnotateSymbol associates a symbol in a generated Go file with a location -// in a source .proto file and a semantic type. -// -// The symbol may refer to a type, constant, variable, function, method, or -// struct field. The "T.sel" syntax is used to identify the method or field -// 'sel' on type 'T'. -func (g *GeneratedFile) AnnotateSymbol(symbol string, info Annotation) { - g.annotations[symbol] = append(g.annotations[symbol], info) -} - -// Content returns the contents of the generated file. -func (g *GeneratedFile) Content() ([]byte, error) { - if !strings.HasSuffix(g.filename, ".go") { - return g.buf.Bytes(), nil - } - - // Reformat generated code. - original := g.buf.Bytes() - fset := token.NewFileSet() - file, err := parser.ParseFile(fset, "", original, parser.ParseComments) - if err != nil { - // Print out the bad code with line numbers. - // This should never happen in practice, but it can while changing generated code - // so consider this a debugging aid. - var src bytes.Buffer - s := bufio.NewScanner(bytes.NewReader(original)) - for line := 1; s.Scan(); line++ { - fmt.Fprintf(&src, "%5d\t%s\n", line, s.Bytes()) - } - return nil, fmt.Errorf("%v: unparsable Go source: %v\n%v", g.filename, err, src.String()) - } - - // Collect a sorted list of all imports. - var importPaths [][2]string - rewriteImport := func(importPath string) string { - if f := g.gen.opts.ImportRewriteFunc; f != nil { - return string(f(GoImportPath(importPath))) - } - return importPath - } - for importPath := range g.packageNames { - pkgName := string(g.packageNames[GoImportPath(importPath)]) - pkgPath := rewriteImport(string(importPath)) - importPaths = append(importPaths, [2]string{pkgName, pkgPath}) - } - for importPath := range g.manualImports { - if _, ok := g.packageNames[importPath]; !ok { - pkgPath := rewriteImport(string(importPath)) - importPaths = append(importPaths, [2]string{"_", pkgPath}) - } - } - sort.Slice(importPaths, func(i, j int) bool { - return importPaths[i][1] < importPaths[j][1] - }) - - // Modify the AST to include a new import block. - if len(importPaths) > 0 { - // Insert block after package statement or - // possible comment attached to the end of the package statement. - pos := file.Package - tokFile := fset.File(file.Package) - pkgLine := tokFile.Line(file.Package) - for _, c := range file.Comments { - if tokFile.Line(c.Pos()) > pkgLine { - break - } - pos = c.End() - } - - // Construct the import block. - impDecl := &ast.GenDecl{ - Tok: token.IMPORT, - TokPos: pos, - Lparen: pos, - Rparen: pos, - } - for _, importPath := range importPaths { - impDecl.Specs = append(impDecl.Specs, &ast.ImportSpec{ - Name: &ast.Ident{ - Name: importPath[0], - NamePos: pos, - }, - Path: &ast.BasicLit{ - Kind: token.STRING, - Value: strconv.Quote(importPath[1]), - ValuePos: pos, - }, - EndPos: pos, - }) - } - file.Decls = append([]ast.Decl{impDecl}, file.Decls...) - } - - var out bytes.Buffer - if err = (&printer.Config{Mode: printer.TabIndent | printer.UseSpaces, Tabwidth: 8}).Fprint(&out, fset, file); err != nil { - return nil, fmt.Errorf("%v: can not reformat Go source: %v", g.filename, err) - } - return out.Bytes(), nil -} - -func (g *GeneratedFile) generatedCodeInfo(content []byte) (*descriptorpb.GeneratedCodeInfo, error) { - fset := token.NewFileSet() - astFile, err := parser.ParseFile(fset, "", content, 0) - if err != nil { - return nil, err - } - info := &descriptorpb.GeneratedCodeInfo{} - - seenAnnotations := make(map[string]bool) - annotate := func(s string, ident *ast.Ident) { - seenAnnotations[s] = true - for _, a := range g.annotations[s] { - info.Annotation = append(info.Annotation, &descriptorpb.GeneratedCodeInfo_Annotation{ - SourceFile: proto.String(a.Location.SourceFile), - Path: a.Location.Path, - Begin: proto.Int32(int32(fset.Position(ident.Pos()).Offset)), - End: proto.Int32(int32(fset.Position(ident.End()).Offset)), - Semantic: a.Semantic, - }) - } - } - for _, decl := range astFile.Decls { - switch decl := decl.(type) { - case *ast.GenDecl: - for _, spec := range decl.Specs { - switch spec := spec.(type) { - case *ast.TypeSpec: - annotate(spec.Name.Name, spec.Name) - switch st := spec.Type.(type) { - case *ast.StructType: - for _, field := range st.Fields.List { - for _, name := range field.Names { - annotate(spec.Name.Name+"."+name.Name, name) - } - } - case *ast.InterfaceType: - for _, field := range st.Methods.List { - for _, name := range field.Names { - annotate(spec.Name.Name+"."+name.Name, name) - } - } - } - case *ast.ValueSpec: - for _, name := range spec.Names { - annotate(name.Name, name) - } - } - } - case *ast.FuncDecl: - if decl.Recv == nil { - annotate(decl.Name.Name, decl.Name) - } else { - recv := decl.Recv.List[0].Type - if s, ok := recv.(*ast.StarExpr); ok { - recv = s.X - } - if id, ok := recv.(*ast.Ident); ok { - annotate(id.Name+"."+decl.Name.Name, decl.Name) - } - } - } - } - for a := range g.annotations { - if !seenAnnotations[a] { - return nil, fmt.Errorf("%v: no symbol matching annotation %q", g.filename, a) - } - } - - return info, nil -} - -// metaFile returns the contents of the file's metadata file, which is a -// text formatted string of the google.protobuf.GeneratedCodeInfo. -func (g *GeneratedFile) metaFile(content []byte) (string, error) { - info, err := g.generatedCodeInfo(content) - if err != nil { - return "", err - } - - b, err := prototext.Marshal(info) - if err != nil { - return "", err - } - return string(b), nil -} - -// A GoIdent is a Go identifier, consisting of a name and import path. -// The name is a single identifier and may not be a dot-qualified selector. -type GoIdent struct { - GoName string - GoImportPath GoImportPath -} - -func (id GoIdent) String() string { return fmt.Sprintf("%q.%v", id.GoImportPath, id.GoName) } - -// newGoIdent returns the Go identifier for a descriptor. -func newGoIdent(f *File, d protoreflect.Descriptor) GoIdent { - name := strings.TrimPrefix(string(d.FullName()), string(f.Desc.Package())+".") - return GoIdent{ - GoName: strs.GoCamelCase(name), - GoImportPath: f.GoImportPath, - } -} - -// A GoImportPath is the import path of a Go package. -// For example: "google.golang.org/protobuf/compiler/protogen" -type GoImportPath string - -func (p GoImportPath) String() string { return strconv.Quote(string(p)) } - -// Ident returns a GoIdent with s as the GoName and p as the GoImportPath. -func (p GoImportPath) Ident(s string) GoIdent { - return GoIdent{GoName: s, GoImportPath: p} -} - -// A GoPackageName is the name of a Go package. e.g., "protobuf". -type GoPackageName string - -// cleanPackageName converts a string to a valid Go package name. -func cleanPackageName(name string) GoPackageName { - return GoPackageName(strs.GoSanitized(name)) -} - -type pathType int - -const ( - pathTypeImport pathType = iota - pathTypeSourceRelative -) - -// A Location is a location in a .proto source file. -// -// See the google.protobuf.SourceCodeInfo documentation in descriptor.proto -// for details. -type Location struct { - SourceFile string - Path protoreflect.SourcePath -} - -// appendPath add elements to a Location's path, returning a new Location. -func (loc Location) appendPath(num protoreflect.FieldNumber, idx int) Location { - loc.Path = append(protoreflect.SourcePath(nil), loc.Path...) // make copy - loc.Path = append(loc.Path, int32(num), int32(idx)) - return loc -} - -// CommentSet is a set of leading and trailing comments associated -// with a .proto descriptor declaration. -type CommentSet struct { - LeadingDetached []Comments - Leading Comments - Trailing Comments -} - -func makeCommentSet(loc protoreflect.SourceLocation) CommentSet { - var leadingDetached []Comments - for _, s := range loc.LeadingDetachedComments { - leadingDetached = append(leadingDetached, Comments(s)) - } - return CommentSet{ - LeadingDetached: leadingDetached, - Leading: Comments(loc.LeadingComments), - Trailing: Comments(loc.TrailingComments), - } -} - -// Comments is a comments string as provided by protoc. -type Comments string - -// String formats the comments by inserting // to the start of each line, -// ensuring that there is a trailing newline. -// An empty comment is formatted as an empty string. -func (c Comments) String() string { - if c == "" { - return "" - } - var b []byte - for _, line := range strings.Split(strings.TrimSuffix(string(c), "\n"), "\n") { - b = append(b, "//"...) - b = append(b, line...) - b = append(b, "\n"...) - } - return string(b) -} - -// extensionRegistry allows registration of new extensions defined in the .proto -// file for which we are generating bindings. -// -// Lookups consult the local type registry first and fall back to the base type -// registry which defaults to protoregistry.GlobalTypes. -type extensionRegistry struct { - base *protoregistry.Types - local *protoregistry.Types -} - -func newExtensionRegistry() *extensionRegistry { - return &extensionRegistry{ - base: protoregistry.GlobalTypes, - local: &protoregistry.Types{}, - } -} - -// FindExtensionByName implements proto.UnmarshalOptions.FindExtensionByName -func (e *extensionRegistry) FindExtensionByName(field protoreflect.FullName) (protoreflect.ExtensionType, error) { - if xt, err := e.local.FindExtensionByName(field); err == nil { - return xt, nil - } - - return e.base.FindExtensionByName(field) -} - -// FindExtensionByNumber implements proto.UnmarshalOptions.FindExtensionByNumber -func (e *extensionRegistry) FindExtensionByNumber(message protoreflect.FullName, field protoreflect.FieldNumber) (protoreflect.ExtensionType, error) { - if xt, err := e.local.FindExtensionByNumber(message, field); err == nil { - return xt, nil - } - - return e.base.FindExtensionByNumber(message, field) -} - -func (e *extensionRegistry) hasNovelExtensions() bool { - return e.local.NumExtensions() > 0 -} - -func (e *extensionRegistry) registerAllExtensionsFromFile(f protoreflect.FileDescriptor) error { - if err := e.registerAllExtensions(f.Extensions()); err != nil { - return err - } - return nil -} - -func (e *extensionRegistry) registerAllExtensionsFromMessage(ms protoreflect.MessageDescriptors) error { - for i := 0; i < ms.Len(); i++ { - m := ms.Get(i) - if err := e.registerAllExtensions(m.Extensions()); err != nil { - return err - } - } - return nil -} - -func (e *extensionRegistry) registerAllExtensions(exts protoreflect.ExtensionDescriptors) error { - for i := 0; i < exts.Len(); i++ { - if err := e.registerExtension(exts.Get(i)); err != nil { - return err - } - } - return nil -} - -// registerExtension adds the given extension to the type registry if an -// extension with that full name does not exist yet. -func (e *extensionRegistry) registerExtension(xd protoreflect.ExtensionDescriptor) error { - if _, err := e.FindExtensionByName(xd.FullName()); err != protoregistry.NotFound { - // Either the extension already exists or there was an error, either way we're done. - return err - } - return e.local.RegisterExtension(dynamicpb.NewExtensionType(xd)) -} diff --git a/vendor/google.golang.org/protobuf/encoding/protojson/decode.go b/vendor/google.golang.org/protobuf/encoding/protojson/decode.go new file mode 100644 index 00000000000..f47902371a6 --- /dev/null +++ b/vendor/google.golang.org/protobuf/encoding/protojson/decode.go @@ -0,0 +1,685 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package protojson + +import ( + "encoding/base64" + "fmt" + "math" + "strconv" + "strings" + + "google.golang.org/protobuf/encoding/protowire" + "google.golang.org/protobuf/internal/encoding/json" + "google.golang.org/protobuf/internal/encoding/messageset" + "google.golang.org/protobuf/internal/errors" + "google.golang.org/protobuf/internal/flags" + "google.golang.org/protobuf/internal/genid" + "google.golang.org/protobuf/internal/pragma" + "google.golang.org/protobuf/internal/set" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protoreflect" + "google.golang.org/protobuf/reflect/protoregistry" +) + +// Unmarshal reads the given []byte into the given [proto.Message]. +// The provided message must be mutable (e.g., a non-nil pointer to a message). +func Unmarshal(b []byte, m proto.Message) error { + return UnmarshalOptions{}.Unmarshal(b, m) +} + +// UnmarshalOptions is a configurable JSON format parser. +type UnmarshalOptions struct { + pragma.NoUnkeyedLiterals + + // If AllowPartial is set, input for messages that will result in missing + // required fields will not return an error. + AllowPartial bool + + // If DiscardUnknown is set, unknown fields and enum name values are ignored. + DiscardUnknown bool + + // Resolver is used for looking up types when unmarshaling + // google.protobuf.Any messages or extension fields. + // If nil, this defaults to using protoregistry.GlobalTypes. + Resolver interface { + protoregistry.MessageTypeResolver + protoregistry.ExtensionTypeResolver + } + + // RecursionLimit limits how deeply messages may be nested. + // If zero, a default limit is applied. + RecursionLimit int +} + +// Unmarshal reads the given []byte and populates the given [proto.Message] +// using options in the UnmarshalOptions object. +// It will clear the message first before setting the fields. +// If it returns an error, the given message may be partially set. +// The provided message must be mutable (e.g., a non-nil pointer to a message). +func (o UnmarshalOptions) Unmarshal(b []byte, m proto.Message) error { + return o.unmarshal(b, m) +} + +// unmarshal is a centralized function that all unmarshal operations go through. +// For profiling purposes, avoid changing the name of this function or +// introducing other code paths for unmarshal that do not go through this. +func (o UnmarshalOptions) unmarshal(b []byte, m proto.Message) error { + proto.Reset(m) + + if o.Resolver == nil { + o.Resolver = protoregistry.GlobalTypes + } + if o.RecursionLimit == 0 { + o.RecursionLimit = protowire.DefaultRecursionLimit + } + + dec := decoder{json.NewDecoder(b), o} + if err := dec.unmarshalMessage(m.ProtoReflect(), false); err != nil { + return err + } + + // Check for EOF. + tok, err := dec.Read() + if err != nil { + return err + } + if tok.Kind() != json.EOF { + return dec.unexpectedTokenError(tok) + } + + if o.AllowPartial { + return nil + } + return proto.CheckInitialized(m) +} + +type decoder struct { + *json.Decoder + opts UnmarshalOptions +} + +// newError returns an error object with position info. +func (d decoder) newError(pos int, f string, x ...interface{}) error { + line, column := d.Position(pos) + head := fmt.Sprintf("(line %d:%d): ", line, column) + return errors.New(head+f, x...) +} + +// unexpectedTokenError returns a syntax error for the given unexpected token. +func (d decoder) unexpectedTokenError(tok json.Token) error { + return d.syntaxError(tok.Pos(), "unexpected token %s", tok.RawString()) +} + +// syntaxError returns a syntax error for given position. +func (d decoder) syntaxError(pos int, f string, x ...interface{}) error { + line, column := d.Position(pos) + head := fmt.Sprintf("syntax error (line %d:%d): ", line, column) + return errors.New(head+f, x...) +} + +// unmarshalMessage unmarshals a message into the given protoreflect.Message. +func (d decoder) unmarshalMessage(m protoreflect.Message, skipTypeURL bool) error { + d.opts.RecursionLimit-- + if d.opts.RecursionLimit < 0 { + return errors.New("exceeded max recursion depth") + } + if unmarshal := wellKnownTypeUnmarshaler(m.Descriptor().FullName()); unmarshal != nil { + return unmarshal(d, m) + } + + tok, err := d.Read() + if err != nil { + return err + } + if tok.Kind() != json.ObjectOpen { + return d.unexpectedTokenError(tok) + } + + messageDesc := m.Descriptor() + if !flags.ProtoLegacy && messageset.IsMessageSet(messageDesc) { + return errors.New("no support for proto1 MessageSets") + } + + var seenNums set.Ints + var seenOneofs set.Ints + fieldDescs := messageDesc.Fields() + for { + // Read field name. + tok, err := d.Read() + if err != nil { + return err + } + switch tok.Kind() { + default: + return d.unexpectedTokenError(tok) + case json.ObjectClose: + return nil + case json.Name: + // Continue below. + } + + name := tok.Name() + // Unmarshaling a non-custom embedded message in Any will contain the + // JSON field "@type" which should be skipped because it is not a field + // of the embedded message, but simply an artifact of the Any format. + if skipTypeURL && name == "@type" { + d.Read() + continue + } + + // Get the FieldDescriptor. + var fd protoreflect.FieldDescriptor + if strings.HasPrefix(name, "[") && strings.HasSuffix(name, "]") { + // Only extension names are in [name] format. + extName := protoreflect.FullName(name[1 : len(name)-1]) + extType, err := d.opts.Resolver.FindExtensionByName(extName) + if err != nil && err != protoregistry.NotFound { + return d.newError(tok.Pos(), "unable to resolve %s: %v", tok.RawString(), err) + } + if extType != nil { + fd = extType.TypeDescriptor() + if !messageDesc.ExtensionRanges().Has(fd.Number()) || fd.ContainingMessage().FullName() != messageDesc.FullName() { + return d.newError(tok.Pos(), "message %v cannot be extended by %v", messageDesc.FullName(), fd.FullName()) + } + } + } else { + // The name can either be the JSON name or the proto field name. + fd = fieldDescs.ByJSONName(name) + if fd == nil { + fd = fieldDescs.ByTextName(name) + } + } + if flags.ProtoLegacy { + if fd != nil && fd.IsWeak() && fd.Message().IsPlaceholder() { + fd = nil // reset since the weak reference is not linked in + } + } + + if fd == nil { + // Field is unknown. + if d.opts.DiscardUnknown { + if err := d.skipJSONValue(); err != nil { + return err + } + continue + } + return d.newError(tok.Pos(), "unknown field %v", tok.RawString()) + } + + // Do not allow duplicate fields. + num := uint64(fd.Number()) + if seenNums.Has(num) { + return d.newError(tok.Pos(), "duplicate field %v", tok.RawString()) + } + seenNums.Set(num) + + // No need to set values for JSON null unless the field type is + // google.protobuf.Value or google.protobuf.NullValue. + if tok, _ := d.Peek(); tok.Kind() == json.Null && !isKnownValue(fd) && !isNullValue(fd) { + d.Read() + continue + } + + switch { + case fd.IsList(): + list := m.Mutable(fd).List() + if err := d.unmarshalList(list, fd); err != nil { + return err + } + case fd.IsMap(): + mmap := m.Mutable(fd).Map() + if err := d.unmarshalMap(mmap, fd); err != nil { + return err + } + default: + // If field is a oneof, check if it has already been set. + if od := fd.ContainingOneof(); od != nil { + idx := uint64(od.Index()) + if seenOneofs.Has(idx) { + return d.newError(tok.Pos(), "error parsing %s, oneof %v is already set", tok.RawString(), od.FullName()) + } + seenOneofs.Set(idx) + } + + // Required or optional fields. + if err := d.unmarshalSingular(m, fd); err != nil { + return err + } + } + } +} + +func isKnownValue(fd protoreflect.FieldDescriptor) bool { + md := fd.Message() + return md != nil && md.FullName() == genid.Value_message_fullname +} + +func isNullValue(fd protoreflect.FieldDescriptor) bool { + ed := fd.Enum() + return ed != nil && ed.FullName() == genid.NullValue_enum_fullname +} + +// unmarshalSingular unmarshals to the non-repeated field specified +// by the given FieldDescriptor. +func (d decoder) unmarshalSingular(m protoreflect.Message, fd protoreflect.FieldDescriptor) error { + var val protoreflect.Value + var err error + switch fd.Kind() { + case protoreflect.MessageKind, protoreflect.GroupKind: + val = m.NewField(fd) + err = d.unmarshalMessage(val.Message(), false) + default: + val, err = d.unmarshalScalar(fd) + } + + if err != nil { + return err + } + if val.IsValid() { + m.Set(fd, val) + } + return nil +} + +// unmarshalScalar unmarshals to a scalar/enum protoreflect.Value specified by +// the given FieldDescriptor. +func (d decoder) unmarshalScalar(fd protoreflect.FieldDescriptor) (protoreflect.Value, error) { + const b32 int = 32 + const b64 int = 64 + + tok, err := d.Read() + if err != nil { + return protoreflect.Value{}, err + } + + kind := fd.Kind() + switch kind { + case protoreflect.BoolKind: + if tok.Kind() == json.Bool { + return protoreflect.ValueOfBool(tok.Bool()), nil + } + + case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind: + if v, ok := unmarshalInt(tok, b32); ok { + return v, nil + } + + case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: + if v, ok := unmarshalInt(tok, b64); ok { + return v, nil + } + + case protoreflect.Uint32Kind, protoreflect.Fixed32Kind: + if v, ok := unmarshalUint(tok, b32); ok { + return v, nil + } + + case protoreflect.Uint64Kind, protoreflect.Fixed64Kind: + if v, ok := unmarshalUint(tok, b64); ok { + return v, nil + } + + case protoreflect.FloatKind: + if v, ok := unmarshalFloat(tok, b32); ok { + return v, nil + } + + case protoreflect.DoubleKind: + if v, ok := unmarshalFloat(tok, b64); ok { + return v, nil + } + + case protoreflect.StringKind: + if tok.Kind() == json.String { + return protoreflect.ValueOfString(tok.ParsedString()), nil + } + + case protoreflect.BytesKind: + if v, ok := unmarshalBytes(tok); ok { + return v, nil + } + + case protoreflect.EnumKind: + if v, ok := unmarshalEnum(tok, fd, d.opts.DiscardUnknown); ok { + return v, nil + } + + default: + panic(fmt.Sprintf("unmarshalScalar: invalid scalar kind %v", kind)) + } + + return protoreflect.Value{}, d.newError(tok.Pos(), "invalid value for %v type: %v", kind, tok.RawString()) +} + +func unmarshalInt(tok json.Token, bitSize int) (protoreflect.Value, bool) { + switch tok.Kind() { + case json.Number: + return getInt(tok, bitSize) + + case json.String: + // Decode number from string. + s := strings.TrimSpace(tok.ParsedString()) + if len(s) != len(tok.ParsedString()) { + return protoreflect.Value{}, false + } + dec := json.NewDecoder([]byte(s)) + tok, err := dec.Read() + if err != nil { + return protoreflect.Value{}, false + } + return getInt(tok, bitSize) + } + return protoreflect.Value{}, false +} + +func getInt(tok json.Token, bitSize int) (protoreflect.Value, bool) { + n, ok := tok.Int(bitSize) + if !ok { + return protoreflect.Value{}, false + } + if bitSize == 32 { + return protoreflect.ValueOfInt32(int32(n)), true + } + return protoreflect.ValueOfInt64(n), true +} + +func unmarshalUint(tok json.Token, bitSize int) (protoreflect.Value, bool) { + switch tok.Kind() { + case json.Number: + return getUint(tok, bitSize) + + case json.String: + // Decode number from string. + s := strings.TrimSpace(tok.ParsedString()) + if len(s) != len(tok.ParsedString()) { + return protoreflect.Value{}, false + } + dec := json.NewDecoder([]byte(s)) + tok, err := dec.Read() + if err != nil { + return protoreflect.Value{}, false + } + return getUint(tok, bitSize) + } + return protoreflect.Value{}, false +} + +func getUint(tok json.Token, bitSize int) (protoreflect.Value, bool) { + n, ok := tok.Uint(bitSize) + if !ok { + return protoreflect.Value{}, false + } + if bitSize == 32 { + return protoreflect.ValueOfUint32(uint32(n)), true + } + return protoreflect.ValueOfUint64(n), true +} + +func unmarshalFloat(tok json.Token, bitSize int) (protoreflect.Value, bool) { + switch tok.Kind() { + case json.Number: + return getFloat(tok, bitSize) + + case json.String: + s := tok.ParsedString() + switch s { + case "NaN": + if bitSize == 32 { + return protoreflect.ValueOfFloat32(float32(math.NaN())), true + } + return protoreflect.ValueOfFloat64(math.NaN()), true + case "Infinity": + if bitSize == 32 { + return protoreflect.ValueOfFloat32(float32(math.Inf(+1))), true + } + return protoreflect.ValueOfFloat64(math.Inf(+1)), true + case "-Infinity": + if bitSize == 32 { + return protoreflect.ValueOfFloat32(float32(math.Inf(-1))), true + } + return protoreflect.ValueOfFloat64(math.Inf(-1)), true + } + + // Decode number from string. + if len(s) != len(strings.TrimSpace(s)) { + return protoreflect.Value{}, false + } + dec := json.NewDecoder([]byte(s)) + tok, err := dec.Read() + if err != nil { + return protoreflect.Value{}, false + } + return getFloat(tok, bitSize) + } + return protoreflect.Value{}, false +} + +func getFloat(tok json.Token, bitSize int) (protoreflect.Value, bool) { + n, ok := tok.Float(bitSize) + if !ok { + return protoreflect.Value{}, false + } + if bitSize == 32 { + return protoreflect.ValueOfFloat32(float32(n)), true + } + return protoreflect.ValueOfFloat64(n), true +} + +func unmarshalBytes(tok json.Token) (protoreflect.Value, bool) { + if tok.Kind() != json.String { + return protoreflect.Value{}, false + } + + s := tok.ParsedString() + enc := base64.StdEncoding + if strings.ContainsAny(s, "-_") { + enc = base64.URLEncoding + } + if len(s)%4 != 0 { + enc = enc.WithPadding(base64.NoPadding) + } + b, err := enc.DecodeString(s) + if err != nil { + return protoreflect.Value{}, false + } + return protoreflect.ValueOfBytes(b), true +} + +func unmarshalEnum(tok json.Token, fd protoreflect.FieldDescriptor, discardUnknown bool) (protoreflect.Value, bool) { + switch tok.Kind() { + case json.String: + // Lookup EnumNumber based on name. + s := tok.ParsedString() + if enumVal := fd.Enum().Values().ByName(protoreflect.Name(s)); enumVal != nil { + return protoreflect.ValueOfEnum(enumVal.Number()), true + } + if discardUnknown { + return protoreflect.Value{}, true + } + + case json.Number: + if n, ok := tok.Int(32); ok { + return protoreflect.ValueOfEnum(protoreflect.EnumNumber(n)), true + } + + case json.Null: + // This is only valid for google.protobuf.NullValue. + if isNullValue(fd) { + return protoreflect.ValueOfEnum(0), true + } + } + + return protoreflect.Value{}, false +} + +func (d decoder) unmarshalList(list protoreflect.List, fd protoreflect.FieldDescriptor) error { + tok, err := d.Read() + if err != nil { + return err + } + if tok.Kind() != json.ArrayOpen { + return d.unexpectedTokenError(tok) + } + + switch fd.Kind() { + case protoreflect.MessageKind, protoreflect.GroupKind: + for { + tok, err := d.Peek() + if err != nil { + return err + } + + if tok.Kind() == json.ArrayClose { + d.Read() + return nil + } + + val := list.NewElement() + if err := d.unmarshalMessage(val.Message(), false); err != nil { + return err + } + list.Append(val) + } + default: + for { + tok, err := d.Peek() + if err != nil { + return err + } + + if tok.Kind() == json.ArrayClose { + d.Read() + return nil + } + + val, err := d.unmarshalScalar(fd) + if err != nil { + return err + } + if val.IsValid() { + list.Append(val) + } + } + } + + return nil +} + +func (d decoder) unmarshalMap(mmap protoreflect.Map, fd protoreflect.FieldDescriptor) error { + tok, err := d.Read() + if err != nil { + return err + } + if tok.Kind() != json.ObjectOpen { + return d.unexpectedTokenError(tok) + } + + // Determine ahead whether map entry is a scalar type or a message type in + // order to call the appropriate unmarshalMapValue func inside the for loop + // below. + var unmarshalMapValue func() (protoreflect.Value, error) + switch fd.MapValue().Kind() { + case protoreflect.MessageKind, protoreflect.GroupKind: + unmarshalMapValue = func() (protoreflect.Value, error) { + val := mmap.NewValue() + if err := d.unmarshalMessage(val.Message(), false); err != nil { + return protoreflect.Value{}, err + } + return val, nil + } + default: + unmarshalMapValue = func() (protoreflect.Value, error) { + return d.unmarshalScalar(fd.MapValue()) + } + } + +Loop: + for { + // Read field name. + tok, err := d.Read() + if err != nil { + return err + } + switch tok.Kind() { + default: + return d.unexpectedTokenError(tok) + case json.ObjectClose: + break Loop + case json.Name: + // Continue. + } + + // Unmarshal field name. + pkey, err := d.unmarshalMapKey(tok, fd.MapKey()) + if err != nil { + return err + } + + // Check for duplicate field name. + if mmap.Has(pkey) { + return d.newError(tok.Pos(), "duplicate map key %v", tok.RawString()) + } + + // Read and unmarshal field value. + pval, err := unmarshalMapValue() + if err != nil { + return err + } + if pval.IsValid() { + mmap.Set(pkey, pval) + } + } + + return nil +} + +// unmarshalMapKey converts given token of Name kind into a protoreflect.MapKey. +// A map key type is any integral or string type. +func (d decoder) unmarshalMapKey(tok json.Token, fd protoreflect.FieldDescriptor) (protoreflect.MapKey, error) { + const b32 = 32 + const b64 = 64 + const base10 = 10 + + name := tok.Name() + kind := fd.Kind() + switch kind { + case protoreflect.StringKind: + return protoreflect.ValueOfString(name).MapKey(), nil + + case protoreflect.BoolKind: + switch name { + case "true": + return protoreflect.ValueOfBool(true).MapKey(), nil + case "false": + return protoreflect.ValueOfBool(false).MapKey(), nil + } + + case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind: + if n, err := strconv.ParseInt(name, base10, b32); err == nil { + return protoreflect.ValueOfInt32(int32(n)).MapKey(), nil + } + + case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: + if n, err := strconv.ParseInt(name, base10, b64); err == nil { + return protoreflect.ValueOfInt64(int64(n)).MapKey(), nil + } + + case protoreflect.Uint32Kind, protoreflect.Fixed32Kind: + if n, err := strconv.ParseUint(name, base10, b32); err == nil { + return protoreflect.ValueOfUint32(uint32(n)).MapKey(), nil + } + + case protoreflect.Uint64Kind, protoreflect.Fixed64Kind: + if n, err := strconv.ParseUint(name, base10, b64); err == nil { + return protoreflect.ValueOfUint64(uint64(n)).MapKey(), nil + } + + default: + panic(fmt.Sprintf("invalid kind for map key: %v", kind)) + } + + return protoreflect.MapKey{}, d.newError(tok.Pos(), "invalid value for %v key: %s", kind, tok.RawString()) +} diff --git a/vendor/google.golang.org/protobuf/encoding/protojson/doc.go b/vendor/google.golang.org/protobuf/encoding/protojson/doc.go new file mode 100644 index 00000000000..ae71007c18b --- /dev/null +++ b/vendor/google.golang.org/protobuf/encoding/protojson/doc.go @@ -0,0 +1,11 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package protojson marshals and unmarshals protocol buffer messages as JSON +// format. It follows the guide at +// https://protobuf.dev/programming-guides/proto3#json. +// +// This package produces a different output than the standard [encoding/json] +// package, which does not operate correctly on protocol buffer messages. +package protojson diff --git a/vendor/google.golang.org/protobuf/encoding/protojson/encode.go b/vendor/google.golang.org/protobuf/encoding/protojson/encode.go new file mode 100644 index 00000000000..3f75098b6fb --- /dev/null +++ b/vendor/google.golang.org/protobuf/encoding/protojson/encode.go @@ -0,0 +1,378 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package protojson + +import ( + "encoding/base64" + "fmt" + + "google.golang.org/protobuf/internal/encoding/json" + "google.golang.org/protobuf/internal/encoding/messageset" + "google.golang.org/protobuf/internal/errors" + "google.golang.org/protobuf/internal/filedesc" + "google.golang.org/protobuf/internal/flags" + "google.golang.org/protobuf/internal/genid" + "google.golang.org/protobuf/internal/order" + "google.golang.org/protobuf/internal/pragma" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protoreflect" + "google.golang.org/protobuf/reflect/protoregistry" +) + +const defaultIndent = " " + +// Format formats the message as a multiline string. +// This function is only intended for human consumption and ignores errors. +// Do not depend on the output being stable. It may change over time across +// different versions of the program. +func Format(m proto.Message) string { + return MarshalOptions{Multiline: true}.Format(m) +} + +// Marshal writes the given [proto.Message] in JSON format using default options. +// Do not depend on the output being stable. It may change over time across +// different versions of the program. +func Marshal(m proto.Message) ([]byte, error) { + return MarshalOptions{}.Marshal(m) +} + +// MarshalOptions is a configurable JSON format marshaler. +type MarshalOptions struct { + pragma.NoUnkeyedLiterals + + // Multiline specifies whether the marshaler should format the output in + // indented-form with every textual element on a new line. + // If Indent is an empty string, then an arbitrary indent is chosen. + Multiline bool + + // Indent specifies the set of indentation characters to use in a multiline + // formatted output such that every entry is preceded by Indent and + // terminated by a newline. If non-empty, then Multiline is treated as true. + // Indent can only be composed of space or tab characters. + Indent string + + // AllowPartial allows messages that have missing required fields to marshal + // without returning an error. If AllowPartial is false (the default), + // Marshal will return error if there are any missing required fields. + AllowPartial bool + + // UseProtoNames uses proto field name instead of lowerCamelCase name in JSON + // field names. + UseProtoNames bool + + // UseEnumNumbers emits enum values as numbers. + UseEnumNumbers bool + + // EmitUnpopulated specifies whether to emit unpopulated fields. It does not + // emit unpopulated oneof fields or unpopulated extension fields. + // The JSON value emitted for unpopulated fields are as follows: + // ╔═══════╤════════════════════════════╗ + // ║ JSON │ Protobuf field ║ + // ╠═══════╪════════════════════════════╣ + // ║ false │ proto3 boolean fields ║ + // ║ 0 │ proto3 numeric fields ║ + // ║ "" │ proto3 string/bytes fields ║ + // ║ null │ proto2 scalar fields ║ + // ║ null │ message fields ║ + // ║ [] │ list fields ║ + // ║ {} │ map fields ║ + // ╚═══════╧════════════════════════════╝ + EmitUnpopulated bool + + // EmitDefaultValues specifies whether to emit default-valued primitive fields, + // empty lists, and empty maps. The fields affected are as follows: + // ╔═══════╤════════════════════════════════════════╗ + // ║ JSON │ Protobuf field ║ + // ╠═══════╪════════════════════════════════════════╣ + // ║ false │ non-optional scalar boolean fields ║ + // ║ 0 │ non-optional scalar numeric fields ║ + // ║ "" │ non-optional scalar string/byte fields ║ + // ║ [] │ empty repeated fields ║ + // ║ {} │ empty map fields ║ + // ╚═══════╧════════════════════════════════════════╝ + // + // Behaves similarly to EmitUnpopulated, but does not emit "null"-value fields, + // i.e. presence-sensing fields that are omitted will remain omitted to preserve + // presence-sensing. + // EmitUnpopulated takes precedence over EmitDefaultValues since the former generates + // a strict superset of the latter. + EmitDefaultValues bool + + // Resolver is used for looking up types when expanding google.protobuf.Any + // messages. If nil, this defaults to using protoregistry.GlobalTypes. + Resolver interface { + protoregistry.ExtensionTypeResolver + protoregistry.MessageTypeResolver + } +} + +// Format formats the message as a string. +// This method is only intended for human consumption and ignores errors. +// Do not depend on the output being stable. It may change over time across +// different versions of the program. +func (o MarshalOptions) Format(m proto.Message) string { + if m == nil || !m.ProtoReflect().IsValid() { + return "" // invalid syntax, but okay since this is for debugging + } + o.AllowPartial = true + b, _ := o.Marshal(m) + return string(b) +} + +// Marshal marshals the given [proto.Message] in the JSON format using options in +// MarshalOptions. Do not depend on the output being stable. It may change over +// time across different versions of the program. +func (o MarshalOptions) Marshal(m proto.Message) ([]byte, error) { + return o.marshal(nil, m) +} + +// MarshalAppend appends the JSON format encoding of m to b, +// returning the result. +func (o MarshalOptions) MarshalAppend(b []byte, m proto.Message) ([]byte, error) { + return o.marshal(b, m) +} + +// marshal is a centralized function that all marshal operations go through. +// For profiling purposes, avoid changing the name of this function or +// introducing other code paths for marshal that do not go through this. +func (o MarshalOptions) marshal(b []byte, m proto.Message) ([]byte, error) { + if o.Multiline && o.Indent == "" { + o.Indent = defaultIndent + } + if o.Resolver == nil { + o.Resolver = protoregistry.GlobalTypes + } + + internalEnc, err := json.NewEncoder(b, o.Indent) + if err != nil { + return nil, err + } + + // Treat nil message interface as an empty message, + // in which case the output in an empty JSON object. + if m == nil { + return append(b, '{', '}'), nil + } + + enc := encoder{internalEnc, o} + if err := enc.marshalMessage(m.ProtoReflect(), ""); err != nil { + return nil, err + } + if o.AllowPartial { + return enc.Bytes(), nil + } + return enc.Bytes(), proto.CheckInitialized(m) +} + +type encoder struct { + *json.Encoder + opts MarshalOptions +} + +// typeFieldDesc is a synthetic field descriptor used for the "@type" field. +var typeFieldDesc = func() protoreflect.FieldDescriptor { + var fd filedesc.Field + fd.L0.FullName = "@type" + fd.L0.Index = -1 + fd.L1.Cardinality = protoreflect.Optional + fd.L1.Kind = protoreflect.StringKind + return &fd +}() + +// typeURLFieldRanger wraps a protoreflect.Message and modifies its Range method +// to additionally iterate over a synthetic field for the type URL. +type typeURLFieldRanger struct { + order.FieldRanger + typeURL string +} + +func (m typeURLFieldRanger) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if !f(typeFieldDesc, protoreflect.ValueOfString(m.typeURL)) { + return + } + m.FieldRanger.Range(f) +} + +// unpopulatedFieldRanger wraps a protoreflect.Message and modifies its Range +// method to additionally iterate over unpopulated fields. +type unpopulatedFieldRanger struct { + protoreflect.Message + + skipNull bool +} + +func (m unpopulatedFieldRanger) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + fds := m.Descriptor().Fields() + for i := 0; i < fds.Len(); i++ { + fd := fds.Get(i) + if m.Has(fd) || fd.ContainingOneof() != nil { + continue // ignore populated fields and fields within a oneofs + } + + v := m.Get(fd) + isProto2Scalar := fd.Syntax() == protoreflect.Proto2 && fd.Default().IsValid() + isSingularMessage := fd.Cardinality() != protoreflect.Repeated && fd.Message() != nil + if isProto2Scalar || isSingularMessage { + if m.skipNull { + continue + } + v = protoreflect.Value{} // use invalid value to emit null + } + if !f(fd, v) { + return + } + } + m.Message.Range(f) +} + +// marshalMessage marshals the fields in the given protoreflect.Message. +// If the typeURL is non-empty, then a synthetic "@type" field is injected +// containing the URL as the value. +func (e encoder) marshalMessage(m protoreflect.Message, typeURL string) error { + if !flags.ProtoLegacy && messageset.IsMessageSet(m.Descriptor()) { + return errors.New("no support for proto1 MessageSets") + } + + if marshal := wellKnownTypeMarshaler(m.Descriptor().FullName()); marshal != nil { + return marshal(e, m) + } + + e.StartObject() + defer e.EndObject() + + var fields order.FieldRanger = m + switch { + case e.opts.EmitUnpopulated: + fields = unpopulatedFieldRanger{Message: m, skipNull: false} + case e.opts.EmitDefaultValues: + fields = unpopulatedFieldRanger{Message: m, skipNull: true} + } + if typeURL != "" { + fields = typeURLFieldRanger{fields, typeURL} + } + + var err error + order.RangeFields(fields, order.IndexNameFieldOrder, func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool { + name := fd.JSONName() + if e.opts.UseProtoNames { + name = fd.TextName() + } + + if err = e.WriteName(name); err != nil { + return false + } + if err = e.marshalValue(v, fd); err != nil { + return false + } + return true + }) + return err +} + +// marshalValue marshals the given protoreflect.Value. +func (e encoder) marshalValue(val protoreflect.Value, fd protoreflect.FieldDescriptor) error { + switch { + case fd.IsList(): + return e.marshalList(val.List(), fd) + case fd.IsMap(): + return e.marshalMap(val.Map(), fd) + default: + return e.marshalSingular(val, fd) + } +} + +// marshalSingular marshals the given non-repeated field value. This includes +// all scalar types, enums, messages, and groups. +func (e encoder) marshalSingular(val protoreflect.Value, fd protoreflect.FieldDescriptor) error { + if !val.IsValid() { + e.WriteNull() + return nil + } + + switch kind := fd.Kind(); kind { + case protoreflect.BoolKind: + e.WriteBool(val.Bool()) + + case protoreflect.StringKind: + if e.WriteString(val.String()) != nil { + return errors.InvalidUTF8(string(fd.FullName())) + } + + case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind: + e.WriteInt(val.Int()) + + case protoreflect.Uint32Kind, protoreflect.Fixed32Kind: + e.WriteUint(val.Uint()) + + case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Uint64Kind, + protoreflect.Sfixed64Kind, protoreflect.Fixed64Kind: + // 64-bit integers are written out as JSON string. + e.WriteString(val.String()) + + case protoreflect.FloatKind: + // Encoder.WriteFloat handles the special numbers NaN and infinites. + e.WriteFloat(val.Float(), 32) + + case protoreflect.DoubleKind: + // Encoder.WriteFloat handles the special numbers NaN and infinites. + e.WriteFloat(val.Float(), 64) + + case protoreflect.BytesKind: + e.WriteString(base64.StdEncoding.EncodeToString(val.Bytes())) + + case protoreflect.EnumKind: + if fd.Enum().FullName() == genid.NullValue_enum_fullname { + e.WriteNull() + } else { + desc := fd.Enum().Values().ByNumber(val.Enum()) + if e.opts.UseEnumNumbers || desc == nil { + e.WriteInt(int64(val.Enum())) + } else { + e.WriteString(string(desc.Name())) + } + } + + case protoreflect.MessageKind, protoreflect.GroupKind: + if err := e.marshalMessage(val.Message(), ""); err != nil { + return err + } + + default: + panic(fmt.Sprintf("%v has unknown kind: %v", fd.FullName(), kind)) + } + return nil +} + +// marshalList marshals the given protoreflect.List. +func (e encoder) marshalList(list protoreflect.List, fd protoreflect.FieldDescriptor) error { + e.StartArray() + defer e.EndArray() + + for i := 0; i < list.Len(); i++ { + item := list.Get(i) + if err := e.marshalSingular(item, fd); err != nil { + return err + } + } + return nil +} + +// marshalMap marshals given protoreflect.Map. +func (e encoder) marshalMap(mmap protoreflect.Map, fd protoreflect.FieldDescriptor) error { + e.StartObject() + defer e.EndObject() + + var err error + order.RangeEntries(mmap, order.GenericKeyOrder, func(k protoreflect.MapKey, v protoreflect.Value) bool { + if err = e.WriteName(k.String()); err != nil { + return false + } + if err = e.marshalSingular(v, fd.MapValue()); err != nil { + return false + } + return true + }) + return err +} diff --git a/vendor/google.golang.org/protobuf/encoding/protojson/well_known_types.go b/vendor/google.golang.org/protobuf/encoding/protojson/well_known_types.go new file mode 100644 index 00000000000..4b177c8206f --- /dev/null +++ b/vendor/google.golang.org/protobuf/encoding/protojson/well_known_types.go @@ -0,0 +1,876 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package protojson + +import ( + "bytes" + "fmt" + "math" + "strconv" + "strings" + "time" + + "google.golang.org/protobuf/internal/encoding/json" + "google.golang.org/protobuf/internal/errors" + "google.golang.org/protobuf/internal/genid" + "google.golang.org/protobuf/internal/strs" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protoreflect" +) + +type marshalFunc func(encoder, protoreflect.Message) error + +// wellKnownTypeMarshaler returns a marshal function if the message type +// has specialized serialization behavior. It returns nil otherwise. +func wellKnownTypeMarshaler(name protoreflect.FullName) marshalFunc { + if name.Parent() == genid.GoogleProtobuf_package { + switch name.Name() { + case genid.Any_message_name: + return encoder.marshalAny + case genid.Timestamp_message_name: + return encoder.marshalTimestamp + case genid.Duration_message_name: + return encoder.marshalDuration + case genid.BoolValue_message_name, + genid.Int32Value_message_name, + genid.Int64Value_message_name, + genid.UInt32Value_message_name, + genid.UInt64Value_message_name, + genid.FloatValue_message_name, + genid.DoubleValue_message_name, + genid.StringValue_message_name, + genid.BytesValue_message_name: + return encoder.marshalWrapperType + case genid.Struct_message_name: + return encoder.marshalStruct + case genid.ListValue_message_name: + return encoder.marshalListValue + case genid.Value_message_name: + return encoder.marshalKnownValue + case genid.FieldMask_message_name: + return encoder.marshalFieldMask + case genid.Empty_message_name: + return encoder.marshalEmpty + } + } + return nil +} + +type unmarshalFunc func(decoder, protoreflect.Message) error + +// wellKnownTypeUnmarshaler returns a unmarshal function if the message type +// has specialized serialization behavior. It returns nil otherwise. +func wellKnownTypeUnmarshaler(name protoreflect.FullName) unmarshalFunc { + if name.Parent() == genid.GoogleProtobuf_package { + switch name.Name() { + case genid.Any_message_name: + return decoder.unmarshalAny + case genid.Timestamp_message_name: + return decoder.unmarshalTimestamp + case genid.Duration_message_name: + return decoder.unmarshalDuration + case genid.BoolValue_message_name, + genid.Int32Value_message_name, + genid.Int64Value_message_name, + genid.UInt32Value_message_name, + genid.UInt64Value_message_name, + genid.FloatValue_message_name, + genid.DoubleValue_message_name, + genid.StringValue_message_name, + genid.BytesValue_message_name: + return decoder.unmarshalWrapperType + case genid.Struct_message_name: + return decoder.unmarshalStruct + case genid.ListValue_message_name: + return decoder.unmarshalListValue + case genid.Value_message_name: + return decoder.unmarshalKnownValue + case genid.FieldMask_message_name: + return decoder.unmarshalFieldMask + case genid.Empty_message_name: + return decoder.unmarshalEmpty + } + } + return nil +} + +// The JSON representation of an Any message uses the regular representation of +// the deserialized, embedded message, with an additional field `@type` which +// contains the type URL. If the embedded message type is well-known and has a +// custom JSON representation, that representation will be embedded adding a +// field `value` which holds the custom JSON in addition to the `@type` field. + +func (e encoder) marshalAny(m protoreflect.Message) error { + fds := m.Descriptor().Fields() + fdType := fds.ByNumber(genid.Any_TypeUrl_field_number) + fdValue := fds.ByNumber(genid.Any_Value_field_number) + + if !m.Has(fdType) { + if !m.Has(fdValue) { + // If message is empty, marshal out empty JSON object. + e.StartObject() + e.EndObject() + return nil + } else { + // Return error if type_url field is not set, but value is set. + return errors.New("%s: %v is not set", genid.Any_message_fullname, genid.Any_TypeUrl_field_name) + } + } + + typeVal := m.Get(fdType) + valueVal := m.Get(fdValue) + + // Resolve the type in order to unmarshal value field. + typeURL := typeVal.String() + emt, err := e.opts.Resolver.FindMessageByURL(typeURL) + if err != nil { + return errors.New("%s: unable to resolve %q: %v", genid.Any_message_fullname, typeURL, err) + } + + em := emt.New() + err = proto.UnmarshalOptions{ + AllowPartial: true, // never check required fields inside an Any + Resolver: e.opts.Resolver, + }.Unmarshal(valueVal.Bytes(), em.Interface()) + if err != nil { + return errors.New("%s: unable to unmarshal %q: %v", genid.Any_message_fullname, typeURL, err) + } + + // If type of value has custom JSON encoding, marshal out a field "value" + // with corresponding custom JSON encoding of the embedded message as a + // field. + if marshal := wellKnownTypeMarshaler(emt.Descriptor().FullName()); marshal != nil { + e.StartObject() + defer e.EndObject() + + // Marshal out @type field. + e.WriteName("@type") + if err := e.WriteString(typeURL); err != nil { + return err + } + + e.WriteName("value") + return marshal(e, em) + } + + // Else, marshal out the embedded message's fields in this Any object. + if err := e.marshalMessage(em, typeURL); err != nil { + return err + } + + return nil +} + +func (d decoder) unmarshalAny(m protoreflect.Message) error { + // Peek to check for json.ObjectOpen to avoid advancing a read. + start, err := d.Peek() + if err != nil { + return err + } + if start.Kind() != json.ObjectOpen { + return d.unexpectedTokenError(start) + } + + // Use another decoder to parse the unread bytes for @type field. This + // avoids advancing a read from current decoder because the current JSON + // object may contain the fields of the embedded type. + dec := decoder{d.Clone(), UnmarshalOptions{RecursionLimit: d.opts.RecursionLimit}} + tok, err := findTypeURL(dec) + switch err { + case errEmptyObject: + // An empty JSON object translates to an empty Any message. + d.Read() // Read json.ObjectOpen. + d.Read() // Read json.ObjectClose. + return nil + + case errMissingType: + if d.opts.DiscardUnknown { + // Treat all fields as unknowns, similar to an empty object. + return d.skipJSONValue() + } + // Use start.Pos() for line position. + return d.newError(start.Pos(), err.Error()) + + default: + if err != nil { + return err + } + } + + typeURL := tok.ParsedString() + emt, err := d.opts.Resolver.FindMessageByURL(typeURL) + if err != nil { + return d.newError(tok.Pos(), "unable to resolve %v: %q", tok.RawString(), err) + } + + // Create new message for the embedded message type and unmarshal into it. + em := emt.New() + if unmarshal := wellKnownTypeUnmarshaler(emt.Descriptor().FullName()); unmarshal != nil { + // If embedded message is a custom type, + // unmarshal the JSON "value" field into it. + if err := d.unmarshalAnyValue(unmarshal, em); err != nil { + return err + } + } else { + // Else unmarshal the current JSON object into it. + if err := d.unmarshalMessage(em, true); err != nil { + return err + } + } + // Serialize the embedded message and assign the resulting bytes to the + // proto value field. + b, err := proto.MarshalOptions{ + AllowPartial: true, // No need to check required fields inside an Any. + Deterministic: true, + }.Marshal(em.Interface()) + if err != nil { + return d.newError(start.Pos(), "error in marshaling Any.value field: %v", err) + } + + fds := m.Descriptor().Fields() + fdType := fds.ByNumber(genid.Any_TypeUrl_field_number) + fdValue := fds.ByNumber(genid.Any_Value_field_number) + + m.Set(fdType, protoreflect.ValueOfString(typeURL)) + m.Set(fdValue, protoreflect.ValueOfBytes(b)) + return nil +} + +var errEmptyObject = fmt.Errorf(`empty object`) +var errMissingType = fmt.Errorf(`missing "@type" field`) + +// findTypeURL returns the token for the "@type" field value from the given +// JSON bytes. It is expected that the given bytes start with json.ObjectOpen. +// It returns errEmptyObject if the JSON object is empty or errMissingType if +// @type field does not exist. It returns other error if the @type field is not +// valid or other decoding issues. +func findTypeURL(d decoder) (json.Token, error) { + var typeURL string + var typeTok json.Token + numFields := 0 + // Skip start object. + d.Read() + +Loop: + for { + tok, err := d.Read() + if err != nil { + return json.Token{}, err + } + + switch tok.Kind() { + case json.ObjectClose: + if typeURL == "" { + // Did not find @type field. + if numFields > 0 { + return json.Token{}, errMissingType + } + return json.Token{}, errEmptyObject + } + break Loop + + case json.Name: + numFields++ + if tok.Name() != "@type" { + // Skip value. + if err := d.skipJSONValue(); err != nil { + return json.Token{}, err + } + continue + } + + // Return error if this was previously set already. + if typeURL != "" { + return json.Token{}, d.newError(tok.Pos(), `duplicate "@type" field`) + } + // Read field value. + tok, err := d.Read() + if err != nil { + return json.Token{}, err + } + if tok.Kind() != json.String { + return json.Token{}, d.newError(tok.Pos(), `@type field value is not a string: %v`, tok.RawString()) + } + typeURL = tok.ParsedString() + if typeURL == "" { + return json.Token{}, d.newError(tok.Pos(), `@type field contains empty value`) + } + typeTok = tok + } + } + + return typeTok, nil +} + +// skipJSONValue parses a JSON value (null, boolean, string, number, object and +// array) in order to advance the read to the next JSON value. It relies on +// the decoder returning an error if the types are not in valid sequence. +func (d decoder) skipJSONValue() error { + var open int + for { + tok, err := d.Read() + if err != nil { + return err + } + switch tok.Kind() { + case json.ObjectClose, json.ArrayClose: + open-- + case json.ObjectOpen, json.ArrayOpen: + open++ + if open > d.opts.RecursionLimit { + return errors.New("exceeded max recursion depth") + } + case json.EOF: + // This can only happen if there's a bug in Decoder.Read. + // Avoid an infinite loop if this does happen. + return errors.New("unexpected EOF") + } + if open == 0 { + return nil + } + } +} + +// unmarshalAnyValue unmarshals the given custom-type message from the JSON +// object's "value" field. +func (d decoder) unmarshalAnyValue(unmarshal unmarshalFunc, m protoreflect.Message) error { + // Skip ObjectOpen, and start reading the fields. + d.Read() + + var found bool // Used for detecting duplicate "value". + for { + tok, err := d.Read() + if err != nil { + return err + } + switch tok.Kind() { + case json.ObjectClose: + if !found { + return d.newError(tok.Pos(), `missing "value" field`) + } + return nil + + case json.Name: + switch tok.Name() { + case "@type": + // Skip the value as this was previously parsed already. + d.Read() + + case "value": + if found { + return d.newError(tok.Pos(), `duplicate "value" field`) + } + // Unmarshal the field value into the given message. + if err := unmarshal(d, m); err != nil { + return err + } + found = true + + default: + if d.opts.DiscardUnknown { + if err := d.skipJSONValue(); err != nil { + return err + } + continue + } + return d.newError(tok.Pos(), "unknown field %v", tok.RawString()) + } + } + } +} + +// Wrapper types are encoded as JSON primitives like string, number or boolean. + +func (e encoder) marshalWrapperType(m protoreflect.Message) error { + fd := m.Descriptor().Fields().ByNumber(genid.WrapperValue_Value_field_number) + val := m.Get(fd) + return e.marshalSingular(val, fd) +} + +func (d decoder) unmarshalWrapperType(m protoreflect.Message) error { + fd := m.Descriptor().Fields().ByNumber(genid.WrapperValue_Value_field_number) + val, err := d.unmarshalScalar(fd) + if err != nil { + return err + } + m.Set(fd, val) + return nil +} + +// The JSON representation for Empty is an empty JSON object. + +func (e encoder) marshalEmpty(protoreflect.Message) error { + e.StartObject() + e.EndObject() + return nil +} + +func (d decoder) unmarshalEmpty(protoreflect.Message) error { + tok, err := d.Read() + if err != nil { + return err + } + if tok.Kind() != json.ObjectOpen { + return d.unexpectedTokenError(tok) + } + + for { + tok, err := d.Read() + if err != nil { + return err + } + switch tok.Kind() { + case json.ObjectClose: + return nil + + case json.Name: + if d.opts.DiscardUnknown { + if err := d.skipJSONValue(); err != nil { + return err + } + continue + } + return d.newError(tok.Pos(), "unknown field %v", tok.RawString()) + + default: + return d.unexpectedTokenError(tok) + } + } +} + +// The JSON representation for Struct is a JSON object that contains the encoded +// Struct.fields map and follows the serialization rules for a map. + +func (e encoder) marshalStruct(m protoreflect.Message) error { + fd := m.Descriptor().Fields().ByNumber(genid.Struct_Fields_field_number) + return e.marshalMap(m.Get(fd).Map(), fd) +} + +func (d decoder) unmarshalStruct(m protoreflect.Message) error { + fd := m.Descriptor().Fields().ByNumber(genid.Struct_Fields_field_number) + return d.unmarshalMap(m.Mutable(fd).Map(), fd) +} + +// The JSON representation for ListValue is JSON array that contains the encoded +// ListValue.values repeated field and follows the serialization rules for a +// repeated field. + +func (e encoder) marshalListValue(m protoreflect.Message) error { + fd := m.Descriptor().Fields().ByNumber(genid.ListValue_Values_field_number) + return e.marshalList(m.Get(fd).List(), fd) +} + +func (d decoder) unmarshalListValue(m protoreflect.Message) error { + fd := m.Descriptor().Fields().ByNumber(genid.ListValue_Values_field_number) + return d.unmarshalList(m.Mutable(fd).List(), fd) +} + +// The JSON representation for a Value is dependent on the oneof field that is +// set. Each of the field in the oneof has its own custom serialization rule. A +// Value message needs to be a oneof field set, else it is an error. + +func (e encoder) marshalKnownValue(m protoreflect.Message) error { + od := m.Descriptor().Oneofs().ByName(genid.Value_Kind_oneof_name) + fd := m.WhichOneof(od) + if fd == nil { + return errors.New("%s: none of the oneof fields is set", genid.Value_message_fullname) + } + if fd.Number() == genid.Value_NumberValue_field_number { + if v := m.Get(fd).Float(); math.IsNaN(v) || math.IsInf(v, 0) { + return errors.New("%s: invalid %v value", genid.Value_NumberValue_field_fullname, v) + } + } + return e.marshalSingular(m.Get(fd), fd) +} + +func (d decoder) unmarshalKnownValue(m protoreflect.Message) error { + tok, err := d.Peek() + if err != nil { + return err + } + + var fd protoreflect.FieldDescriptor + var val protoreflect.Value + switch tok.Kind() { + case json.Null: + d.Read() + fd = m.Descriptor().Fields().ByNumber(genid.Value_NullValue_field_number) + val = protoreflect.ValueOfEnum(0) + + case json.Bool: + tok, err := d.Read() + if err != nil { + return err + } + fd = m.Descriptor().Fields().ByNumber(genid.Value_BoolValue_field_number) + val = protoreflect.ValueOfBool(tok.Bool()) + + case json.Number: + tok, err := d.Read() + if err != nil { + return err + } + fd = m.Descriptor().Fields().ByNumber(genid.Value_NumberValue_field_number) + var ok bool + val, ok = unmarshalFloat(tok, 64) + if !ok { + return d.newError(tok.Pos(), "invalid %v: %v", genid.Value_message_fullname, tok.RawString()) + } + + case json.String: + // A JSON string may have been encoded from the number_value field, + // e.g. "NaN", "Infinity", etc. Parsing a proto double type also allows + // for it to be in JSON string form. Given this custom encoding spec, + // however, there is no way to identify that and hence a JSON string is + // always assigned to the string_value field, which means that certain + // encoding cannot be parsed back to the same field. + tok, err := d.Read() + if err != nil { + return err + } + fd = m.Descriptor().Fields().ByNumber(genid.Value_StringValue_field_number) + val = protoreflect.ValueOfString(tok.ParsedString()) + + case json.ObjectOpen: + fd = m.Descriptor().Fields().ByNumber(genid.Value_StructValue_field_number) + val = m.NewField(fd) + if err := d.unmarshalStruct(val.Message()); err != nil { + return err + } + + case json.ArrayOpen: + fd = m.Descriptor().Fields().ByNumber(genid.Value_ListValue_field_number) + val = m.NewField(fd) + if err := d.unmarshalListValue(val.Message()); err != nil { + return err + } + + default: + return d.newError(tok.Pos(), "invalid %v: %v", genid.Value_message_fullname, tok.RawString()) + } + + m.Set(fd, val) + return nil +} + +// The JSON representation for a Duration is a JSON string that ends in the +// suffix "s" (indicating seconds) and is preceded by the number of seconds, +// with nanoseconds expressed as fractional seconds. +// +// Durations less than one second are represented with a 0 seconds field and a +// positive or negative nanos field. For durations of one second or more, a +// non-zero value for the nanos field must be of the same sign as the seconds +// field. +// +// Duration.seconds must be from -315,576,000,000 to +315,576,000,000 inclusive. +// Duration.nanos must be from -999,999,999 to +999,999,999 inclusive. + +const ( + secondsInNanos = 999999999 + maxSecondsInDuration = 315576000000 +) + +func (e encoder) marshalDuration(m protoreflect.Message) error { + fds := m.Descriptor().Fields() + fdSeconds := fds.ByNumber(genid.Duration_Seconds_field_number) + fdNanos := fds.ByNumber(genid.Duration_Nanos_field_number) + + secsVal := m.Get(fdSeconds) + nanosVal := m.Get(fdNanos) + secs := secsVal.Int() + nanos := nanosVal.Int() + if secs < -maxSecondsInDuration || secs > maxSecondsInDuration { + return errors.New("%s: seconds out of range %v", genid.Duration_message_fullname, secs) + } + if nanos < -secondsInNanos || nanos > secondsInNanos { + return errors.New("%s: nanos out of range %v", genid.Duration_message_fullname, nanos) + } + if (secs > 0 && nanos < 0) || (secs < 0 && nanos > 0) { + return errors.New("%s: signs of seconds and nanos do not match", genid.Duration_message_fullname) + } + // Generated output always contains 0, 3, 6, or 9 fractional digits, + // depending on required precision, followed by the suffix "s". + var sign string + if secs < 0 || nanos < 0 { + sign, secs, nanos = "-", -1*secs, -1*nanos + } + x := fmt.Sprintf("%s%d.%09d", sign, secs, nanos) + x = strings.TrimSuffix(x, "000") + x = strings.TrimSuffix(x, "000") + x = strings.TrimSuffix(x, ".000") + e.WriteString(x + "s") + return nil +} + +func (d decoder) unmarshalDuration(m protoreflect.Message) error { + tok, err := d.Read() + if err != nil { + return err + } + if tok.Kind() != json.String { + return d.unexpectedTokenError(tok) + } + + secs, nanos, ok := parseDuration(tok.ParsedString()) + if !ok { + return d.newError(tok.Pos(), "invalid %v value %v", genid.Duration_message_fullname, tok.RawString()) + } + // Validate seconds. No need to validate nanos because parseDuration would + // have covered that already. + if secs < -maxSecondsInDuration || secs > maxSecondsInDuration { + return d.newError(tok.Pos(), "%v value out of range: %v", genid.Duration_message_fullname, tok.RawString()) + } + + fds := m.Descriptor().Fields() + fdSeconds := fds.ByNumber(genid.Duration_Seconds_field_number) + fdNanos := fds.ByNumber(genid.Duration_Nanos_field_number) + + m.Set(fdSeconds, protoreflect.ValueOfInt64(secs)) + m.Set(fdNanos, protoreflect.ValueOfInt32(nanos)) + return nil +} + +// parseDuration parses the given input string for seconds and nanoseconds value +// for the Duration JSON format. The format is a decimal number with a suffix +// 's'. It can have optional plus/minus sign. There needs to be at least an +// integer or fractional part. Fractional part is limited to 9 digits only for +// nanoseconds precision, regardless of whether there are trailing zero digits. +// Example values are 1s, 0.1s, 1.s, .1s, +1s, -1s, -.1s. +func parseDuration(input string) (int64, int32, bool) { + b := []byte(input) + size := len(b) + if size < 2 { + return 0, 0, false + } + if b[size-1] != 's' { + return 0, 0, false + } + b = b[:size-1] + + // Read optional plus/minus symbol. + var neg bool + switch b[0] { + case '-': + neg = true + b = b[1:] + case '+': + b = b[1:] + } + if len(b) == 0 { + return 0, 0, false + } + + // Read the integer part. + var intp []byte + switch { + case b[0] == '0': + b = b[1:] + + case '1' <= b[0] && b[0] <= '9': + intp = b[0:] + b = b[1:] + n := 1 + for len(b) > 0 && '0' <= b[0] && b[0] <= '9' { + n++ + b = b[1:] + } + intp = intp[:n] + + case b[0] == '.': + // Continue below. + + default: + return 0, 0, false + } + + hasFrac := false + var frac [9]byte + if len(b) > 0 { + if b[0] != '.' { + return 0, 0, false + } + // Read the fractional part. + b = b[1:] + n := 0 + for len(b) > 0 && n < 9 && '0' <= b[0] && b[0] <= '9' { + frac[n] = b[0] + n++ + b = b[1:] + } + // It is not valid if there are more bytes left. + if len(b) > 0 { + return 0, 0, false + } + // Pad fractional part with 0s. + for i := n; i < 9; i++ { + frac[i] = '0' + } + hasFrac = true + } + + var secs int64 + if len(intp) > 0 { + var err error + secs, err = strconv.ParseInt(string(intp), 10, 64) + if err != nil { + return 0, 0, false + } + } + + var nanos int64 + if hasFrac { + nanob := bytes.TrimLeft(frac[:], "0") + if len(nanob) > 0 { + var err error + nanos, err = strconv.ParseInt(string(nanob), 10, 32) + if err != nil { + return 0, 0, false + } + } + } + + if neg { + if secs > 0 { + secs = -secs + } + if nanos > 0 { + nanos = -nanos + } + } + return secs, int32(nanos), true +} + +// The JSON representation for a Timestamp is a JSON string in the RFC 3339 +// format, i.e. "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where +// {year} is always expressed using four digits while {month}, {day}, {hour}, +// {min}, and {sec} are zero-padded to two digits each. The fractional seconds, +// which can go up to 9 digits, up to 1 nanosecond resolution, is optional. The +// "Z" suffix indicates the timezone ("UTC"); the timezone is required. Encoding +// should always use UTC (as indicated by "Z") and a decoder should be able to +// accept both UTC and other timezones (as indicated by an offset). +// +// Timestamp.seconds must be from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z +// inclusive. +// Timestamp.nanos must be from 0 to 999,999,999 inclusive. + +const ( + maxTimestampSeconds = 253402300799 + minTimestampSeconds = -62135596800 +) + +func (e encoder) marshalTimestamp(m protoreflect.Message) error { + fds := m.Descriptor().Fields() + fdSeconds := fds.ByNumber(genid.Timestamp_Seconds_field_number) + fdNanos := fds.ByNumber(genid.Timestamp_Nanos_field_number) + + secsVal := m.Get(fdSeconds) + nanosVal := m.Get(fdNanos) + secs := secsVal.Int() + nanos := nanosVal.Int() + if secs < minTimestampSeconds || secs > maxTimestampSeconds { + return errors.New("%s: seconds out of range %v", genid.Timestamp_message_fullname, secs) + } + if nanos < 0 || nanos > secondsInNanos { + return errors.New("%s: nanos out of range %v", genid.Timestamp_message_fullname, nanos) + } + // Uses RFC 3339, where generated output will be Z-normalized and uses 0, 3, + // 6 or 9 fractional digits. + t := time.Unix(secs, nanos).UTC() + x := t.Format("2006-01-02T15:04:05.000000000") + x = strings.TrimSuffix(x, "000") + x = strings.TrimSuffix(x, "000") + x = strings.TrimSuffix(x, ".000") + e.WriteString(x + "Z") + return nil +} + +func (d decoder) unmarshalTimestamp(m protoreflect.Message) error { + tok, err := d.Read() + if err != nil { + return err + } + if tok.Kind() != json.String { + return d.unexpectedTokenError(tok) + } + + s := tok.ParsedString() + t, err := time.Parse(time.RFC3339Nano, s) + if err != nil { + return d.newError(tok.Pos(), "invalid %v value %v", genid.Timestamp_message_fullname, tok.RawString()) + } + // Validate seconds. + secs := t.Unix() + if secs < minTimestampSeconds || secs > maxTimestampSeconds { + return d.newError(tok.Pos(), "%v value out of range: %v", genid.Timestamp_message_fullname, tok.RawString()) + } + // Validate subseconds. + i := strings.LastIndexByte(s, '.') // start of subsecond field + j := strings.LastIndexAny(s, "Z-+") // start of timezone field + if i >= 0 && j >= i && j-i > len(".999999999") { + return d.newError(tok.Pos(), "invalid %v value %v", genid.Timestamp_message_fullname, tok.RawString()) + } + + fds := m.Descriptor().Fields() + fdSeconds := fds.ByNumber(genid.Timestamp_Seconds_field_number) + fdNanos := fds.ByNumber(genid.Timestamp_Nanos_field_number) + + m.Set(fdSeconds, protoreflect.ValueOfInt64(secs)) + m.Set(fdNanos, protoreflect.ValueOfInt32(int32(t.Nanosecond()))) + return nil +} + +// The JSON representation for a FieldMask is a JSON string where paths are +// separated by a comma. Fields name in each path are converted to/from +// lower-camel naming conventions. Encoding should fail if the path name would +// end up differently after a round-trip. + +func (e encoder) marshalFieldMask(m protoreflect.Message) error { + fd := m.Descriptor().Fields().ByNumber(genid.FieldMask_Paths_field_number) + list := m.Get(fd).List() + paths := make([]string, 0, list.Len()) + + for i := 0; i < list.Len(); i++ { + s := list.Get(i).String() + if !protoreflect.FullName(s).IsValid() { + return errors.New("%s contains invalid path: %q", genid.FieldMask_Paths_field_fullname, s) + } + // Return error if conversion to camelCase is not reversible. + cc := strs.JSONCamelCase(s) + if s != strs.JSONSnakeCase(cc) { + return errors.New("%s contains irreversible value %q", genid.FieldMask_Paths_field_fullname, s) + } + paths = append(paths, cc) + } + + e.WriteString(strings.Join(paths, ",")) + return nil +} + +func (d decoder) unmarshalFieldMask(m protoreflect.Message) error { + tok, err := d.Read() + if err != nil { + return err + } + if tok.Kind() != json.String { + return d.unexpectedTokenError(tok) + } + str := strings.TrimSpace(tok.ParsedString()) + if str == "" { + return nil + } + paths := strings.Split(str, ",") + + fd := m.Descriptor().Fields().ByNumber(genid.FieldMask_Paths_field_number) + list := m.Mutable(fd).List() + + for _, s0 := range paths { + s := strs.JSONSnakeCase(s0) + if strings.Contains(s0, "_") || !protoreflect.FullName(s).IsValid() { + return d.newError(tok.Pos(), "%v contains invalid path: %q", genid.FieldMask_Paths_field_fullname, s0) + } + list.Append(protoreflect.ValueOfString(s)) + } + return nil +} diff --git a/vendor/google.golang.org/protobuf/internal/encoding/json/decode.go b/vendor/google.golang.org/protobuf/internal/encoding/json/decode.go new file mode 100644 index 00000000000..d2b3ac031e1 --- /dev/null +++ b/vendor/google.golang.org/protobuf/internal/encoding/json/decode.go @@ -0,0 +1,340 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package json + +import ( + "bytes" + "fmt" + "io" + "regexp" + "unicode/utf8" + + "google.golang.org/protobuf/internal/errors" +) + +// call specifies which Decoder method was invoked. +type call uint8 + +const ( + readCall call = iota + peekCall +) + +const unexpectedFmt = "unexpected token %s" + +// ErrUnexpectedEOF means that EOF was encountered in the middle of the input. +var ErrUnexpectedEOF = errors.New("%v", io.ErrUnexpectedEOF) + +// Decoder is a token-based JSON decoder. +type Decoder struct { + // lastCall is last method called, either readCall or peekCall. + // Initial value is readCall. + lastCall call + + // lastToken contains the last read token. + lastToken Token + + // lastErr contains the last read error. + lastErr error + + // openStack is a stack containing ObjectOpen and ArrayOpen values. The + // top of stack represents the object or the array the current value is + // directly located in. + openStack []Kind + + // orig is used in reporting line and column. + orig []byte + // in contains the unconsumed input. + in []byte +} + +// NewDecoder returns a Decoder to read the given []byte. +func NewDecoder(b []byte) *Decoder { + return &Decoder{orig: b, in: b} +} + +// Peek looks ahead and returns the next token kind without advancing a read. +func (d *Decoder) Peek() (Token, error) { + defer func() { d.lastCall = peekCall }() + if d.lastCall == readCall { + d.lastToken, d.lastErr = d.Read() + } + return d.lastToken, d.lastErr +} + +// Read returns the next JSON token. +// It will return an error if there is no valid token. +func (d *Decoder) Read() (Token, error) { + const scalar = Null | Bool | Number | String + + defer func() { d.lastCall = readCall }() + if d.lastCall == peekCall { + return d.lastToken, d.lastErr + } + + tok, err := d.parseNext() + if err != nil { + return Token{}, err + } + + switch tok.kind { + case EOF: + if len(d.openStack) != 0 || + d.lastToken.kind&scalar|ObjectClose|ArrayClose == 0 { + return Token{}, ErrUnexpectedEOF + } + + case Null: + if !d.isValueNext() { + return Token{}, d.newSyntaxError(tok.pos, unexpectedFmt, tok.RawString()) + } + + case Bool, Number: + if !d.isValueNext() { + return Token{}, d.newSyntaxError(tok.pos, unexpectedFmt, tok.RawString()) + } + + case String: + if d.isValueNext() { + break + } + // This string token should only be for a field name. + if d.lastToken.kind&(ObjectOpen|comma) == 0 { + return Token{}, d.newSyntaxError(tok.pos, unexpectedFmt, tok.RawString()) + } + if len(d.in) == 0 { + return Token{}, ErrUnexpectedEOF + } + if c := d.in[0]; c != ':' { + return Token{}, d.newSyntaxError(d.currPos(), `unexpected character %s, missing ":" after field name`, string(c)) + } + tok.kind = Name + d.consume(1) + + case ObjectOpen, ArrayOpen: + if !d.isValueNext() { + return Token{}, d.newSyntaxError(tok.pos, unexpectedFmt, tok.RawString()) + } + d.openStack = append(d.openStack, tok.kind) + + case ObjectClose: + if len(d.openStack) == 0 || + d.lastToken.kind&(Name|comma) != 0 || + d.openStack[len(d.openStack)-1] != ObjectOpen { + return Token{}, d.newSyntaxError(tok.pos, unexpectedFmt, tok.RawString()) + } + d.openStack = d.openStack[:len(d.openStack)-1] + + case ArrayClose: + if len(d.openStack) == 0 || + d.lastToken.kind == comma || + d.openStack[len(d.openStack)-1] != ArrayOpen { + return Token{}, d.newSyntaxError(tok.pos, unexpectedFmt, tok.RawString()) + } + d.openStack = d.openStack[:len(d.openStack)-1] + + case comma: + if len(d.openStack) == 0 || + d.lastToken.kind&(scalar|ObjectClose|ArrayClose) == 0 { + return Token{}, d.newSyntaxError(tok.pos, unexpectedFmt, tok.RawString()) + } + } + + // Update d.lastToken only after validating token to be in the right sequence. + d.lastToken = tok + + if d.lastToken.kind == comma { + return d.Read() + } + return tok, nil +} + +// Any sequence that looks like a non-delimiter (for error reporting). +var errRegexp = regexp.MustCompile(`^([-+._a-zA-Z0-9]{1,32}|.)`) + +// parseNext parses for the next JSON token. It returns a Token object for +// different types, except for Name. It does not handle whether the next token +// is in a valid sequence or not. +func (d *Decoder) parseNext() (Token, error) { + // Trim leading spaces. + d.consume(0) + + in := d.in + if len(in) == 0 { + return d.consumeToken(EOF, 0), nil + } + + switch in[0] { + case 'n': + if n := matchWithDelim("null", in); n != 0 { + return d.consumeToken(Null, n), nil + } + + case 't': + if n := matchWithDelim("true", in); n != 0 { + return d.consumeBoolToken(true, n), nil + } + + case 'f': + if n := matchWithDelim("false", in); n != 0 { + return d.consumeBoolToken(false, n), nil + } + + case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + if n, ok := parseNumber(in); ok { + return d.consumeToken(Number, n), nil + } + + case '"': + s, n, err := d.parseString(in) + if err != nil { + return Token{}, err + } + return d.consumeStringToken(s, n), nil + + case '{': + return d.consumeToken(ObjectOpen, 1), nil + + case '}': + return d.consumeToken(ObjectClose, 1), nil + + case '[': + return d.consumeToken(ArrayOpen, 1), nil + + case ']': + return d.consumeToken(ArrayClose, 1), nil + + case ',': + return d.consumeToken(comma, 1), nil + } + return Token{}, d.newSyntaxError(d.currPos(), "invalid value %s", errRegexp.Find(in)) +} + +// newSyntaxError returns an error with line and column information useful for +// syntax errors. +func (d *Decoder) newSyntaxError(pos int, f string, x ...interface{}) error { + e := errors.New(f, x...) + line, column := d.Position(pos) + return errors.New("syntax error (line %d:%d): %v", line, column, e) +} + +// Position returns line and column number of given index of the original input. +// It will panic if index is out of range. +func (d *Decoder) Position(idx int) (line int, column int) { + b := d.orig[:idx] + line = bytes.Count(b, []byte("\n")) + 1 + if i := bytes.LastIndexByte(b, '\n'); i >= 0 { + b = b[i+1:] + } + column = utf8.RuneCount(b) + 1 // ignore multi-rune characters + return line, column +} + +// currPos returns the current index position of d.in from d.orig. +func (d *Decoder) currPos() int { + return len(d.orig) - len(d.in) +} + +// matchWithDelim matches s with the input b and verifies that the match +// terminates with a delimiter of some form (e.g., r"[^-+_.a-zA-Z0-9]"). +// As a special case, EOF is considered a delimiter. It returns the length of s +// if there is a match, else 0. +func matchWithDelim(s string, b []byte) int { + if !bytes.HasPrefix(b, []byte(s)) { + return 0 + } + + n := len(s) + if n < len(b) && isNotDelim(b[n]) { + return 0 + } + return n +} + +// isNotDelim returns true if given byte is a not delimiter character. +func isNotDelim(c byte) bool { + return (c == '-' || c == '+' || c == '.' || c == '_' || + ('a' <= c && c <= 'z') || + ('A' <= c && c <= 'Z') || + ('0' <= c && c <= '9')) +} + +// consume consumes n bytes of input and any subsequent whitespace. +func (d *Decoder) consume(n int) { + d.in = d.in[n:] + for len(d.in) > 0 { + switch d.in[0] { + case ' ', '\n', '\r', '\t': + d.in = d.in[1:] + default: + return + } + } +} + +// isValueNext returns true if next type should be a JSON value: Null, +// Number, String or Bool. +func (d *Decoder) isValueNext() bool { + if len(d.openStack) == 0 { + return d.lastToken.kind == 0 + } + + start := d.openStack[len(d.openStack)-1] + switch start { + case ObjectOpen: + return d.lastToken.kind&Name != 0 + case ArrayOpen: + return d.lastToken.kind&(ArrayOpen|comma) != 0 + } + panic(fmt.Sprintf( + "unreachable logic in Decoder.isValueNext, lastToken.kind: %v, openStack: %v", + d.lastToken.kind, start)) +} + +// consumeToken constructs a Token for given Kind with raw value derived from +// current d.in and given size, and consumes the given size-length of it. +func (d *Decoder) consumeToken(kind Kind, size int) Token { + tok := Token{ + kind: kind, + raw: d.in[:size], + pos: len(d.orig) - len(d.in), + } + d.consume(size) + return tok +} + +// consumeBoolToken constructs a Token for a Bool kind with raw value derived from +// current d.in and given size. +func (d *Decoder) consumeBoolToken(b bool, size int) Token { + tok := Token{ + kind: Bool, + raw: d.in[:size], + pos: len(d.orig) - len(d.in), + boo: b, + } + d.consume(size) + return tok +} + +// consumeStringToken constructs a Token for a String kind with raw value derived +// from current d.in and given size. +func (d *Decoder) consumeStringToken(s string, size int) Token { + tok := Token{ + kind: String, + raw: d.in[:size], + pos: len(d.orig) - len(d.in), + str: s, + } + d.consume(size) + return tok +} + +// Clone returns a copy of the Decoder for use in reading ahead the next JSON +// object, array or other values without affecting current Decoder. +func (d *Decoder) Clone() *Decoder { + ret := *d + ret.openStack = append([]Kind(nil), ret.openStack...) + return &ret +} diff --git a/vendor/google.golang.org/protobuf/internal/encoding/json/decode_number.go b/vendor/google.golang.org/protobuf/internal/encoding/json/decode_number.go new file mode 100644 index 00000000000..2999d713320 --- /dev/null +++ b/vendor/google.golang.org/protobuf/internal/encoding/json/decode_number.go @@ -0,0 +1,254 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package json + +import ( + "bytes" + "strconv" +) + +// parseNumber reads the given []byte for a valid JSON number. If it is valid, +// it returns the number of bytes. Parsing logic follows the definition in +// https://tools.ietf.org/html/rfc7159#section-6, and is based off +// encoding/json.isValidNumber function. +func parseNumber(input []byte) (int, bool) { + var n int + + s := input + if len(s) == 0 { + return 0, false + } + + // Optional - + if s[0] == '-' { + s = s[1:] + n++ + if len(s) == 0 { + return 0, false + } + } + + // Digits + switch { + case s[0] == '0': + s = s[1:] + n++ + + case '1' <= s[0] && s[0] <= '9': + s = s[1:] + n++ + for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { + s = s[1:] + n++ + } + + default: + return 0, false + } + + // . followed by 1 or more digits. + if len(s) >= 2 && s[0] == '.' && '0' <= s[1] && s[1] <= '9' { + s = s[2:] + n += 2 + for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { + s = s[1:] + n++ + } + } + + // e or E followed by an optional - or + and + // 1 or more digits. + if len(s) >= 2 && (s[0] == 'e' || s[0] == 'E') { + s = s[1:] + n++ + if s[0] == '+' || s[0] == '-' { + s = s[1:] + n++ + if len(s) == 0 { + return 0, false + } + } + for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { + s = s[1:] + n++ + } + } + + // Check that next byte is a delimiter or it is at the end. + if n < len(input) && isNotDelim(input[n]) { + return 0, false + } + + return n, true +} + +// numberParts is the result of parsing out a valid JSON number. It contains +// the parts of a number. The parts are used for integer conversion. +type numberParts struct { + neg bool + intp []byte + frac []byte + exp []byte +} + +// parseNumber constructs numberParts from given []byte. The logic here is +// similar to consumeNumber above with the difference of having to construct +// numberParts. The slice fields in numberParts are subslices of the input. +func parseNumberParts(input []byte) (numberParts, bool) { + var neg bool + var intp []byte + var frac []byte + var exp []byte + + s := input + if len(s) == 0 { + return numberParts{}, false + } + + // Optional - + if s[0] == '-' { + neg = true + s = s[1:] + if len(s) == 0 { + return numberParts{}, false + } + } + + // Digits + switch { + case s[0] == '0': + // Skip first 0 and no need to store. + s = s[1:] + + case '1' <= s[0] && s[0] <= '9': + intp = s + n := 1 + s = s[1:] + for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { + s = s[1:] + n++ + } + intp = intp[:n] + + default: + return numberParts{}, false + } + + // . followed by 1 or more digits. + if len(s) >= 2 && s[0] == '.' && '0' <= s[1] && s[1] <= '9' { + frac = s[1:] + n := 1 + s = s[2:] + for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { + s = s[1:] + n++ + } + frac = frac[:n] + } + + // e or E followed by an optional - or + and + // 1 or more digits. + if len(s) >= 2 && (s[0] == 'e' || s[0] == 'E') { + s = s[1:] + exp = s + n := 0 + if s[0] == '+' || s[0] == '-' { + s = s[1:] + n++ + if len(s) == 0 { + return numberParts{}, false + } + } + for len(s) > 0 && '0' <= s[0] && s[0] <= '9' { + s = s[1:] + n++ + } + exp = exp[:n] + } + + return numberParts{ + neg: neg, + intp: intp, + frac: bytes.TrimRight(frac, "0"), // Remove unnecessary 0s to the right. + exp: exp, + }, true +} + +// normalizeToIntString returns an integer string in normal form without the +// E-notation for given numberParts. It will return false if it is not an +// integer or if the exponent exceeds than max/min int value. +func normalizeToIntString(n numberParts) (string, bool) { + intpSize := len(n.intp) + fracSize := len(n.frac) + + if intpSize == 0 && fracSize == 0 { + return "0", true + } + + var exp int + if len(n.exp) > 0 { + i, err := strconv.ParseInt(string(n.exp), 10, 32) + if err != nil { + return "", false + } + exp = int(i) + } + + var num []byte + if exp >= 0 { + // For positive E, shift fraction digits into integer part and also pad + // with zeroes as needed. + + // If there are more digits in fraction than the E value, then the + // number is not an integer. + if fracSize > exp { + return "", false + } + + // Make sure resulting digits are within max value limit to avoid + // unnecessarily constructing a large byte slice that may simply fail + // later on. + const maxDigits = 20 // Max uint64 value has 20 decimal digits. + if intpSize+exp > maxDigits { + return "", false + } + + // Set cap to make a copy of integer part when appended. + num = n.intp[:len(n.intp):len(n.intp)] + num = append(num, n.frac...) + for i := 0; i < exp-fracSize; i++ { + num = append(num, '0') + } + } else { + // For negative E, shift digits in integer part out. + + // If there are fractions, then the number is not an integer. + if fracSize > 0 { + return "", false + } + + // index is where the decimal point will be after adjusting for negative + // exponent. + index := intpSize + exp + if index < 0 { + return "", false + } + + num = n.intp + // If any of the digits being shifted to the right of the decimal point + // is non-zero, then the number is not an integer. + for i := index; i < intpSize; i++ { + if num[i] != '0' { + return "", false + } + } + num = num[:index] + } + + if n.neg { + return "-" + string(num), true + } + return string(num), true +} diff --git a/vendor/google.golang.org/protobuf/internal/encoding/json/decode_string.go b/vendor/google.golang.org/protobuf/internal/encoding/json/decode_string.go new file mode 100644 index 00000000000..f7fea7d8dd4 --- /dev/null +++ b/vendor/google.golang.org/protobuf/internal/encoding/json/decode_string.go @@ -0,0 +1,91 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package json + +import ( + "strconv" + "unicode" + "unicode/utf16" + "unicode/utf8" + + "google.golang.org/protobuf/internal/strs" +) + +func (d *Decoder) parseString(in []byte) (string, int, error) { + in0 := in + if len(in) == 0 { + return "", 0, ErrUnexpectedEOF + } + if in[0] != '"' { + return "", 0, d.newSyntaxError(d.currPos(), "invalid character %q at start of string", in[0]) + } + in = in[1:] + i := indexNeedEscapeInBytes(in) + in, out := in[i:], in[:i:i] // set cap to prevent mutations + for len(in) > 0 { + switch r, n := utf8.DecodeRune(in); { + case r == utf8.RuneError && n == 1: + return "", 0, d.newSyntaxError(d.currPos(), "invalid UTF-8 in string") + case r < ' ': + return "", 0, d.newSyntaxError(d.currPos(), "invalid character %q in string", r) + case r == '"': + in = in[1:] + n := len(in0) - len(in) + return string(out), n, nil + case r == '\\': + if len(in) < 2 { + return "", 0, ErrUnexpectedEOF + } + switch r := in[1]; r { + case '"', '\\', '/': + in, out = in[2:], append(out, r) + case 'b': + in, out = in[2:], append(out, '\b') + case 'f': + in, out = in[2:], append(out, '\f') + case 'n': + in, out = in[2:], append(out, '\n') + case 'r': + in, out = in[2:], append(out, '\r') + case 't': + in, out = in[2:], append(out, '\t') + case 'u': + if len(in) < 6 { + return "", 0, ErrUnexpectedEOF + } + v, err := strconv.ParseUint(string(in[2:6]), 16, 16) + if err != nil { + return "", 0, d.newSyntaxError(d.currPos(), "invalid escape code %q in string", in[:6]) + } + in = in[6:] + + r := rune(v) + if utf16.IsSurrogate(r) { + if len(in) < 6 { + return "", 0, ErrUnexpectedEOF + } + v, err := strconv.ParseUint(string(in[2:6]), 16, 16) + r = utf16.DecodeRune(r, rune(v)) + if in[0] != '\\' || in[1] != 'u' || + r == unicode.ReplacementChar || err != nil { + return "", 0, d.newSyntaxError(d.currPos(), "invalid escape code %q in string", in[:6]) + } + in = in[6:] + } + out = append(out, string(r)...) + default: + return "", 0, d.newSyntaxError(d.currPos(), "invalid escape code %q in string", in[:2]) + } + default: + i := indexNeedEscapeInBytes(in[n:]) + in, out = in[n+i:], append(out, in[:n+i]...) + } + } + return "", 0, ErrUnexpectedEOF +} + +// indexNeedEscapeInBytes returns the index of the character that needs +// escaping. If no characters need escaping, this returns the input length. +func indexNeedEscapeInBytes(b []byte) int { return indexNeedEscapeInString(strs.UnsafeString(b)) } diff --git a/vendor/google.golang.org/protobuf/internal/encoding/json/decode_token.go b/vendor/google.golang.org/protobuf/internal/encoding/json/decode_token.go new file mode 100644 index 00000000000..50578d6593c --- /dev/null +++ b/vendor/google.golang.org/protobuf/internal/encoding/json/decode_token.go @@ -0,0 +1,192 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package json + +import ( + "bytes" + "fmt" + "strconv" +) + +// Kind represents a token kind expressible in the JSON format. +type Kind uint16 + +const ( + Invalid Kind = (1 << iota) / 2 + EOF + Null + Bool + Number + String + Name + ObjectOpen + ObjectClose + ArrayOpen + ArrayClose + + // comma is only for parsing in between tokens and + // does not need to be exported. + comma +) + +func (k Kind) String() string { + switch k { + case EOF: + return "eof" + case Null: + return "null" + case Bool: + return "bool" + case Number: + return "number" + case String: + return "string" + case ObjectOpen: + return "{" + case ObjectClose: + return "}" + case Name: + return "name" + case ArrayOpen: + return "[" + case ArrayClose: + return "]" + case comma: + return "," + } + return "" +} + +// Token provides a parsed token kind and value. +// +// Values are provided by the difference accessor methods. The accessor methods +// Name, Bool, and ParsedString will panic if called on the wrong kind. There +// are different accessor methods for the Number kind for converting to the +// appropriate Go numeric type and those methods have the ok return value. +type Token struct { + // Token kind. + kind Kind + // pos provides the position of the token in the original input. + pos int + // raw bytes of the serialized token. + // This is a subslice into the original input. + raw []byte + // boo is parsed boolean value. + boo bool + // str is parsed string value. + str string +} + +// Kind returns the token kind. +func (t Token) Kind() Kind { + return t.kind +} + +// RawString returns the read value in string. +func (t Token) RawString() string { + return string(t.raw) +} + +// Pos returns the token position from the input. +func (t Token) Pos() int { + return t.pos +} + +// Name returns the object name if token is Name, else it panics. +func (t Token) Name() string { + if t.kind == Name { + return t.str + } + panic(fmt.Sprintf("Token is not a Name: %v", t.RawString())) +} + +// Bool returns the bool value if token kind is Bool, else it panics. +func (t Token) Bool() bool { + if t.kind == Bool { + return t.boo + } + panic(fmt.Sprintf("Token is not a Bool: %v", t.RawString())) +} + +// ParsedString returns the string value for a JSON string token or the read +// value in string if token is not a string. +func (t Token) ParsedString() string { + if t.kind == String { + return t.str + } + panic(fmt.Sprintf("Token is not a String: %v", t.RawString())) +} + +// Float returns the floating-point number if token kind is Number. +// +// The floating-point precision is specified by the bitSize parameter: 32 for +// float32 or 64 for float64. If bitSize=32, the result still has type float64, +// but it will be convertible to float32 without changing its value. It will +// return false if the number exceeds the floating point limits for given +// bitSize. +func (t Token) Float(bitSize int) (float64, bool) { + if t.kind != Number { + return 0, false + } + f, err := strconv.ParseFloat(t.RawString(), bitSize) + if err != nil { + return 0, false + } + return f, true +} + +// Int returns the signed integer number if token is Number. +// +// The given bitSize specifies the integer type that the result must fit into. +// It returns false if the number is not an integer value or if the result +// exceeds the limits for given bitSize. +func (t Token) Int(bitSize int) (int64, bool) { + s, ok := t.getIntStr() + if !ok { + return 0, false + } + n, err := strconv.ParseInt(s, 10, bitSize) + if err != nil { + return 0, false + } + return n, true +} + +// Uint returns the signed integer number if token is Number. +// +// The given bitSize specifies the unsigned integer type that the result must +// fit into. It returns false if the number is not an unsigned integer value +// or if the result exceeds the limits for given bitSize. +func (t Token) Uint(bitSize int) (uint64, bool) { + s, ok := t.getIntStr() + if !ok { + return 0, false + } + n, err := strconv.ParseUint(s, 10, bitSize) + if err != nil { + return 0, false + } + return n, true +} + +func (t Token) getIntStr() (string, bool) { + if t.kind != Number { + return "", false + } + parts, ok := parseNumberParts(t.raw) + if !ok { + return "", false + } + return normalizeToIntString(parts) +} + +// TokenEquals returns true if given Tokens are equal, else false. +func TokenEquals(x, y Token) bool { + return x.kind == y.kind && + x.pos == y.pos && + bytes.Equal(x.raw, y.raw) && + x.boo == y.boo && + x.str == y.str +} diff --git a/vendor/google.golang.org/protobuf/internal/encoding/json/encode.go b/vendor/google.golang.org/protobuf/internal/encoding/json/encode.go new file mode 100644 index 00000000000..934f2dcb39d --- /dev/null +++ b/vendor/google.golang.org/protobuf/internal/encoding/json/encode.go @@ -0,0 +1,278 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package json + +import ( + "math" + "math/bits" + "strconv" + "strings" + "unicode/utf8" + + "google.golang.org/protobuf/internal/detrand" + "google.golang.org/protobuf/internal/errors" +) + +// kind represents an encoding type. +type kind uint8 + +const ( + _ kind = (1 << iota) / 2 + name + scalar + objectOpen + objectClose + arrayOpen + arrayClose +) + +// Encoder provides methods to write out JSON constructs and values. The user is +// responsible for producing valid sequences of JSON constructs and values. +type Encoder struct { + indent string + lastKind kind + indents []byte + out []byte +} + +// NewEncoder returns an Encoder. +// +// If indent is a non-empty string, it causes every entry for an Array or Object +// to be preceded by the indent and trailed by a newline. +func NewEncoder(buf []byte, indent string) (*Encoder, error) { + e := &Encoder{ + out: buf, + } + if len(indent) > 0 { + if strings.Trim(indent, " \t") != "" { + return nil, errors.New("indent may only be composed of space or tab characters") + } + e.indent = indent + } + return e, nil +} + +// Bytes returns the content of the written bytes. +func (e *Encoder) Bytes() []byte { + return e.out +} + +// WriteNull writes out the null value. +func (e *Encoder) WriteNull() { + e.prepareNext(scalar) + e.out = append(e.out, "null"...) +} + +// WriteBool writes out the given boolean value. +func (e *Encoder) WriteBool(b bool) { + e.prepareNext(scalar) + if b { + e.out = append(e.out, "true"...) + } else { + e.out = append(e.out, "false"...) + } +} + +// WriteString writes out the given string in JSON string value. Returns error +// if input string contains invalid UTF-8. +func (e *Encoder) WriteString(s string) error { + e.prepareNext(scalar) + var err error + if e.out, err = appendString(e.out, s); err != nil { + return err + } + return nil +} + +// Sentinel error used for indicating invalid UTF-8. +var errInvalidUTF8 = errors.New("invalid UTF-8") + +func appendString(out []byte, in string) ([]byte, error) { + out = append(out, '"') + i := indexNeedEscapeInString(in) + in, out = in[i:], append(out, in[:i]...) + for len(in) > 0 { + switch r, n := utf8.DecodeRuneInString(in); { + case r == utf8.RuneError && n == 1: + return out, errInvalidUTF8 + case r < ' ' || r == '"' || r == '\\': + out = append(out, '\\') + switch r { + case '"', '\\': + out = append(out, byte(r)) + case '\b': + out = append(out, 'b') + case '\f': + out = append(out, 'f') + case '\n': + out = append(out, 'n') + case '\r': + out = append(out, 'r') + case '\t': + out = append(out, 't') + default: + out = append(out, 'u') + out = append(out, "0000"[1+(bits.Len32(uint32(r))-1)/4:]...) + out = strconv.AppendUint(out, uint64(r), 16) + } + in = in[n:] + default: + i := indexNeedEscapeInString(in[n:]) + in, out = in[n+i:], append(out, in[:n+i]...) + } + } + out = append(out, '"') + return out, nil +} + +// indexNeedEscapeInString returns the index of the character that needs +// escaping. If no characters need escaping, this returns the input length. +func indexNeedEscapeInString(s string) int { + for i, r := range s { + if r < ' ' || r == '\\' || r == '"' || r == utf8.RuneError { + return i + } + } + return len(s) +} + +// WriteFloat writes out the given float and bitSize in JSON number value. +func (e *Encoder) WriteFloat(n float64, bitSize int) { + e.prepareNext(scalar) + e.out = appendFloat(e.out, n, bitSize) +} + +// appendFloat formats given float in bitSize, and appends to the given []byte. +func appendFloat(out []byte, n float64, bitSize int) []byte { + switch { + case math.IsNaN(n): + return append(out, `"NaN"`...) + case math.IsInf(n, +1): + return append(out, `"Infinity"`...) + case math.IsInf(n, -1): + return append(out, `"-Infinity"`...) + } + + // JSON number formatting logic based on encoding/json. + // See floatEncoder.encode for reference. + fmt := byte('f') + if abs := math.Abs(n); abs != 0 { + if bitSize == 64 && (abs < 1e-6 || abs >= 1e21) || + bitSize == 32 && (float32(abs) < 1e-6 || float32(abs) >= 1e21) { + fmt = 'e' + } + } + out = strconv.AppendFloat(out, n, fmt, -1, bitSize) + if fmt == 'e' { + n := len(out) + if n >= 4 && out[n-4] == 'e' && out[n-3] == '-' && out[n-2] == '0' { + out[n-2] = out[n-1] + out = out[:n-1] + } + } + return out +} + +// WriteInt writes out the given signed integer in JSON number value. +func (e *Encoder) WriteInt(n int64) { + e.prepareNext(scalar) + e.out = strconv.AppendInt(e.out, n, 10) +} + +// WriteUint writes out the given unsigned integer in JSON number value. +func (e *Encoder) WriteUint(n uint64) { + e.prepareNext(scalar) + e.out = strconv.AppendUint(e.out, n, 10) +} + +// StartObject writes out the '{' symbol. +func (e *Encoder) StartObject() { + e.prepareNext(objectOpen) + e.out = append(e.out, '{') +} + +// EndObject writes out the '}' symbol. +func (e *Encoder) EndObject() { + e.prepareNext(objectClose) + e.out = append(e.out, '}') +} + +// WriteName writes out the given string in JSON string value and the name +// separator ':'. Returns error if input string contains invalid UTF-8, which +// should not be likely as protobuf field names should be valid. +func (e *Encoder) WriteName(s string) error { + e.prepareNext(name) + var err error + // Append to output regardless of error. + e.out, err = appendString(e.out, s) + e.out = append(e.out, ':') + return err +} + +// StartArray writes out the '[' symbol. +func (e *Encoder) StartArray() { + e.prepareNext(arrayOpen) + e.out = append(e.out, '[') +} + +// EndArray writes out the ']' symbol. +func (e *Encoder) EndArray() { + e.prepareNext(arrayClose) + e.out = append(e.out, ']') +} + +// prepareNext adds possible comma and indentation for the next value based +// on last type and indent option. It also updates lastKind to next. +func (e *Encoder) prepareNext(next kind) { + defer func() { + // Set lastKind to next. + e.lastKind = next + }() + + if len(e.indent) == 0 { + // Need to add comma on the following condition. + if e.lastKind&(scalar|objectClose|arrayClose) != 0 && + next&(name|scalar|objectOpen|arrayOpen) != 0 { + e.out = append(e.out, ',') + // For single-line output, add a random extra space after each + // comma to make output unstable. + if detrand.Bool() { + e.out = append(e.out, ' ') + } + } + return + } + + switch { + case e.lastKind&(objectOpen|arrayOpen) != 0: + // If next type is NOT closing, add indent and newline. + if next&(objectClose|arrayClose) == 0 { + e.indents = append(e.indents, e.indent...) + e.out = append(e.out, '\n') + e.out = append(e.out, e.indents...) + } + + case e.lastKind&(scalar|objectClose|arrayClose) != 0: + switch { + // If next type is either a value or name, add comma and newline. + case next&(name|scalar|objectOpen|arrayOpen) != 0: + e.out = append(e.out, ',', '\n') + + // If next type is a closing object or array, adjust indentation. + case next&(objectClose|arrayClose) != 0: + e.indents = e.indents[:len(e.indents)-len(e.indent)] + e.out = append(e.out, '\n') + } + e.out = append(e.out, e.indents...) + + case e.lastKind&name != 0: + e.out = append(e.out, ' ') + // For multi-line output, add a random extra space after key: to make + // output unstable. + if detrand.Bool() { + e.out = append(e.out, ' ') + } + } +} diff --git a/vendor/google.golang.org/protobuf/internal/msgfmt/format.go b/vendor/google.golang.org/protobuf/internal/msgfmt/format.go deleted file mode 100644 index a319550f69e..00000000000 --- a/vendor/google.golang.org/protobuf/internal/msgfmt/format.go +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package msgfmt implements a text marshaler combining the desirable features -// of both the JSON and proto text formats. -// It is optimized for human readability and has no associated deserializer. -package msgfmt - -import ( - "bytes" - "fmt" - "reflect" - "sort" - "strconv" - "strings" - "time" - - "google.golang.org/protobuf/encoding/protowire" - "google.golang.org/protobuf/internal/detrand" - "google.golang.org/protobuf/internal/genid" - "google.golang.org/protobuf/internal/order" - "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/reflect/protoreflect" - "google.golang.org/protobuf/reflect/protoregistry" -) - -// Format returns a formatted string for the message. -func Format(m proto.Message) string { - return string(appendMessage(nil, m.ProtoReflect())) -} - -// FormatValue returns a formatted string for an arbitrary value. -func FormatValue(v protoreflect.Value, fd protoreflect.FieldDescriptor) string { - return string(appendValue(nil, v, fd)) -} - -func appendValue(b []byte, v protoreflect.Value, fd protoreflect.FieldDescriptor) []byte { - switch v := v.Interface().(type) { - case nil: - return append(b, ""...) - case bool, int32, int64, uint32, uint64, float32, float64: - return append(b, fmt.Sprint(v)...) - case string: - return append(b, strconv.Quote(string(v))...) - case []byte: - return append(b, strconv.Quote(string(v))...) - case protoreflect.EnumNumber: - return appendEnum(b, v, fd) - case protoreflect.Message: - return appendMessage(b, v) - case protoreflect.List: - return appendList(b, v, fd) - case protoreflect.Map: - return appendMap(b, v, fd) - default: - panic(fmt.Sprintf("invalid type: %T", v)) - } -} - -func appendEnum(b []byte, v protoreflect.EnumNumber, fd protoreflect.FieldDescriptor) []byte { - if fd != nil { - if ev := fd.Enum().Values().ByNumber(v); ev != nil { - return append(b, ev.Name()...) - } - } - return strconv.AppendInt(b, int64(v), 10) -} - -func appendMessage(b []byte, m protoreflect.Message) []byte { - if b2 := appendKnownMessage(b, m); b2 != nil { - return b2 - } - - b = append(b, '{') - order.RangeFields(m, order.IndexNameFieldOrder, func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool { - b = append(b, fd.TextName()...) - b = append(b, ':') - b = appendValue(b, v, fd) - b = append(b, delim()...) - return true - }) - b = appendUnknown(b, m.GetUnknown()) - b = bytes.TrimRight(b, delim()) - b = append(b, '}') - return b -} - -var protocmpMessageType = reflect.TypeOf(map[string]interface{}(nil)) - -func appendKnownMessage(b []byte, m protoreflect.Message) []byte { - md := m.Descriptor() - fds := md.Fields() - switch md.FullName() { - case genid.Any_message_fullname: - var msgVal protoreflect.Message - url := m.Get(fds.ByNumber(genid.Any_TypeUrl_field_number)).String() - if v := reflect.ValueOf(m); v.Type().ConvertibleTo(protocmpMessageType) { - // For protocmp.Message, directly obtain the sub-message value - // which is stored in structured form, rather than as raw bytes. - m2 := v.Convert(protocmpMessageType).Interface().(map[string]interface{}) - v, ok := m2[string(genid.Any_Value_field_name)].(proto.Message) - if !ok { - return nil - } - msgVal = v.ProtoReflect() - } else { - val := m.Get(fds.ByNumber(genid.Any_Value_field_number)).Bytes() - mt, err := protoregistry.GlobalTypes.FindMessageByURL(url) - if err != nil { - return nil - } - msgVal = mt.New() - err = proto.UnmarshalOptions{AllowPartial: true}.Unmarshal(val, msgVal.Interface()) - if err != nil { - return nil - } - } - - b = append(b, '{') - b = append(b, "["+url+"]"...) - b = append(b, ':') - b = appendMessage(b, msgVal) - b = append(b, '}') - return b - - case genid.Timestamp_message_fullname: - secs := m.Get(fds.ByNumber(genid.Timestamp_Seconds_field_number)).Int() - nanos := m.Get(fds.ByNumber(genid.Timestamp_Nanos_field_number)).Int() - if nanos < 0 || nanos >= 1e9 { - return nil - } - t := time.Unix(secs, nanos).UTC() - x := t.Format("2006-01-02T15:04:05.000000000") // RFC 3339 - x = strings.TrimSuffix(x, "000") - x = strings.TrimSuffix(x, "000") - x = strings.TrimSuffix(x, ".000") - return append(b, x+"Z"...) - - case genid.Duration_message_fullname: - sign := "" - secs := m.Get(fds.ByNumber(genid.Duration_Seconds_field_number)).Int() - nanos := m.Get(fds.ByNumber(genid.Duration_Nanos_field_number)).Int() - if nanos <= -1e9 || nanos >= 1e9 || (secs > 0 && nanos < 0) || (secs < 0 && nanos > 0) { - return nil - } - if secs < 0 || nanos < 0 { - sign, secs, nanos = "-", -1*secs, -1*nanos - } - x := fmt.Sprintf("%s%d.%09d", sign, secs, nanos) - x = strings.TrimSuffix(x, "000") - x = strings.TrimSuffix(x, "000") - x = strings.TrimSuffix(x, ".000") - return append(b, x+"s"...) - - case genid.BoolValue_message_fullname, - genid.Int32Value_message_fullname, - genid.Int64Value_message_fullname, - genid.UInt32Value_message_fullname, - genid.UInt64Value_message_fullname, - genid.FloatValue_message_fullname, - genid.DoubleValue_message_fullname, - genid.StringValue_message_fullname, - genid.BytesValue_message_fullname: - fd := fds.ByNumber(genid.WrapperValue_Value_field_number) - return appendValue(b, m.Get(fd), fd) - } - - return nil -} - -func appendUnknown(b []byte, raw protoreflect.RawFields) []byte { - rs := make(map[protoreflect.FieldNumber][]protoreflect.RawFields) - for len(raw) > 0 { - num, _, n := protowire.ConsumeField(raw) - rs[num] = append(rs[num], raw[:n]) - raw = raw[n:] - } - - var ns []protoreflect.FieldNumber - for n := range rs { - ns = append(ns, n) - } - sort.Slice(ns, func(i, j int) bool { return ns[i] < ns[j] }) - - for _, n := range ns { - var leftBracket, rightBracket string - if len(rs[n]) > 1 { - leftBracket, rightBracket = "[", "]" - } - - b = strconv.AppendInt(b, int64(n), 10) - b = append(b, ':') - b = append(b, leftBracket...) - for _, r := range rs[n] { - num, typ, n := protowire.ConsumeTag(r) - r = r[n:] - switch typ { - case protowire.VarintType: - v, _ := protowire.ConsumeVarint(r) - b = strconv.AppendInt(b, int64(v), 10) - case protowire.Fixed32Type: - v, _ := protowire.ConsumeFixed32(r) - b = append(b, fmt.Sprintf("0x%08x", v)...) - case protowire.Fixed64Type: - v, _ := protowire.ConsumeFixed64(r) - b = append(b, fmt.Sprintf("0x%016x", v)...) - case protowire.BytesType: - v, _ := protowire.ConsumeBytes(r) - b = strconv.AppendQuote(b, string(v)) - case protowire.StartGroupType: - v, _ := protowire.ConsumeGroup(num, r) - b = append(b, '{') - b = appendUnknown(b, v) - b = bytes.TrimRight(b, delim()) - b = append(b, '}') - default: - panic(fmt.Sprintf("invalid type: %v", typ)) - } - b = append(b, delim()...) - } - b = bytes.TrimRight(b, delim()) - b = append(b, rightBracket...) - b = append(b, delim()...) - } - return b -} - -func appendList(b []byte, v protoreflect.List, fd protoreflect.FieldDescriptor) []byte { - b = append(b, '[') - for i := 0; i < v.Len(); i++ { - b = appendValue(b, v.Get(i), fd) - b = append(b, delim()...) - } - b = bytes.TrimRight(b, delim()) - b = append(b, ']') - return b -} - -func appendMap(b []byte, v protoreflect.Map, fd protoreflect.FieldDescriptor) []byte { - b = append(b, '{') - order.RangeEntries(v, order.GenericKeyOrder, func(k protoreflect.MapKey, v protoreflect.Value) bool { - b = appendValue(b, k.Value(), fd.MapKey()) - b = append(b, ':') - b = appendValue(b, v, fd.MapValue()) - b = append(b, delim()...) - return true - }) - b = bytes.TrimRight(b, delim()) - b = append(b, '}') - return b -} - -func delim() string { - // Deliberately introduce instability into the message string to - // discourage users from depending on it. - if detrand.Bool() { - return " " - } - return ", " -} diff --git a/vendor/google.golang.org/protobuf/reflect/protopath/path.go b/vendor/google.golang.org/protobuf/reflect/protopath/path.go deleted file mode 100644 index fffac00ebce..00000000000 --- a/vendor/google.golang.org/protobuf/reflect/protopath/path.go +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2020 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package protopath provides functionality for -// representing a sequence of protobuf reflection operations on a message. -package protopath - -import ( - "fmt" - - "google.golang.org/protobuf/internal/msgfmt" - "google.golang.org/protobuf/reflect/protoreflect" -) - -// NOTE: The Path and Values are separate types here since there are use cases -// where you would like to "address" some value in a message with just the path -// and don't have the value information available. -// -// This is different from how github.com/google/go-cmp/cmp.Path operates, -// which combines both path and value information together. -// Since the cmp package itself is the only one ever constructing a cmp.Path, -// it will always have the value available. - -// Path is a sequence of protobuf reflection steps applied to some root -// protobuf message value to arrive at the current value. -// The first step must be a [Root] step. -type Path []Step - -// TODO: Provide a Parse function that parses something similar to or -// perhaps identical to the output of Path.String. - -// Index returns the ith step in the path and supports negative indexing. -// A negative index starts counting from the tail of the Path such that -1 -// refers to the last step, -2 refers to the second-to-last step, and so on. -// It returns a zero Step value if the index is out-of-bounds. -func (p Path) Index(i int) Step { - if i < 0 { - i = len(p) + i - } - if i < 0 || i >= len(p) { - return Step{} - } - return p[i] -} - -// String returns a structured representation of the path -// by concatenating the string representation of every path step. -func (p Path) String() string { - var b []byte - for _, s := range p { - b = s.appendString(b) - } - return string(b) -} - -// Values is a Path paired with a sequence of values at each step. -// The lengths of [Values.Path] and [Values.Values] must be identical. -// The first step must be a [Root] step and -// the first value must be a concrete message value. -type Values struct { - Path Path - Values []protoreflect.Value -} - -// Len reports the length of the path and values. -// If the path and values have differing length, it returns the minimum length. -func (p Values) Len() int { - n := len(p.Path) - if n > len(p.Values) { - n = len(p.Values) - } - return n -} - -// Index returns the ith step and value and supports negative indexing. -// A negative index starts counting from the tail of the Values such that -1 -// refers to the last pair, -2 refers to the second-to-last pair, and so on. -func (p Values) Index(i int) (out struct { - Step Step - Value protoreflect.Value -}) { - // NOTE: This returns a single struct instead of two return values so that - // callers can make use of the the value in an expression: - // vs.Index(i).Value.Interface() - n := p.Len() - if i < 0 { - i = n + i - } - if i < 0 || i >= n { - return out - } - out.Step = p.Path[i] - out.Value = p.Values[i] - return out -} - -// String returns a humanly readable representation of the path and last value. -// Do not depend on the output being stable. -// -// For example: -// -// (path.to.MyMessage).list_field[5].map_field["hello"] = {hello: "world"} -func (p Values) String() string { - n := p.Len() - if n == 0 { - return "" - } - - // Determine the field descriptor associated with the last step. - var fd protoreflect.FieldDescriptor - last := p.Index(-1) - switch last.Step.kind { - case FieldAccessStep: - fd = last.Step.FieldDescriptor() - case MapIndexStep, ListIndexStep: - fd = p.Index(-2).Step.FieldDescriptor() - } - - // Format the full path with the last value. - return fmt.Sprintf("%v = %v", p.Path[:n], msgfmt.FormatValue(last.Value, fd)) -} diff --git a/vendor/google.golang.org/protobuf/reflect/protopath/step.go b/vendor/google.golang.org/protobuf/reflect/protopath/step.go deleted file mode 100644 index 95ae85c5b1d..00000000000 --- a/vendor/google.golang.org/protobuf/reflect/protopath/step.go +++ /dev/null @@ -1,241 +0,0 @@ -// Copyright 2020 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package protopath - -import ( - "fmt" - "strconv" - "strings" - - "google.golang.org/protobuf/internal/encoding/text" - "google.golang.org/protobuf/reflect/protoreflect" -) - -// StepKind identifies the kind of step operation. -// Each kind of step corresponds with some protobuf reflection operation. -type StepKind int - -const ( - invalidStep StepKind = iota - // RootStep identifies a step as the Root step operation. - RootStep - // FieldAccessStep identifies a step as the FieldAccess step operation. - FieldAccessStep - // UnknownAccessStep identifies a step as the UnknownAccess step operation. - UnknownAccessStep - // ListIndexStep identifies a step as the ListIndex step operation. - ListIndexStep - // MapIndexStep identifies a step as the MapIndex step operation. - MapIndexStep - // AnyExpandStep identifies a step as the AnyExpand step operation. - AnyExpandStep -) - -func (k StepKind) String() string { - switch k { - case invalidStep: - return "" - case RootStep: - return "Root" - case FieldAccessStep: - return "FieldAccess" - case UnknownAccessStep: - return "UnknownAccess" - case ListIndexStep: - return "ListIndex" - case MapIndexStep: - return "MapIndex" - case AnyExpandStep: - return "AnyExpand" - default: - return fmt.Sprintf("", k) - } -} - -// Step is a union where only one step operation may be specified at a time. -// The different kinds of steps are specified by the constants defined for -// the StepKind type. -type Step struct { - kind StepKind - desc protoreflect.Descriptor - key protoreflect.Value -} - -// Root indicates the root message that a path is relative to. -// It should always (and only ever) be the first step in a path. -func Root(md protoreflect.MessageDescriptor) Step { - if md == nil { - panic("nil message descriptor") - } - return Step{kind: RootStep, desc: md} -} - -// FieldAccess describes access of a field within a message. -// Extension field accesses are also represented using a FieldAccess and -// must be provided with a protoreflect.FieldDescriptor -// -// Within the context of Values, -// the type of the previous step value is always a message, and -// the type of the current step value is determined by the field descriptor. -func FieldAccess(fd protoreflect.FieldDescriptor) Step { - if fd == nil { - panic("nil field descriptor") - } else if _, ok := fd.(protoreflect.ExtensionTypeDescriptor); !ok && fd.IsExtension() { - panic(fmt.Sprintf("extension field %q must implement protoreflect.ExtensionTypeDescriptor", fd.FullName())) - } - return Step{kind: FieldAccessStep, desc: fd} -} - -// UnknownAccess describes access to the unknown fields within a message. -// -// Within the context of Values, -// the type of the previous step value is always a message, and -// the type of the current step value is always a bytes type. -func UnknownAccess() Step { - return Step{kind: UnknownAccessStep} -} - -// ListIndex describes index of an element within a list. -// -// Within the context of Values, -// the type of the previous, previous step value is always a message, -// the type of the previous step value is always a list, and -// the type of the current step value is determined by the field descriptor. -func ListIndex(i int) Step { - if i < 0 { - panic(fmt.Sprintf("invalid list index: %v", i)) - } - return Step{kind: ListIndexStep, key: protoreflect.ValueOfInt64(int64(i))} -} - -// MapIndex describes index of an entry within a map. -// The key type is determined by field descriptor that the map belongs to. -// -// Within the context of Values, -// the type of the previous previous step value is always a message, -// the type of the previous step value is always a map, and -// the type of the current step value is determined by the field descriptor. -func MapIndex(k protoreflect.MapKey) Step { - if !k.IsValid() { - panic("invalid map index") - } - return Step{kind: MapIndexStep, key: k.Value()} -} - -// AnyExpand describes expansion of a google.protobuf.Any message into -// a structured representation of the underlying message. -// -// Within the context of Values, -// the type of the previous step value is always a google.protobuf.Any message, and -// the type of the current step value is always a message. -func AnyExpand(md protoreflect.MessageDescriptor) Step { - if md == nil { - panic("nil message descriptor") - } - return Step{kind: AnyExpandStep, desc: md} -} - -// MessageDescriptor returns the message descriptor for Root or AnyExpand steps, -// otherwise it returns nil. -func (s Step) MessageDescriptor() protoreflect.MessageDescriptor { - switch s.kind { - case RootStep, AnyExpandStep: - return s.desc.(protoreflect.MessageDescriptor) - default: - return nil - } -} - -// FieldDescriptor returns the field descriptor for FieldAccess steps, -// otherwise it returns nil. -func (s Step) FieldDescriptor() protoreflect.FieldDescriptor { - switch s.kind { - case FieldAccessStep: - return s.desc.(protoreflect.FieldDescriptor) - default: - return nil - } -} - -// ListIndex returns the list index for ListIndex steps, -// otherwise it returns 0. -func (s Step) ListIndex() int { - switch s.kind { - case ListIndexStep: - return int(s.key.Int()) - default: - return 0 - } -} - -// MapIndex returns the map key for MapIndex steps, -// otherwise it returns an invalid map key. -func (s Step) MapIndex() protoreflect.MapKey { - switch s.kind { - case MapIndexStep: - return s.key.MapKey() - default: - return protoreflect.MapKey{} - } -} - -// Kind reports which kind of step this is. -func (s Step) Kind() StepKind { - return s.kind -} - -func (s Step) String() string { - return string(s.appendString(nil)) -} - -func (s Step) appendString(b []byte) []byte { - switch s.kind { - case RootStep: - b = append(b, '(') - b = append(b, s.desc.FullName()...) - b = append(b, ')') - case FieldAccessStep: - b = append(b, '.') - if fd := s.desc.(protoreflect.FieldDescriptor); fd.IsExtension() { - b = append(b, '(') - b = append(b, strings.Trim(fd.TextName(), "[]")...) - b = append(b, ')') - } else { - b = append(b, fd.TextName()...) - } - case UnknownAccessStep: - b = append(b, '.') - b = append(b, '?') - case ListIndexStep: - b = append(b, '[') - b = strconv.AppendInt(b, s.key.Int(), 10) - b = append(b, ']') - case MapIndexStep: - b = append(b, '[') - switch k := s.key.Interface().(type) { - case bool: - b = strconv.AppendBool(b, bool(k)) // e.g., "true" or "false" - case int32: - b = strconv.AppendInt(b, int64(k), 10) // e.g., "-32" - case int64: - b = strconv.AppendInt(b, int64(k), 10) // e.g., "-64" - case uint32: - b = strconv.AppendUint(b, uint64(k), 10) // e.g., "32" - case uint64: - b = strconv.AppendUint(b, uint64(k), 10) // e.g., "64" - case string: - b = text.AppendString(b, k) // e.g., `"hello, world"` - } - b = append(b, ']') - case AnyExpandStep: - b = append(b, '.') - b = append(b, '(') - b = append(b, s.desc.FullName()...) - b = append(b, ')') - default: - b = append(b, ""...) - } - return b -} diff --git a/vendor/google.golang.org/protobuf/reflect/protorange/range.go b/vendor/google.golang.org/protobuf/reflect/protorange/range.go deleted file mode 100644 index 7a032758b51..00000000000 --- a/vendor/google.golang.org/protobuf/reflect/protorange/range.go +++ /dev/null @@ -1,316 +0,0 @@ -// Copyright 2020 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package protorange provides functionality to traverse a message value. -package protorange - -import ( - "bytes" - "errors" - - "google.golang.org/protobuf/internal/genid" - "google.golang.org/protobuf/internal/order" - "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/reflect/protopath" - "google.golang.org/protobuf/reflect/protoreflect" - "google.golang.org/protobuf/reflect/protoregistry" -) - -var ( - // Break breaks traversal of children in the current value. - // It has no effect when traversing values that are not composite types - // (e.g., messages, lists, and maps). - Break = errors.New("break traversal of children in current value") - - // Terminate terminates the entire range operation. - // All necessary Pop operations continue to be called. - Terminate = errors.New("terminate range operation") -) - -// Range performs a depth-first traversal over reachable values in a message. -// -// See [Options.Range] for details. -func Range(m protoreflect.Message, f func(protopath.Values) error) error { - return Options{}.Range(m, f, nil) -} - -// Options configures traversal of a message value tree. -type Options struct { - // Stable specifies whether to visit message fields and map entries - // in a stable ordering. If false, then the ordering is undefined and - // may be non-deterministic. - // - // Message fields are visited in ascending order by field number. - // Map entries are visited in ascending order, where - // boolean keys are ordered such that false sorts before true, - // numeric keys are ordered based on the numeric value, and - // string keys are lexicographically ordered by Unicode codepoints. - Stable bool - - // Resolver is used for looking up types when expanding google.protobuf.Any - // messages. If nil, this defaults to using protoregistry.GlobalTypes. - // To prevent expansion of Any messages, pass an empty protoregistry.Types: - // - // Options{Resolver: (*protoregistry.Types)(nil)} - // - Resolver interface { - protoregistry.ExtensionTypeResolver - protoregistry.MessageTypeResolver - } -} - -// Range performs a depth-first traversal over reachable values in a message. -// The first push and the last pop are to push/pop a [protopath.Root] step. -// If push or pop return any non-nil error (other than [Break] or [Terminate]), -// it terminates the traversal and is returned by Range. -// -// The rules for traversing a message is as follows: -// -// - For messages, iterate over every populated known and extension field. -// Each field is preceded by a push of a [protopath.FieldAccess] step, -// followed by recursive application of the rules on the field value, -// and succeeded by a pop of that step. -// If the message has unknown fields, then push an [protopath.UnknownAccess] step -// followed immediately by pop of that step. -// -// - As an exception to the above rule, if the current message is a -// google.protobuf.Any message, expand the underlying message (if resolvable). -// The expanded message is preceded by a push of a [protopath.AnyExpand] step, -// followed by recursive application of the rules on the underlying message, -// and succeeded by a pop of that step. Mutations to the expanded message -// are written back to the Any message when popping back out. -// -// - For lists, iterate over every element. Each element is preceded by a push -// of a [protopath.ListIndex] step, followed by recursive application of the rules -// on the list element, and succeeded by a pop of that step. -// -// - For maps, iterate over every entry. Each entry is preceded by a push -// of a [protopath.MapIndex] step, followed by recursive application of the rules -// on the map entry value, and succeeded by a pop of that step. -// -// Mutations should only be made to the last value, otherwise the effects on -// traversal will be undefined. If the mutation is made to the last value -// during to a push, then the effects of the mutation will affect traversal. -// For example, if the last value is currently a message, and the push function -// populates a few fields in that message, then the newly modified fields -// will be traversed. -// -// The [protopath.Values] provided to push functions is only valid until the -// corresponding pop call and the values provided to a pop call is only valid -// for the duration of the pop call itself. -func (o Options) Range(m protoreflect.Message, push, pop func(protopath.Values) error) error { - var err error - p := new(protopath.Values) - if o.Resolver == nil { - o.Resolver = protoregistry.GlobalTypes - } - - pushStep(p, protopath.Root(m.Descriptor()), protoreflect.ValueOfMessage(m)) - if push != nil { - err = amendError(err, push(*p)) - } - if err == nil { - err = o.rangeMessage(p, m, push, pop) - } - if pop != nil { - err = amendError(err, pop(*p)) - } - popStep(p) - - if err == Break || err == Terminate { - err = nil - } - return err -} - -func (o Options) rangeMessage(p *protopath.Values, m protoreflect.Message, push, pop func(protopath.Values) error) (err error) { - if ok, err := o.rangeAnyMessage(p, m, push, pop); ok { - return err - } - - fieldOrder := order.AnyFieldOrder - if o.Stable { - fieldOrder = order.NumberFieldOrder - } - order.RangeFields(m, fieldOrder, func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool { - pushStep(p, protopath.FieldAccess(fd), v) - if push != nil { - err = amendError(err, push(*p)) - } - if err == nil { - switch { - case fd.IsMap(): - err = o.rangeMap(p, fd, v.Map(), push, pop) - case fd.IsList(): - err = o.rangeList(p, fd, v.List(), push, pop) - case fd.Message() != nil: - err = o.rangeMessage(p, v.Message(), push, pop) - } - } - if pop != nil { - err = amendError(err, pop(*p)) - } - popStep(p) - return err == nil - }) - - if b := m.GetUnknown(); len(b) > 0 && err == nil { - pushStep(p, protopath.UnknownAccess(), protoreflect.ValueOfBytes(b)) - if push != nil { - err = amendError(err, push(*p)) - } - if pop != nil { - err = amendError(err, pop(*p)) - } - popStep(p) - } - - if err == Break { - err = nil - } - return err -} - -func (o Options) rangeAnyMessage(p *protopath.Values, m protoreflect.Message, push, pop func(protopath.Values) error) (ok bool, err error) { - md := m.Descriptor() - if md.FullName() != "google.protobuf.Any" { - return false, nil - } - - fds := md.Fields() - url := m.Get(fds.ByNumber(genid.Any_TypeUrl_field_number)).String() - val := m.Get(fds.ByNumber(genid.Any_Value_field_number)).Bytes() - mt, errFind := o.Resolver.FindMessageByURL(url) - if errFind != nil { - return false, nil - } - - // Unmarshal the raw encoded message value into a structured message value. - m2 := mt.New() - errUnmarshal := proto.UnmarshalOptions{ - Merge: true, - AllowPartial: true, - Resolver: o.Resolver, - }.Unmarshal(val, m2.Interface()) - if errUnmarshal != nil { - // If the the underlying message cannot be unmarshaled, - // then just treat this as an normal message type. - return false, nil - } - - // Marshal Any before ranging to detect possible mutations. - b1, errMarshal := proto.MarshalOptions{ - AllowPartial: true, - Deterministic: true, - }.Marshal(m2.Interface()) - if errMarshal != nil { - return true, errMarshal - } - - pushStep(p, protopath.AnyExpand(m2.Descriptor()), protoreflect.ValueOfMessage(m2)) - if push != nil { - err = amendError(err, push(*p)) - } - if err == nil { - err = o.rangeMessage(p, m2, push, pop) - } - if pop != nil { - err = amendError(err, pop(*p)) - } - popStep(p) - - // Marshal Any after ranging to detect possible mutations. - b2, errMarshal := proto.MarshalOptions{ - AllowPartial: true, - Deterministic: true, - }.Marshal(m2.Interface()) - if errMarshal != nil { - return true, errMarshal - } - - // Mutations detected, write the new sequence of bytes to the Any message. - if !bytes.Equal(b1, b2) { - m.Set(fds.ByNumber(genid.Any_Value_field_number), protoreflect.ValueOfBytes(b2)) - } - - if err == Break { - err = nil - } - return true, err -} - -func (o Options) rangeList(p *protopath.Values, fd protoreflect.FieldDescriptor, ls protoreflect.List, push, pop func(protopath.Values) error) (err error) { - for i := 0; i < ls.Len() && err == nil; i++ { - v := ls.Get(i) - pushStep(p, protopath.ListIndex(i), v) - if push != nil { - err = amendError(err, push(*p)) - } - if err == nil && fd.Message() != nil { - err = o.rangeMessage(p, v.Message(), push, pop) - } - if pop != nil { - err = amendError(err, pop(*p)) - } - popStep(p) - } - - if err == Break { - err = nil - } - return err -} - -func (o Options) rangeMap(p *protopath.Values, fd protoreflect.FieldDescriptor, ms protoreflect.Map, push, pop func(protopath.Values) error) (err error) { - keyOrder := order.AnyKeyOrder - if o.Stable { - keyOrder = order.GenericKeyOrder - } - order.RangeEntries(ms, keyOrder, func(k protoreflect.MapKey, v protoreflect.Value) bool { - pushStep(p, protopath.MapIndex(k), v) - if push != nil { - err = amendError(err, push(*p)) - } - if err == nil && fd.MapValue().Message() != nil { - err = o.rangeMessage(p, v.Message(), push, pop) - } - if pop != nil { - err = amendError(err, pop(*p)) - } - popStep(p) - return err == nil - }) - - if err == Break { - err = nil - } - return err -} - -func pushStep(p *protopath.Values, s protopath.Step, v protoreflect.Value) { - p.Path = append(p.Path, s) - p.Values = append(p.Values, v) -} - -func popStep(p *protopath.Values) { - p.Path = p.Path[:len(p.Path)-1] - p.Values = p.Values[:len(p.Values)-1] -} - -// amendError amends the previous error with the current error if it is -// considered more serious. The precedence order for errors is: -// -// nil < Break < Terminate < previous non-nil < current non-nil -func amendError(prev, curr error) error { - switch { - case curr == nil: - return prev - case curr == Break && prev != nil: - return prev - case curr == Terminate && prev != nil && prev != Break: - return prev - default: - return curr - } -} diff --git a/vendor/google.golang.org/protobuf/types/dynamicpb/dynamic.go b/vendor/google.golang.org/protobuf/types/dynamicpb/dynamic.go deleted file mode 100644 index 39b024b46b8..00000000000 --- a/vendor/google.golang.org/protobuf/types/dynamicpb/dynamic.go +++ /dev/null @@ -1,718 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package dynamicpb creates protocol buffer messages using runtime type information. -package dynamicpb - -import ( - "math" - - "google.golang.org/protobuf/internal/errors" - "google.golang.org/protobuf/reflect/protoreflect" - "google.golang.org/protobuf/runtime/protoiface" - "google.golang.org/protobuf/runtime/protoimpl" -) - -// enum is a dynamic protoreflect.Enum. -type enum struct { - num protoreflect.EnumNumber - typ protoreflect.EnumType -} - -func (e enum) Descriptor() protoreflect.EnumDescriptor { return e.typ.Descriptor() } -func (e enum) Type() protoreflect.EnumType { return e.typ } -func (e enum) Number() protoreflect.EnumNumber { return e.num } - -// enumType is a dynamic protoreflect.EnumType. -type enumType struct { - desc protoreflect.EnumDescriptor -} - -// NewEnumType creates a new EnumType with the provided descriptor. -// -// EnumTypes created by this package are equal if their descriptors are equal. -// That is, if ed1 == ed2, then NewEnumType(ed1) == NewEnumType(ed2). -// -// Enum values created by the EnumType are equal if their numbers are equal. -func NewEnumType(desc protoreflect.EnumDescriptor) protoreflect.EnumType { - return enumType{desc} -} - -func (et enumType) New(n protoreflect.EnumNumber) protoreflect.Enum { return enum{n, et} } -func (et enumType) Descriptor() protoreflect.EnumDescriptor { return et.desc } - -// extensionType is a dynamic protoreflect.ExtensionType. -type extensionType struct { - desc extensionTypeDescriptor -} - -// A Message is a dynamically constructed protocol buffer message. -// -// Message implements the [google.golang.org/protobuf/proto.Message] interface, -// and may be used with all standard proto package functions -// such as Marshal, Unmarshal, and so forth. -// -// Message also implements the [protoreflect.Message] interface. -// See the [protoreflect] package documentation for that interface for how to -// get and set fields and otherwise interact with the contents of a Message. -// -// Reflection API functions which construct messages, such as NewField, -// return new dynamic messages of the appropriate type. Functions which take -// messages, such as Set for a message-value field, will accept any message -// with a compatible type. -// -// Operations which modify a Message are not safe for concurrent use. -type Message struct { - typ messageType - known map[protoreflect.FieldNumber]protoreflect.Value - ext map[protoreflect.FieldNumber]protoreflect.FieldDescriptor - unknown protoreflect.RawFields -} - -var ( - _ protoreflect.Message = (*Message)(nil) - _ protoreflect.ProtoMessage = (*Message)(nil) - _ protoiface.MessageV1 = (*Message)(nil) -) - -// NewMessage creates a new message with the provided descriptor. -func NewMessage(desc protoreflect.MessageDescriptor) *Message { - return &Message{ - typ: messageType{desc}, - known: make(map[protoreflect.FieldNumber]protoreflect.Value), - ext: make(map[protoreflect.FieldNumber]protoreflect.FieldDescriptor), - } -} - -// ProtoMessage implements the legacy message interface. -func (m *Message) ProtoMessage() {} - -// ProtoReflect implements the [protoreflect.ProtoMessage] interface. -func (m *Message) ProtoReflect() protoreflect.Message { - return m -} - -// String returns a string representation of a message. -func (m *Message) String() string { - return protoimpl.X.MessageStringOf(m) -} - -// Reset clears the message to be empty, but preserves the dynamic message type. -func (m *Message) Reset() { - m.known = make(map[protoreflect.FieldNumber]protoreflect.Value) - m.ext = make(map[protoreflect.FieldNumber]protoreflect.FieldDescriptor) - m.unknown = nil -} - -// Descriptor returns the message descriptor. -func (m *Message) Descriptor() protoreflect.MessageDescriptor { - return m.typ.desc -} - -// Type returns the message type. -func (m *Message) Type() protoreflect.MessageType { - return m.typ -} - -// New returns a newly allocated empty message with the same descriptor. -// See [protoreflect.Message] for details. -func (m *Message) New() protoreflect.Message { - return m.Type().New() -} - -// Interface returns the message. -// See [protoreflect.Message] for details. -func (m *Message) Interface() protoreflect.ProtoMessage { - return m -} - -// ProtoMethods is an internal detail of the [protoreflect.Message] interface. -// Users should never call this directly. -func (m *Message) ProtoMethods() *protoiface.Methods { - return nil -} - -// Range visits every populated field in undefined order. -// See [protoreflect.Message] for details. -func (m *Message) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { - for num, v := range m.known { - fd := m.ext[num] - if fd == nil { - fd = m.Descriptor().Fields().ByNumber(num) - } - if !isSet(fd, v) { - continue - } - if !f(fd, v) { - return - } - } -} - -// Has reports whether a field is populated. -// See [protoreflect.Message] for details. -func (m *Message) Has(fd protoreflect.FieldDescriptor) bool { - m.checkField(fd) - if fd.IsExtension() && m.ext[fd.Number()] != fd { - return false - } - v, ok := m.known[fd.Number()] - if !ok { - return false - } - return isSet(fd, v) -} - -// Clear clears a field. -// See [protoreflect.Message] for details. -func (m *Message) Clear(fd protoreflect.FieldDescriptor) { - m.checkField(fd) - num := fd.Number() - delete(m.known, num) - delete(m.ext, num) -} - -// Get returns the value of a field. -// See [protoreflect.Message] for details. -func (m *Message) Get(fd protoreflect.FieldDescriptor) protoreflect.Value { - m.checkField(fd) - num := fd.Number() - if fd.IsExtension() { - if fd != m.ext[num] { - return fd.(protoreflect.ExtensionTypeDescriptor).Type().Zero() - } - return m.known[num] - } - if v, ok := m.known[num]; ok { - switch { - case fd.IsMap(): - if v.Map().Len() > 0 { - return v - } - case fd.IsList(): - if v.List().Len() > 0 { - return v - } - default: - return v - } - } - switch { - case fd.IsMap(): - return protoreflect.ValueOfMap(&dynamicMap{desc: fd}) - case fd.IsList(): - return protoreflect.ValueOfList(emptyList{desc: fd}) - case fd.Message() != nil: - return protoreflect.ValueOfMessage(&Message{typ: messageType{fd.Message()}}) - case fd.Kind() == protoreflect.BytesKind: - return protoreflect.ValueOfBytes(append([]byte(nil), fd.Default().Bytes()...)) - default: - return fd.Default() - } -} - -// Mutable returns a mutable reference to a repeated, map, or message field. -// See [protoreflect.Message] for details. -func (m *Message) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { - m.checkField(fd) - if !fd.IsMap() && !fd.IsList() && fd.Message() == nil { - panic(errors.New("%v: getting mutable reference to non-composite type", fd.FullName())) - } - if m.known == nil { - panic(errors.New("%v: modification of read-only message", fd.FullName())) - } - num := fd.Number() - if fd.IsExtension() { - if fd != m.ext[num] { - m.ext[num] = fd - m.known[num] = fd.(protoreflect.ExtensionTypeDescriptor).Type().New() - } - return m.known[num] - } - if v, ok := m.known[num]; ok { - return v - } - m.clearOtherOneofFields(fd) - m.known[num] = m.NewField(fd) - if fd.IsExtension() { - m.ext[num] = fd - } - return m.known[num] -} - -// Set stores a value in a field. -// See [protoreflect.Message] for details. -func (m *Message) Set(fd protoreflect.FieldDescriptor, v protoreflect.Value) { - m.checkField(fd) - if m.known == nil { - panic(errors.New("%v: modification of read-only message", fd.FullName())) - } - if fd.IsExtension() { - isValid := true - switch { - case !fd.(protoreflect.ExtensionTypeDescriptor).Type().IsValidValue(v): - isValid = false - case fd.IsList(): - isValid = v.List().IsValid() - case fd.IsMap(): - isValid = v.Map().IsValid() - case fd.Message() != nil: - isValid = v.Message().IsValid() - } - if !isValid { - panic(errors.New("%v: assigning invalid type %T", fd.FullName(), v.Interface())) - } - m.ext[fd.Number()] = fd - } else { - typecheck(fd, v) - } - m.clearOtherOneofFields(fd) - m.known[fd.Number()] = v -} - -func (m *Message) clearOtherOneofFields(fd protoreflect.FieldDescriptor) { - od := fd.ContainingOneof() - if od == nil { - return - } - num := fd.Number() - for i := 0; i < od.Fields().Len(); i++ { - if n := od.Fields().Get(i).Number(); n != num { - delete(m.known, n) - } - } -} - -// NewField returns a new value for assignable to the field of a given descriptor. -// See [protoreflect.Message] for details. -func (m *Message) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { - m.checkField(fd) - switch { - case fd.IsExtension(): - return fd.(protoreflect.ExtensionTypeDescriptor).Type().New() - case fd.IsMap(): - return protoreflect.ValueOfMap(&dynamicMap{ - desc: fd, - mapv: make(map[interface{}]protoreflect.Value), - }) - case fd.IsList(): - return protoreflect.ValueOfList(&dynamicList{desc: fd}) - case fd.Message() != nil: - return protoreflect.ValueOfMessage(NewMessage(fd.Message()).ProtoReflect()) - default: - return fd.Default() - } -} - -// WhichOneof reports which field in a oneof is populated, returning nil if none are populated. -// See [protoreflect.Message] for details. -func (m *Message) WhichOneof(od protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { - for i := 0; i < od.Fields().Len(); i++ { - fd := od.Fields().Get(i) - if m.Has(fd) { - return fd - } - } - return nil -} - -// GetUnknown returns the raw unknown fields. -// See [protoreflect.Message] for details. -func (m *Message) GetUnknown() protoreflect.RawFields { - return m.unknown -} - -// SetUnknown sets the raw unknown fields. -// See [protoreflect.Message] for details. -func (m *Message) SetUnknown(r protoreflect.RawFields) { - if m.known == nil { - panic(errors.New("%v: modification of read-only message", m.typ.desc.FullName())) - } - m.unknown = r -} - -// IsValid reports whether the message is valid. -// See [protoreflect.Message] for details. -func (m *Message) IsValid() bool { - return m.known != nil -} - -func (m *Message) checkField(fd protoreflect.FieldDescriptor) { - if fd.IsExtension() && fd.ContainingMessage().FullName() == m.Descriptor().FullName() { - if _, ok := fd.(protoreflect.ExtensionTypeDescriptor); !ok { - panic(errors.New("%v: extension field descriptor does not implement ExtensionTypeDescriptor", fd.FullName())) - } - return - } - if fd.Parent() == m.Descriptor() { - return - } - fields := m.Descriptor().Fields() - index := fd.Index() - if index >= fields.Len() || fields.Get(index) != fd { - panic(errors.New("%v: field descriptor does not belong to this message", fd.FullName())) - } -} - -type messageType struct { - desc protoreflect.MessageDescriptor -} - -// NewMessageType creates a new MessageType with the provided descriptor. -// -// MessageTypes created by this package are equal if their descriptors are equal. -// That is, if md1 == md2, then NewMessageType(md1) == NewMessageType(md2). -func NewMessageType(desc protoreflect.MessageDescriptor) protoreflect.MessageType { - return messageType{desc} -} - -func (mt messageType) New() protoreflect.Message { return NewMessage(mt.desc) } -func (mt messageType) Zero() protoreflect.Message { return &Message{typ: messageType{mt.desc}} } -func (mt messageType) Descriptor() protoreflect.MessageDescriptor { return mt.desc } -func (mt messageType) Enum(i int) protoreflect.EnumType { - if ed := mt.desc.Fields().Get(i).Enum(); ed != nil { - return NewEnumType(ed) - } - return nil -} -func (mt messageType) Message(i int) protoreflect.MessageType { - if md := mt.desc.Fields().Get(i).Message(); md != nil { - return NewMessageType(md) - } - return nil -} - -type emptyList struct { - desc protoreflect.FieldDescriptor -} - -func (x emptyList) Len() int { return 0 } -func (x emptyList) Get(n int) protoreflect.Value { panic(errors.New("out of range")) } -func (x emptyList) Set(n int, v protoreflect.Value) { - panic(errors.New("modification of immutable list")) -} -func (x emptyList) Append(v protoreflect.Value) { panic(errors.New("modification of immutable list")) } -func (x emptyList) AppendMutable() protoreflect.Value { - panic(errors.New("modification of immutable list")) -} -func (x emptyList) Truncate(n int) { panic(errors.New("modification of immutable list")) } -func (x emptyList) NewElement() protoreflect.Value { return newListEntry(x.desc) } -func (x emptyList) IsValid() bool { return false } - -type dynamicList struct { - desc protoreflect.FieldDescriptor - list []protoreflect.Value -} - -func (x *dynamicList) Len() int { - return len(x.list) -} - -func (x *dynamicList) Get(n int) protoreflect.Value { - return x.list[n] -} - -func (x *dynamicList) Set(n int, v protoreflect.Value) { - typecheckSingular(x.desc, v) - x.list[n] = v -} - -func (x *dynamicList) Append(v protoreflect.Value) { - typecheckSingular(x.desc, v) - x.list = append(x.list, v) -} - -func (x *dynamicList) AppendMutable() protoreflect.Value { - if x.desc.Message() == nil { - panic(errors.New("%v: invalid AppendMutable on list with non-message type", x.desc.FullName())) - } - v := x.NewElement() - x.Append(v) - return v -} - -func (x *dynamicList) Truncate(n int) { - // Zero truncated elements to avoid keeping data live. - for i := n; i < len(x.list); i++ { - x.list[i] = protoreflect.Value{} - } - x.list = x.list[:n] -} - -func (x *dynamicList) NewElement() protoreflect.Value { - return newListEntry(x.desc) -} - -func (x *dynamicList) IsValid() bool { - return true -} - -type dynamicMap struct { - desc protoreflect.FieldDescriptor - mapv map[interface{}]protoreflect.Value -} - -func (x *dynamicMap) Get(k protoreflect.MapKey) protoreflect.Value { return x.mapv[k.Interface()] } -func (x *dynamicMap) Set(k protoreflect.MapKey, v protoreflect.Value) { - typecheckSingular(x.desc.MapKey(), k.Value()) - typecheckSingular(x.desc.MapValue(), v) - x.mapv[k.Interface()] = v -} -func (x *dynamicMap) Has(k protoreflect.MapKey) bool { return x.Get(k).IsValid() } -func (x *dynamicMap) Clear(k protoreflect.MapKey) { delete(x.mapv, k.Interface()) } -func (x *dynamicMap) Mutable(k protoreflect.MapKey) protoreflect.Value { - if x.desc.MapValue().Message() == nil { - panic(errors.New("%v: invalid Mutable on map with non-message value type", x.desc.FullName())) - } - v := x.Get(k) - if !v.IsValid() { - v = x.NewValue() - x.Set(k, v) - } - return v -} -func (x *dynamicMap) Len() int { return len(x.mapv) } -func (x *dynamicMap) NewValue() protoreflect.Value { - if md := x.desc.MapValue().Message(); md != nil { - return protoreflect.ValueOfMessage(NewMessage(md).ProtoReflect()) - } - return x.desc.MapValue().Default() -} -func (x *dynamicMap) IsValid() bool { - return x.mapv != nil -} - -func (x *dynamicMap) Range(f func(protoreflect.MapKey, protoreflect.Value) bool) { - for k, v := range x.mapv { - if !f(protoreflect.ValueOf(k).MapKey(), v) { - return - } - } -} - -func isSet(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool { - switch { - case fd.IsMap(): - return v.Map().Len() > 0 - case fd.IsList(): - return v.List().Len() > 0 - case fd.ContainingOneof() != nil: - return true - case !fd.HasPresence() && !fd.IsExtension(): - switch fd.Kind() { - case protoreflect.BoolKind: - return v.Bool() - case protoreflect.EnumKind: - return v.Enum() != 0 - case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed32Kind, protoreflect.Sfixed64Kind: - return v.Int() != 0 - case protoreflect.Uint32Kind, protoreflect.Uint64Kind, protoreflect.Fixed32Kind, protoreflect.Fixed64Kind: - return v.Uint() != 0 - case protoreflect.FloatKind, protoreflect.DoubleKind: - return v.Float() != 0 || math.Signbit(v.Float()) - case protoreflect.StringKind: - return v.String() != "" - case protoreflect.BytesKind: - return len(v.Bytes()) > 0 - } - } - return true -} - -func typecheck(fd protoreflect.FieldDescriptor, v protoreflect.Value) { - if err := typeIsValid(fd, v); err != nil { - panic(err) - } -} - -func typeIsValid(fd protoreflect.FieldDescriptor, v protoreflect.Value) error { - switch { - case !v.IsValid(): - return errors.New("%v: assigning invalid value", fd.FullName()) - case fd.IsMap(): - if mapv, ok := v.Interface().(*dynamicMap); !ok || mapv.desc != fd || !mapv.IsValid() { - return errors.New("%v: assigning invalid type %T", fd.FullName(), v.Interface()) - } - return nil - case fd.IsList(): - switch list := v.Interface().(type) { - case *dynamicList: - if list.desc == fd && list.IsValid() { - return nil - } - case emptyList: - if list.desc == fd && list.IsValid() { - return nil - } - } - return errors.New("%v: assigning invalid type %T", fd.FullName(), v.Interface()) - default: - return singularTypeIsValid(fd, v) - } -} - -func typecheckSingular(fd protoreflect.FieldDescriptor, v protoreflect.Value) { - if err := singularTypeIsValid(fd, v); err != nil { - panic(err) - } -} - -func singularTypeIsValid(fd protoreflect.FieldDescriptor, v protoreflect.Value) error { - vi := v.Interface() - var ok bool - switch fd.Kind() { - case protoreflect.BoolKind: - _, ok = vi.(bool) - case protoreflect.EnumKind: - // We could check against the valid set of enum values, but do not. - _, ok = vi.(protoreflect.EnumNumber) - case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind: - _, ok = vi.(int32) - case protoreflect.Uint32Kind, protoreflect.Fixed32Kind: - _, ok = vi.(uint32) - case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: - _, ok = vi.(int64) - case protoreflect.Uint64Kind, protoreflect.Fixed64Kind: - _, ok = vi.(uint64) - case protoreflect.FloatKind: - _, ok = vi.(float32) - case protoreflect.DoubleKind: - _, ok = vi.(float64) - case protoreflect.StringKind: - _, ok = vi.(string) - case protoreflect.BytesKind: - _, ok = vi.([]byte) - case protoreflect.MessageKind, protoreflect.GroupKind: - var m protoreflect.Message - m, ok = vi.(protoreflect.Message) - if ok && m.Descriptor().FullName() != fd.Message().FullName() { - return errors.New("%v: assigning invalid message type %v", fd.FullName(), m.Descriptor().FullName()) - } - if dm, ok := vi.(*Message); ok && dm.known == nil { - return errors.New("%v: assigning invalid zero-value message", fd.FullName()) - } - } - if !ok { - return errors.New("%v: assigning invalid type %T", fd.FullName(), v.Interface()) - } - return nil -} - -func newListEntry(fd protoreflect.FieldDescriptor) protoreflect.Value { - switch fd.Kind() { - case protoreflect.BoolKind: - return protoreflect.ValueOfBool(false) - case protoreflect.EnumKind: - return protoreflect.ValueOfEnum(fd.Enum().Values().Get(0).Number()) - case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind: - return protoreflect.ValueOfInt32(0) - case protoreflect.Uint32Kind, protoreflect.Fixed32Kind: - return protoreflect.ValueOfUint32(0) - case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: - return protoreflect.ValueOfInt64(0) - case protoreflect.Uint64Kind, protoreflect.Fixed64Kind: - return protoreflect.ValueOfUint64(0) - case protoreflect.FloatKind: - return protoreflect.ValueOfFloat32(0) - case protoreflect.DoubleKind: - return protoreflect.ValueOfFloat64(0) - case protoreflect.StringKind: - return protoreflect.ValueOfString("") - case protoreflect.BytesKind: - return protoreflect.ValueOfBytes(nil) - case protoreflect.MessageKind, protoreflect.GroupKind: - return protoreflect.ValueOfMessage(NewMessage(fd.Message()).ProtoReflect()) - } - panic(errors.New("%v: unknown kind %v", fd.FullName(), fd.Kind())) -} - -// NewExtensionType creates a new ExtensionType with the provided descriptor. -// -// Dynamic ExtensionTypes with the same descriptor compare as equal. That is, -// if xd1 == xd2, then NewExtensionType(xd1) == NewExtensionType(xd2). -// -// The InterfaceOf and ValueOf methods of the extension type are defined as: -// -// func (xt extensionType) ValueOf(iv interface{}) protoreflect.Value { -// return protoreflect.ValueOf(iv) -// } -// -// func (xt extensionType) InterfaceOf(v protoreflect.Value) interface{} { -// return v.Interface() -// } -// -// The Go type used by the proto.GetExtension and proto.SetExtension functions -// is determined by these methods, and is therefore equivalent to the Go type -// used to represent a protoreflect.Value. See the protoreflect.Value -// documentation for more details. -func NewExtensionType(desc protoreflect.ExtensionDescriptor) protoreflect.ExtensionType { - if xt, ok := desc.(protoreflect.ExtensionTypeDescriptor); ok { - desc = xt.Descriptor() - } - return extensionType{extensionTypeDescriptor{desc}} -} - -func (xt extensionType) New() protoreflect.Value { - switch { - case xt.desc.IsMap(): - return protoreflect.ValueOfMap(&dynamicMap{ - desc: xt.desc, - mapv: make(map[interface{}]protoreflect.Value), - }) - case xt.desc.IsList(): - return protoreflect.ValueOfList(&dynamicList{desc: xt.desc}) - case xt.desc.Message() != nil: - return protoreflect.ValueOfMessage(NewMessage(xt.desc.Message())) - default: - return xt.desc.Default() - } -} - -func (xt extensionType) Zero() protoreflect.Value { - switch { - case xt.desc.IsMap(): - return protoreflect.ValueOfMap(&dynamicMap{desc: xt.desc}) - case xt.desc.Cardinality() == protoreflect.Repeated: - return protoreflect.ValueOfList(emptyList{desc: xt.desc}) - case xt.desc.Message() != nil: - return protoreflect.ValueOfMessage(&Message{typ: messageType{xt.desc.Message()}}) - default: - return xt.desc.Default() - } -} - -func (xt extensionType) TypeDescriptor() protoreflect.ExtensionTypeDescriptor { - return xt.desc -} - -func (xt extensionType) ValueOf(iv interface{}) protoreflect.Value { - v := protoreflect.ValueOf(iv) - typecheck(xt.desc, v) - return v -} - -func (xt extensionType) InterfaceOf(v protoreflect.Value) interface{} { - typecheck(xt.desc, v) - return v.Interface() -} - -func (xt extensionType) IsValidInterface(iv interface{}) bool { - return typeIsValid(xt.desc, protoreflect.ValueOf(iv)) == nil -} - -func (xt extensionType) IsValidValue(v protoreflect.Value) bool { - return typeIsValid(xt.desc, v) == nil -} - -type extensionTypeDescriptor struct { - protoreflect.ExtensionDescriptor -} - -func (xt extensionTypeDescriptor) Type() protoreflect.ExtensionType { - return extensionType{xt} -} - -func (xt extensionTypeDescriptor) Descriptor() protoreflect.ExtensionDescriptor { - return xt.ExtensionDescriptor -} diff --git a/vendor/google.golang.org/protobuf/types/dynamicpb/types.go b/vendor/google.golang.org/protobuf/types/dynamicpb/types.go deleted file mode 100644 index c432817bb9c..00000000000 --- a/vendor/google.golang.org/protobuf/types/dynamicpb/types.go +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package dynamicpb - -import ( - "fmt" - "strings" - "sync" - "sync/atomic" - - "google.golang.org/protobuf/internal/errors" - "google.golang.org/protobuf/reflect/protoreflect" - "google.golang.org/protobuf/reflect/protoregistry" -) - -type extField struct { - name protoreflect.FullName - number protoreflect.FieldNumber -} - -// A Types is a collection of dynamically constructed descriptors. -// Its methods are safe for concurrent use. -// -// Types implements [protoregistry.MessageTypeResolver] and [protoregistry.ExtensionTypeResolver]. -// A Types may be used as a [google.golang.org/protobuf/proto.UnmarshalOptions.Resolver]. -type Types struct { - // atomicExtFiles is used with sync/atomic and hence must be the first word - // of the struct to guarantee 64-bit alignment. - // - // TODO(stapelberg): once we only support Go 1.19 and newer, switch this - // field to be of type atomic.Uint64 to guarantee alignment on - // stack-allocated values, too. - atomicExtFiles uint64 - extMu sync.Mutex - - files *protoregistry.Files - - extensionsByMessage map[extField]protoreflect.ExtensionDescriptor -} - -// NewTypes creates a new Types registry with the provided files. -// The Files registry is retained, and changes to Files will be reflected in Types. -// It is not safe to concurrently change the Files while calling Types methods. -func NewTypes(f *protoregistry.Files) *Types { - return &Types{ - files: f, - } -} - -// FindEnumByName looks up an enum by its full name; -// e.g., "google.protobuf.Field.Kind". -// -// This returns (nil, [protoregistry.NotFound]) if not found. -func (t *Types) FindEnumByName(name protoreflect.FullName) (protoreflect.EnumType, error) { - d, err := t.files.FindDescriptorByName(name) - if err != nil { - return nil, err - } - ed, ok := d.(protoreflect.EnumDescriptor) - if !ok { - return nil, errors.New("found wrong type: got %v, want enum", descName(d)) - } - return NewEnumType(ed), nil -} - -// FindExtensionByName looks up an extension field by the field's full name. -// Note that this is the full name of the field as determined by -// where the extension is declared and is unrelated to the full name of the -// message being extended. -// -// This returns (nil, [protoregistry.NotFound]) if not found. -func (t *Types) FindExtensionByName(name protoreflect.FullName) (protoreflect.ExtensionType, error) { - d, err := t.files.FindDescriptorByName(name) - if err != nil { - return nil, err - } - xd, ok := d.(protoreflect.ExtensionDescriptor) - if !ok { - return nil, errors.New("found wrong type: got %v, want extension", descName(d)) - } - return NewExtensionType(xd), nil -} - -// FindExtensionByNumber looks up an extension field by the field number -// within some parent message, identified by full name. -// -// This returns (nil, [protoregistry.NotFound]) if not found. -func (t *Types) FindExtensionByNumber(message protoreflect.FullName, field protoreflect.FieldNumber) (protoreflect.ExtensionType, error) { - // Construct the extension number map lazily, since not every user will need it. - // Update the map if new files are added to the registry. - if atomic.LoadUint64(&t.atomicExtFiles) != uint64(t.files.NumFiles()) { - t.updateExtensions() - } - xd := t.extensionsByMessage[extField{message, field}] - if xd == nil { - return nil, protoregistry.NotFound - } - return NewExtensionType(xd), nil -} - -// FindMessageByName looks up a message by its full name; -// e.g. "google.protobuf.Any". -// -// This returns (nil, [protoregistry.NotFound]) if not found. -func (t *Types) FindMessageByName(name protoreflect.FullName) (protoreflect.MessageType, error) { - d, err := t.files.FindDescriptorByName(name) - if err != nil { - return nil, err - } - md, ok := d.(protoreflect.MessageDescriptor) - if !ok { - return nil, errors.New("found wrong type: got %v, want message", descName(d)) - } - return NewMessageType(md), nil -} - -// FindMessageByURL looks up a message by a URL identifier. -// See documentation on google.protobuf.Any.type_url for the URL format. -// -// This returns (nil, [protoregistry.NotFound]) if not found. -func (t *Types) FindMessageByURL(url string) (protoreflect.MessageType, error) { - // This function is similar to FindMessageByName but - // truncates anything before and including '/' in the URL. - message := protoreflect.FullName(url) - if i := strings.LastIndexByte(url, '/'); i >= 0 { - message = message[i+len("/"):] - } - return t.FindMessageByName(message) -} - -func (t *Types) updateExtensions() { - t.extMu.Lock() - defer t.extMu.Unlock() - if atomic.LoadUint64(&t.atomicExtFiles) == uint64(t.files.NumFiles()) { - return - } - defer atomic.StoreUint64(&t.atomicExtFiles, uint64(t.files.NumFiles())) - t.files.RangeFiles(func(fd protoreflect.FileDescriptor) bool { - t.registerExtensions(fd.Extensions()) - t.registerExtensionsInMessages(fd.Messages()) - return true - }) -} - -func (t *Types) registerExtensionsInMessages(mds protoreflect.MessageDescriptors) { - count := mds.Len() - for i := 0; i < count; i++ { - md := mds.Get(i) - t.registerExtensions(md.Extensions()) - t.registerExtensionsInMessages(md.Messages()) - } -} - -func (t *Types) registerExtensions(xds protoreflect.ExtensionDescriptors) { - count := xds.Len() - for i := 0; i < count; i++ { - xd := xds.Get(i) - field := xd.Number() - message := xd.ContainingMessage().FullName() - if t.extensionsByMessage == nil { - t.extensionsByMessage = make(map[extField]protoreflect.ExtensionDescriptor) - } - t.extensionsByMessage[extField{message, field}] = xd - } -} - -func descName(d protoreflect.Descriptor) string { - switch d.(type) { - case protoreflect.EnumDescriptor: - return "enum" - case protoreflect.EnumValueDescriptor: - return "enum value" - case protoreflect.MessageDescriptor: - return "message" - case protoreflect.ExtensionDescriptor: - return "extension" - case protoreflect.ServiceDescriptor: - return "service" - default: - return fmt.Sprintf("%T", d) - } -} diff --git a/vendor/google.golang.org/protobuf/types/known/emptypb/empty.pb.go b/vendor/google.golang.org/protobuf/types/known/emptypb/empty.pb.go new file mode 100644 index 00000000000..9a7277ba394 --- /dev/null +++ b/vendor/google.golang.org/protobuf/types/known/emptypb/empty.pb.go @@ -0,0 +1,166 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: google/protobuf/empty.proto + +package emptypb + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +// A generic empty message that you can re-use to avoid defining duplicated +// empty messages in your APIs. A typical example is to use it as the request +// or the response type of an API method. For instance: +// +// service Foo { +// rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); +// } +type Empty struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *Empty) Reset() { + *x = Empty{} + if protoimpl.UnsafeEnabled { + mi := &file_google_protobuf_empty_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Empty) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Empty) ProtoMessage() {} + +func (x *Empty) ProtoReflect() protoreflect.Message { + mi := &file_google_protobuf_empty_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Empty.ProtoReflect.Descriptor instead. +func (*Empty) Descriptor() ([]byte, []int) { + return file_google_protobuf_empty_proto_rawDescGZIP(), []int{0} +} + +var File_google_protobuf_empty_proto protoreflect.FileDescriptor + +var file_google_protobuf_empty_proto_rawDesc = []byte{ + 0x0a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x22, 0x07, + 0x0a, 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x42, 0x7d, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x42, 0x0a, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x6b, + 0x6e, 0x6f, 0x77, 0x6e, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x70, 0x62, 0xf8, 0x01, 0x01, 0xa2, + 0x02, 0x03, 0x47, 0x50, 0x42, 0xaa, 0x02, 0x1e, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x50, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x57, 0x65, 0x6c, 0x6c, 0x4b, 0x6e, 0x6f, 0x77, + 0x6e, 0x54, 0x79, 0x70, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_google_protobuf_empty_proto_rawDescOnce sync.Once + file_google_protobuf_empty_proto_rawDescData = file_google_protobuf_empty_proto_rawDesc +) + +func file_google_protobuf_empty_proto_rawDescGZIP() []byte { + file_google_protobuf_empty_proto_rawDescOnce.Do(func() { + file_google_protobuf_empty_proto_rawDescData = protoimpl.X.CompressGZIP(file_google_protobuf_empty_proto_rawDescData) + }) + return file_google_protobuf_empty_proto_rawDescData +} + +var file_google_protobuf_empty_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_google_protobuf_empty_proto_goTypes = []interface{}{ + (*Empty)(nil), // 0: google.protobuf.Empty +} +var file_google_protobuf_empty_proto_depIdxs = []int32{ + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_google_protobuf_empty_proto_init() } +func file_google_protobuf_empty_proto_init() { + if File_google_protobuf_empty_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_google_protobuf_empty_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Empty); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_google_protobuf_empty_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_google_protobuf_empty_proto_goTypes, + DependencyIndexes: file_google_protobuf_empty_proto_depIdxs, + MessageInfos: file_google_protobuf_empty_proto_msgTypes, + }.Build() + File_google_protobuf_empty_proto = out.File + file_google_protobuf_empty_proto_rawDesc = nil + file_google_protobuf_empty_proto_goTypes = nil + file_google_protobuf_empty_proto_depIdxs = nil +} diff --git a/vendor/google.golang.org/protobuf/types/known/fieldmaskpb/field_mask.pb.go b/vendor/google.golang.org/protobuf/types/known/fieldmaskpb/field_mask.pb.go new file mode 100644 index 00000000000..e8789cb331e --- /dev/null +++ b/vendor/google.golang.org/protobuf/types/known/fieldmaskpb/field_mask.pb.go @@ -0,0 +1,588 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: google/protobuf/field_mask.proto + +// Package fieldmaskpb contains generated types for google/protobuf/field_mask.proto. +// +// The FieldMask message represents a set of symbolic field paths. +// The paths are specific to some target message type, +// which is not stored within the FieldMask message itself. +// +// # Constructing a FieldMask +// +// The New function is used construct a FieldMask: +// +// var messageType *descriptorpb.DescriptorProto +// fm, err := fieldmaskpb.New(messageType, "field.name", "field.number") +// if err != nil { +// ... // handle error +// } +// ... // make use of fm +// +// The "field.name" and "field.number" paths are valid paths according to the +// google.protobuf.DescriptorProto message. Use of a path that does not correlate +// to valid fields reachable from DescriptorProto would result in an error. +// +// Once a FieldMask message has been constructed, +// the Append method can be used to insert additional paths to the path set: +// +// var messageType *descriptorpb.DescriptorProto +// if err := fm.Append(messageType, "options"); err != nil { +// ... // handle error +// } +// +// # Type checking a FieldMask +// +// In order to verify that a FieldMask represents a set of fields that are +// reachable from some target message type, use the IsValid method: +// +// var messageType *descriptorpb.DescriptorProto +// if fm.IsValid(messageType) { +// ... // make use of fm +// } +// +// IsValid needs to be passed the target message type as an input since the +// FieldMask message itself does not store the message type that the set of paths +// are for. +package fieldmaskpb + +import ( + proto "google.golang.org/protobuf/proto" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sort "sort" + strings "strings" + sync "sync" +) + +// `FieldMask` represents a set of symbolic field paths, for example: +// +// paths: "f.a" +// paths: "f.b.d" +// +// Here `f` represents a field in some root message, `a` and `b` +// fields in the message found in `f`, and `d` a field found in the +// message in `f.b`. +// +// Field masks are used to specify a subset of fields that should be +// returned by a get operation or modified by an update operation. +// Field masks also have a custom JSON encoding (see below). +// +// # Field Masks in Projections +// +// When used in the context of a projection, a response message or +// sub-message is filtered by the API to only contain those fields as +// specified in the mask. For example, if the mask in the previous +// example is applied to a response message as follows: +// +// f { +// a : 22 +// b { +// d : 1 +// x : 2 +// } +// y : 13 +// } +// z: 8 +// +// The result will not contain specific values for fields x,y and z +// (their value will be set to the default, and omitted in proto text +// output): +// +// f { +// a : 22 +// b { +// d : 1 +// } +// } +// +// A repeated field is not allowed except at the last position of a +// paths string. +// +// If a FieldMask object is not present in a get operation, the +// operation applies to all fields (as if a FieldMask of all fields +// had been specified). +// +// Note that a field mask does not necessarily apply to the +// top-level response message. In case of a REST get operation, the +// field mask applies directly to the response, but in case of a REST +// list operation, the mask instead applies to each individual message +// in the returned resource list. In case of a REST custom method, +// other definitions may be used. Where the mask applies will be +// clearly documented together with its declaration in the API. In +// any case, the effect on the returned resource/resources is required +// behavior for APIs. +// +// # Field Masks in Update Operations +// +// A field mask in update operations specifies which fields of the +// targeted resource are going to be updated. The API is required +// to only change the values of the fields as specified in the mask +// and leave the others untouched. If a resource is passed in to +// describe the updated values, the API ignores the values of all +// fields not covered by the mask. +// +// If a repeated field is specified for an update operation, new values will +// be appended to the existing repeated field in the target resource. Note that +// a repeated field is only allowed in the last position of a `paths` string. +// +// If a sub-message is specified in the last position of the field mask for an +// update operation, then new value will be merged into the existing sub-message +// in the target resource. +// +// For example, given the target message: +// +// f { +// b { +// d: 1 +// x: 2 +// } +// c: [1] +// } +// +// And an update message: +// +// f { +// b { +// d: 10 +// } +// c: [2] +// } +// +// then if the field mask is: +// +// paths: ["f.b", "f.c"] +// +// then the result will be: +// +// f { +// b { +// d: 10 +// x: 2 +// } +// c: [1, 2] +// } +// +// An implementation may provide options to override this default behavior for +// repeated and message fields. +// +// In order to reset a field's value to the default, the field must +// be in the mask and set to the default value in the provided resource. +// Hence, in order to reset all fields of a resource, provide a default +// instance of the resource and set all fields in the mask, or do +// not provide a mask as described below. +// +// If a field mask is not present on update, the operation applies to +// all fields (as if a field mask of all fields has been specified). +// Note that in the presence of schema evolution, this may mean that +// fields the client does not know and has therefore not filled into +// the request will be reset to their default. If this is unwanted +// behavior, a specific service may require a client to always specify +// a field mask, producing an error if not. +// +// As with get operations, the location of the resource which +// describes the updated values in the request message depends on the +// operation kind. In any case, the effect of the field mask is +// required to be honored by the API. +// +// ## Considerations for HTTP REST +// +// The HTTP kind of an update operation which uses a field mask must +// be set to PATCH instead of PUT in order to satisfy HTTP semantics +// (PUT must only be used for full updates). +// +// # JSON Encoding of Field Masks +// +// In JSON, a field mask is encoded as a single string where paths are +// separated by a comma. Fields name in each path are converted +// to/from lower-camel naming conventions. +// +// As an example, consider the following message declarations: +// +// message Profile { +// User user = 1; +// Photo photo = 2; +// } +// message User { +// string display_name = 1; +// string address = 2; +// } +// +// In proto a field mask for `Profile` may look as such: +// +// mask { +// paths: "user.display_name" +// paths: "photo" +// } +// +// In JSON, the same mask is represented as below: +// +// { +// mask: "user.displayName,photo" +// } +// +// # Field Masks and Oneof Fields +// +// Field masks treat fields in oneofs just as regular fields. Consider the +// following message: +// +// message SampleMessage { +// oneof test_oneof { +// string name = 4; +// SubMessage sub_message = 9; +// } +// } +// +// The field mask can be: +// +// mask { +// paths: "name" +// } +// +// Or: +// +// mask { +// paths: "sub_message" +// } +// +// Note that oneof type names ("test_oneof" in this case) cannot be used in +// paths. +// +// ## Field Mask Verification +// +// The implementation of any API method which has a FieldMask type field in the +// request should verify the included field paths, and return an +// `INVALID_ARGUMENT` error if any path is unmappable. +type FieldMask struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The set of field mask paths. + Paths []string `protobuf:"bytes,1,rep,name=paths,proto3" json:"paths,omitempty"` +} + +// New constructs a field mask from a list of paths and verifies that +// each one is valid according to the specified message type. +func New(m proto.Message, paths ...string) (*FieldMask, error) { + x := new(FieldMask) + return x, x.Append(m, paths...) +} + +// Union returns the union of all the paths in the input field masks. +func Union(mx *FieldMask, my *FieldMask, ms ...*FieldMask) *FieldMask { + var out []string + out = append(out, mx.GetPaths()...) + out = append(out, my.GetPaths()...) + for _, m := range ms { + out = append(out, m.GetPaths()...) + } + return &FieldMask{Paths: normalizePaths(out)} +} + +// Intersect returns the intersection of all the paths in the input field masks. +func Intersect(mx *FieldMask, my *FieldMask, ms ...*FieldMask) *FieldMask { + var ss1, ss2 []string // reused buffers for performance + intersect := func(out, in []string) []string { + ss1 = normalizePaths(append(ss1[:0], in...)) + ss2 = normalizePaths(append(ss2[:0], out...)) + out = out[:0] + for i1, i2 := 0, 0; i1 < len(ss1) && i2 < len(ss2); { + switch s1, s2 := ss1[i1], ss2[i2]; { + case hasPathPrefix(s1, s2): + out = append(out, s1) + i1++ + case hasPathPrefix(s2, s1): + out = append(out, s2) + i2++ + case lessPath(s1, s2): + i1++ + case lessPath(s2, s1): + i2++ + } + } + return out + } + + out := Union(mx, my, ms...).GetPaths() + out = intersect(out, mx.GetPaths()) + out = intersect(out, my.GetPaths()) + for _, m := range ms { + out = intersect(out, m.GetPaths()) + } + return &FieldMask{Paths: normalizePaths(out)} +} + +// IsValid reports whether all the paths are syntactically valid and +// refer to known fields in the specified message type. +// It reports false for a nil FieldMask. +func (x *FieldMask) IsValid(m proto.Message) bool { + paths := x.GetPaths() + return x != nil && numValidPaths(m, paths) == len(paths) +} + +// Append appends a list of paths to the mask and verifies that each one +// is valid according to the specified message type. +// An invalid path is not appended and breaks insertion of subsequent paths. +func (x *FieldMask) Append(m proto.Message, paths ...string) error { + numValid := numValidPaths(m, paths) + x.Paths = append(x.Paths, paths[:numValid]...) + paths = paths[numValid:] + if len(paths) > 0 { + name := m.ProtoReflect().Descriptor().FullName() + return protoimpl.X.NewError("invalid path %q for message %q", paths[0], name) + } + return nil +} + +func numValidPaths(m proto.Message, paths []string) int { + md0 := m.ProtoReflect().Descriptor() + for i, path := range paths { + md := md0 + if !rangeFields(path, func(field string) bool { + // Search the field within the message. + if md == nil { + return false // not within a message + } + fd := md.Fields().ByName(protoreflect.Name(field)) + // The real field name of a group is the message name. + if fd == nil { + gd := md.Fields().ByName(protoreflect.Name(strings.ToLower(field))) + if gd != nil && gd.Kind() == protoreflect.GroupKind && string(gd.Message().Name()) == field { + fd = gd + } + } else if fd.Kind() == protoreflect.GroupKind && string(fd.Message().Name()) != field { + fd = nil + } + if fd == nil { + return false // message has does not have this field + } + + // Identify the next message to search within. + md = fd.Message() // may be nil + + // Repeated fields are only allowed at the last position. + if fd.IsList() || fd.IsMap() { + md = nil + } + + return true + }) { + return i + } + } + return len(paths) +} + +// Normalize converts the mask to its canonical form where all paths are sorted +// and redundant paths are removed. +func (x *FieldMask) Normalize() { + x.Paths = normalizePaths(x.Paths) +} + +func normalizePaths(paths []string) []string { + sort.Slice(paths, func(i, j int) bool { + return lessPath(paths[i], paths[j]) + }) + + // Elide any path that is a prefix match on the previous. + out := paths[:0] + for _, path := range paths { + if len(out) > 0 && hasPathPrefix(path, out[len(out)-1]) { + continue + } + out = append(out, path) + } + return out +} + +// hasPathPrefix is like strings.HasPrefix, but further checks for either +// an exact matche or that the prefix is delimited by a dot. +func hasPathPrefix(path, prefix string) bool { + return strings.HasPrefix(path, prefix) && (len(path) == len(prefix) || path[len(prefix)] == '.') +} + +// lessPath is a lexicographical comparison where dot is specially treated +// as the smallest symbol. +func lessPath(x, y string) bool { + for i := 0; i < len(x) && i < len(y); i++ { + if x[i] != y[i] { + return (x[i] - '.') < (y[i] - '.') + } + } + return len(x) < len(y) +} + +// rangeFields is like strings.Split(path, "."), but avoids allocations by +// iterating over each field in place and calling a iterator function. +func rangeFields(path string, f func(field string) bool) bool { + for { + var field string + if i := strings.IndexByte(path, '.'); i >= 0 { + field, path = path[:i], path[i:] + } else { + field, path = path, "" + } + + if !f(field) { + return false + } + + if len(path) == 0 { + return true + } + path = strings.TrimPrefix(path, ".") + } +} + +func (x *FieldMask) Reset() { + *x = FieldMask{} + if protoimpl.UnsafeEnabled { + mi := &file_google_protobuf_field_mask_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FieldMask) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FieldMask) ProtoMessage() {} + +func (x *FieldMask) ProtoReflect() protoreflect.Message { + mi := &file_google_protobuf_field_mask_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FieldMask.ProtoReflect.Descriptor instead. +func (*FieldMask) Descriptor() ([]byte, []int) { + return file_google_protobuf_field_mask_proto_rawDescGZIP(), []int{0} +} + +func (x *FieldMask) GetPaths() []string { + if x != nil { + return x.Paths + } + return nil +} + +var File_google_protobuf_field_mask_proto protoreflect.FileDescriptor + +var file_google_protobuf_field_mask_proto_rawDesc = []byte{ + 0x0a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x12, 0x0f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x22, 0x21, 0x0a, 0x09, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, + 0x12, 0x14, 0x0a, 0x05, 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x05, 0x70, 0x61, 0x74, 0x68, 0x73, 0x42, 0x85, 0x01, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x42, 0x0e, + 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, + 0x5a, 0x32, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, + 0x6f, 0x72, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x79, 0x70, + 0x65, 0x73, 0x2f, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x6d, 0x61, + 0x73, 0x6b, 0x70, 0x62, 0xf8, 0x01, 0x01, 0xa2, 0x02, 0x03, 0x47, 0x50, 0x42, 0xaa, 0x02, 0x1e, + 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x57, 0x65, 0x6c, 0x6c, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x73, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_google_protobuf_field_mask_proto_rawDescOnce sync.Once + file_google_protobuf_field_mask_proto_rawDescData = file_google_protobuf_field_mask_proto_rawDesc +) + +func file_google_protobuf_field_mask_proto_rawDescGZIP() []byte { + file_google_protobuf_field_mask_proto_rawDescOnce.Do(func() { + file_google_protobuf_field_mask_proto_rawDescData = protoimpl.X.CompressGZIP(file_google_protobuf_field_mask_proto_rawDescData) + }) + return file_google_protobuf_field_mask_proto_rawDescData +} + +var file_google_protobuf_field_mask_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_google_protobuf_field_mask_proto_goTypes = []interface{}{ + (*FieldMask)(nil), // 0: google.protobuf.FieldMask +} +var file_google_protobuf_field_mask_proto_depIdxs = []int32{ + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_google_protobuf_field_mask_proto_init() } +func file_google_protobuf_field_mask_proto_init() { + if File_google_protobuf_field_mask_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_google_protobuf_field_mask_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FieldMask); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_google_protobuf_field_mask_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_google_protobuf_field_mask_proto_goTypes, + DependencyIndexes: file_google_protobuf_field_mask_proto_depIdxs, + MessageInfos: file_google_protobuf_field_mask_proto_msgTypes, + }.Build() + File_google_protobuf_field_mask_proto = out.File + file_google_protobuf_field_mask_proto_rawDesc = nil + file_google_protobuf_field_mask_proto_goTypes = nil + file_google_protobuf_field_mask_proto_depIdxs = nil +} diff --git a/vendor/google.golang.org/protobuf/types/pluginpb/plugin.pb.go b/vendor/google.golang.org/protobuf/types/pluginpb/plugin.pb.go deleted file mode 100644 index 620728f8cca..00000000000 --- a/vendor/google.golang.org/protobuf/types/pluginpb/plugin.pb.go +++ /dev/null @@ -1,690 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file or at -// https://developers.google.com/open-source/licenses/bsd - -// Author: kenton@google.com (Kenton Varda) -// -// protoc (aka the Protocol Compiler) can be extended via plugins. A plugin is -// just a program that reads a CodeGeneratorRequest from stdin and writes a -// CodeGeneratorResponse to stdout. -// -// Plugins written using C++ can use google/protobuf/compiler/plugin.h instead -// of dealing with the raw protocol defined here. -// -// A plugin executable needs only to be placed somewhere in the path. The -// plugin should be named "protoc-gen-$NAME", and will then be used when the -// flag "--${NAME}_out" is passed to protoc. - -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: google/protobuf/compiler/plugin.proto - -package pluginpb - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - descriptorpb "google.golang.org/protobuf/types/descriptorpb" - reflect "reflect" - sync "sync" -) - -// Sync with code_generator.h. -type CodeGeneratorResponse_Feature int32 - -const ( - CodeGeneratorResponse_FEATURE_NONE CodeGeneratorResponse_Feature = 0 - CodeGeneratorResponse_FEATURE_PROTO3_OPTIONAL CodeGeneratorResponse_Feature = 1 - CodeGeneratorResponse_FEATURE_SUPPORTS_EDITIONS CodeGeneratorResponse_Feature = 2 -) - -// Enum value maps for CodeGeneratorResponse_Feature. -var ( - CodeGeneratorResponse_Feature_name = map[int32]string{ - 0: "FEATURE_NONE", - 1: "FEATURE_PROTO3_OPTIONAL", - 2: "FEATURE_SUPPORTS_EDITIONS", - } - CodeGeneratorResponse_Feature_value = map[string]int32{ - "FEATURE_NONE": 0, - "FEATURE_PROTO3_OPTIONAL": 1, - "FEATURE_SUPPORTS_EDITIONS": 2, - } -) - -func (x CodeGeneratorResponse_Feature) Enum() *CodeGeneratorResponse_Feature { - p := new(CodeGeneratorResponse_Feature) - *p = x - return p -} - -func (x CodeGeneratorResponse_Feature) String() string { - return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) -} - -func (CodeGeneratorResponse_Feature) Descriptor() protoreflect.EnumDescriptor { - return file_google_protobuf_compiler_plugin_proto_enumTypes[0].Descriptor() -} - -func (CodeGeneratorResponse_Feature) Type() protoreflect.EnumType { - return &file_google_protobuf_compiler_plugin_proto_enumTypes[0] -} - -func (x CodeGeneratorResponse_Feature) Number() protoreflect.EnumNumber { - return protoreflect.EnumNumber(x) -} - -// Deprecated: Do not use. -func (x *CodeGeneratorResponse_Feature) UnmarshalJSON(b []byte) error { - num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) - if err != nil { - return err - } - *x = CodeGeneratorResponse_Feature(num) - return nil -} - -// Deprecated: Use CodeGeneratorResponse_Feature.Descriptor instead. -func (CodeGeneratorResponse_Feature) EnumDescriptor() ([]byte, []int) { - return file_google_protobuf_compiler_plugin_proto_rawDescGZIP(), []int{2, 0} -} - -// The version number of protocol compiler. -type Version struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Major *int32 `protobuf:"varint,1,opt,name=major" json:"major,omitempty"` - Minor *int32 `protobuf:"varint,2,opt,name=minor" json:"minor,omitempty"` - Patch *int32 `protobuf:"varint,3,opt,name=patch" json:"patch,omitempty"` - // A suffix for alpha, beta or rc release, e.g., "alpha-1", "rc2". It should - // be empty for mainline stable releases. - Suffix *string `protobuf:"bytes,4,opt,name=suffix" json:"suffix,omitempty"` -} - -func (x *Version) Reset() { - *x = Version{} - if protoimpl.UnsafeEnabled { - mi := &file_google_protobuf_compiler_plugin_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Version) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Version) ProtoMessage() {} - -func (x *Version) ProtoReflect() protoreflect.Message { - mi := &file_google_protobuf_compiler_plugin_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Version.ProtoReflect.Descriptor instead. -func (*Version) Descriptor() ([]byte, []int) { - return file_google_protobuf_compiler_plugin_proto_rawDescGZIP(), []int{0} -} - -func (x *Version) GetMajor() int32 { - if x != nil && x.Major != nil { - return *x.Major - } - return 0 -} - -func (x *Version) GetMinor() int32 { - if x != nil && x.Minor != nil { - return *x.Minor - } - return 0 -} - -func (x *Version) GetPatch() int32 { - if x != nil && x.Patch != nil { - return *x.Patch - } - return 0 -} - -func (x *Version) GetSuffix() string { - if x != nil && x.Suffix != nil { - return *x.Suffix - } - return "" -} - -// An encoded CodeGeneratorRequest is written to the plugin's stdin. -type CodeGeneratorRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // The .proto files that were explicitly listed on the command-line. The - // code generator should generate code only for these files. Each file's - // descriptor will be included in proto_file, below. - FileToGenerate []string `protobuf:"bytes,1,rep,name=file_to_generate,json=fileToGenerate" json:"file_to_generate,omitempty"` - // The generator parameter passed on the command-line. - Parameter *string `protobuf:"bytes,2,opt,name=parameter" json:"parameter,omitempty"` - // FileDescriptorProtos for all files in files_to_generate and everything - // they import. The files will appear in topological order, so each file - // appears before any file that imports it. - // - // Note: the files listed in files_to_generate will include runtime-retention - // options only, but all other files will include source-retention options. - // The source_file_descriptors field below is available in case you need - // source-retention options for files_to_generate. - // - // protoc guarantees that all proto_files will be written after - // the fields above, even though this is not technically guaranteed by the - // protobuf wire format. This theoretically could allow a plugin to stream - // in the FileDescriptorProtos and handle them one by one rather than read - // the entire set into memory at once. However, as of this writing, this - // is not similarly optimized on protoc's end -- it will store all fields in - // memory at once before sending them to the plugin. - // - // Type names of fields and extensions in the FileDescriptorProto are always - // fully qualified. - ProtoFile []*descriptorpb.FileDescriptorProto `protobuf:"bytes,15,rep,name=proto_file,json=protoFile" json:"proto_file,omitempty"` - // File descriptors with all options, including source-retention options. - // These descriptors are only provided for the files listed in - // files_to_generate. - SourceFileDescriptors []*descriptorpb.FileDescriptorProto `protobuf:"bytes,17,rep,name=source_file_descriptors,json=sourceFileDescriptors" json:"source_file_descriptors,omitempty"` - // The version number of protocol compiler. - CompilerVersion *Version `protobuf:"bytes,3,opt,name=compiler_version,json=compilerVersion" json:"compiler_version,omitempty"` -} - -func (x *CodeGeneratorRequest) Reset() { - *x = CodeGeneratorRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_google_protobuf_compiler_plugin_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *CodeGeneratorRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*CodeGeneratorRequest) ProtoMessage() {} - -func (x *CodeGeneratorRequest) ProtoReflect() protoreflect.Message { - mi := &file_google_protobuf_compiler_plugin_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use CodeGeneratorRequest.ProtoReflect.Descriptor instead. -func (*CodeGeneratorRequest) Descriptor() ([]byte, []int) { - return file_google_protobuf_compiler_plugin_proto_rawDescGZIP(), []int{1} -} - -func (x *CodeGeneratorRequest) GetFileToGenerate() []string { - if x != nil { - return x.FileToGenerate - } - return nil -} - -func (x *CodeGeneratorRequest) GetParameter() string { - if x != nil && x.Parameter != nil { - return *x.Parameter - } - return "" -} - -func (x *CodeGeneratorRequest) GetProtoFile() []*descriptorpb.FileDescriptorProto { - if x != nil { - return x.ProtoFile - } - return nil -} - -func (x *CodeGeneratorRequest) GetSourceFileDescriptors() []*descriptorpb.FileDescriptorProto { - if x != nil { - return x.SourceFileDescriptors - } - return nil -} - -func (x *CodeGeneratorRequest) GetCompilerVersion() *Version { - if x != nil { - return x.CompilerVersion - } - return nil -} - -// The plugin writes an encoded CodeGeneratorResponse to stdout. -type CodeGeneratorResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Error message. If non-empty, code generation failed. The plugin process - // should exit with status code zero even if it reports an error in this way. - // - // This should be used to indicate errors in .proto files which prevent the - // code generator from generating correct code. Errors which indicate a - // problem in protoc itself -- such as the input CodeGeneratorRequest being - // unparseable -- should be reported by writing a message to stderr and - // exiting with a non-zero status code. - Error *string `protobuf:"bytes,1,opt,name=error" json:"error,omitempty"` - // A bitmask of supported features that the code generator supports. - // This is a bitwise "or" of values from the Feature enum. - SupportedFeatures *uint64 `protobuf:"varint,2,opt,name=supported_features,json=supportedFeatures" json:"supported_features,omitempty"` - // The minimum edition this plugin supports. This will be treated as an - // Edition enum, but we want to allow unknown values. It should be specified - // according the edition enum value, *not* the edition number. Only takes - // effect for plugins that have FEATURE_SUPPORTS_EDITIONS set. - MinimumEdition *int32 `protobuf:"varint,3,opt,name=minimum_edition,json=minimumEdition" json:"minimum_edition,omitempty"` - // The maximum edition this plugin supports. This will be treated as an - // Edition enum, but we want to allow unknown values. It should be specified - // according the edition enum value, *not* the edition number. Only takes - // effect for plugins that have FEATURE_SUPPORTS_EDITIONS set. - MaximumEdition *int32 `protobuf:"varint,4,opt,name=maximum_edition,json=maximumEdition" json:"maximum_edition,omitempty"` - File []*CodeGeneratorResponse_File `protobuf:"bytes,15,rep,name=file" json:"file,omitempty"` -} - -func (x *CodeGeneratorResponse) Reset() { - *x = CodeGeneratorResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_google_protobuf_compiler_plugin_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *CodeGeneratorResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*CodeGeneratorResponse) ProtoMessage() {} - -func (x *CodeGeneratorResponse) ProtoReflect() protoreflect.Message { - mi := &file_google_protobuf_compiler_plugin_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use CodeGeneratorResponse.ProtoReflect.Descriptor instead. -func (*CodeGeneratorResponse) Descriptor() ([]byte, []int) { - return file_google_protobuf_compiler_plugin_proto_rawDescGZIP(), []int{2} -} - -func (x *CodeGeneratorResponse) GetError() string { - if x != nil && x.Error != nil { - return *x.Error - } - return "" -} - -func (x *CodeGeneratorResponse) GetSupportedFeatures() uint64 { - if x != nil && x.SupportedFeatures != nil { - return *x.SupportedFeatures - } - return 0 -} - -func (x *CodeGeneratorResponse) GetMinimumEdition() int32 { - if x != nil && x.MinimumEdition != nil { - return *x.MinimumEdition - } - return 0 -} - -func (x *CodeGeneratorResponse) GetMaximumEdition() int32 { - if x != nil && x.MaximumEdition != nil { - return *x.MaximumEdition - } - return 0 -} - -func (x *CodeGeneratorResponse) GetFile() []*CodeGeneratorResponse_File { - if x != nil { - return x.File - } - return nil -} - -// Represents a single generated file. -type CodeGeneratorResponse_File struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // The file name, relative to the output directory. The name must not - // contain "." or ".." components and must be relative, not be absolute (so, - // the file cannot lie outside the output directory). "/" must be used as - // the path separator, not "\". - // - // If the name is omitted, the content will be appended to the previous - // file. This allows the generator to break large files into small chunks, - // and allows the generated text to be streamed back to protoc so that large - // files need not reside completely in memory at one time. Note that as of - // this writing protoc does not optimize for this -- it will read the entire - // CodeGeneratorResponse before writing files to disk. - Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` - // If non-empty, indicates that the named file should already exist, and the - // content here is to be inserted into that file at a defined insertion - // point. This feature allows a code generator to extend the output - // produced by another code generator. The original generator may provide - // insertion points by placing special annotations in the file that look - // like: - // - // @@protoc_insertion_point(NAME) - // - // The annotation can have arbitrary text before and after it on the line, - // which allows it to be placed in a comment. NAME should be replaced with - // an identifier naming the point -- this is what other generators will use - // as the insertion_point. Code inserted at this point will be placed - // immediately above the line containing the insertion point (thus multiple - // insertions to the same point will come out in the order they were added). - // The double-@ is intended to make it unlikely that the generated code - // could contain things that look like insertion points by accident. - // - // For example, the C++ code generator places the following line in the - // .pb.h files that it generates: - // - // // @@protoc_insertion_point(namespace_scope) - // - // This line appears within the scope of the file's package namespace, but - // outside of any particular class. Another plugin can then specify the - // insertion_point "namespace_scope" to generate additional classes or - // other declarations that should be placed in this scope. - // - // Note that if the line containing the insertion point begins with - // whitespace, the same whitespace will be added to every line of the - // inserted text. This is useful for languages like Python, where - // indentation matters. In these languages, the insertion point comment - // should be indented the same amount as any inserted code will need to be - // in order to work correctly in that context. - // - // The code generator that generates the initial file and the one which - // inserts into it must both run as part of a single invocation of protoc. - // Code generators are executed in the order in which they appear on the - // command line. - // - // If |insertion_point| is present, |name| must also be present. - InsertionPoint *string `protobuf:"bytes,2,opt,name=insertion_point,json=insertionPoint" json:"insertion_point,omitempty"` - // The file contents. - Content *string `protobuf:"bytes,15,opt,name=content" json:"content,omitempty"` - // Information describing the file content being inserted. If an insertion - // point is used, this information will be appropriately offset and inserted - // into the code generation metadata for the generated files. - GeneratedCodeInfo *descriptorpb.GeneratedCodeInfo `protobuf:"bytes,16,opt,name=generated_code_info,json=generatedCodeInfo" json:"generated_code_info,omitempty"` -} - -func (x *CodeGeneratorResponse_File) Reset() { - *x = CodeGeneratorResponse_File{} - if protoimpl.UnsafeEnabled { - mi := &file_google_protobuf_compiler_plugin_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *CodeGeneratorResponse_File) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*CodeGeneratorResponse_File) ProtoMessage() {} - -func (x *CodeGeneratorResponse_File) ProtoReflect() protoreflect.Message { - mi := &file_google_protobuf_compiler_plugin_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use CodeGeneratorResponse_File.ProtoReflect.Descriptor instead. -func (*CodeGeneratorResponse_File) Descriptor() ([]byte, []int) { - return file_google_protobuf_compiler_plugin_proto_rawDescGZIP(), []int{2, 0} -} - -func (x *CodeGeneratorResponse_File) GetName() string { - if x != nil && x.Name != nil { - return *x.Name - } - return "" -} - -func (x *CodeGeneratorResponse_File) GetInsertionPoint() string { - if x != nil && x.InsertionPoint != nil { - return *x.InsertionPoint - } - return "" -} - -func (x *CodeGeneratorResponse_File) GetContent() string { - if x != nil && x.Content != nil { - return *x.Content - } - return "" -} - -func (x *CodeGeneratorResponse_File) GetGeneratedCodeInfo() *descriptorpb.GeneratedCodeInfo { - if x != nil { - return x.GeneratedCodeInfo - } - return nil -} - -var File_google_protobuf_compiler_plugin_proto protoreflect.FileDescriptor - -var file_google_protobuf_compiler_plugin_proto_rawDesc = []byte{ - 0x0a, 0x25, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2f, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x2f, 0x70, 0x6c, 0x75, 0x67, 0x69, - 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x18, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, - 0x72, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x22, 0x63, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, - 0x0a, 0x05, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6d, - 0x61, 0x6a, 0x6f, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x05, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x61, - 0x74, 0x63, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x70, 0x61, 0x74, 0x63, 0x68, - 0x12, 0x16, 0x0a, 0x06, 0x73, 0x75, 0x66, 0x66, 0x69, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x73, 0x75, 0x66, 0x66, 0x69, 0x78, 0x22, 0xcf, 0x02, 0x0a, 0x14, 0x43, 0x6f, 0x64, - 0x65, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x28, 0x0a, 0x10, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x74, 0x6f, 0x5f, 0x67, 0x65, 0x6e, - 0x65, 0x72, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x66, 0x69, 0x6c, - 0x65, 0x54, 0x6f, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x70, - 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, - 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x12, 0x43, 0x0a, 0x0a, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x0f, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x46, 0x69, 0x6c, 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x50, 0x72, - 0x6f, 0x74, 0x6f, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x5c, - 0x0a, 0x17, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x64, 0x65, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x11, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x24, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x52, 0x15, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x46, 0x69, 0x6c, - 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x4c, 0x0a, 0x10, - 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, - 0x72, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0f, 0x63, 0x6f, 0x6d, 0x70, 0x69, - 0x6c, 0x65, 0x72, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x85, 0x04, 0x0a, 0x15, 0x43, - 0x6f, 0x64, 0x65, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x2d, 0x0a, 0x12, 0x73, 0x75, - 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, - 0x64, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x6d, 0x69, 0x6e, - 0x69, 0x6d, 0x75, 0x6d, 0x5f, 0x65, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x05, 0x52, 0x0e, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x45, 0x64, 0x69, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x27, 0x0a, 0x0f, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x5f, 0x65, 0x64, - 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x6d, 0x61, 0x78, - 0x69, 0x6d, 0x75, 0x6d, 0x45, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x48, 0x0a, 0x04, 0x66, - 0x69, 0x6c, 0x65, 0x18, 0x0f, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x63, 0x6f, 0x6d, 0x70, - 0x69, 0x6c, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, - 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x52, - 0x04, 0x66, 0x69, 0x6c, 0x65, 0x1a, 0xb1, 0x01, 0x0a, 0x04, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x12, - 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x69, 0x6f, 0x6e, 0x5f, - 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x69, 0x6e, 0x73, - 0x65, 0x72, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x63, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x52, 0x0a, 0x13, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, - 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x10, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x43, 0x6f, - 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x11, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, - 0x64, 0x43, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0x57, 0x0a, 0x07, 0x46, 0x65, 0x61, - 0x74, 0x75, 0x72, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x46, 0x45, 0x41, 0x54, 0x55, 0x52, 0x45, 0x5f, - 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x46, 0x45, 0x41, 0x54, 0x55, 0x52, - 0x45, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x33, 0x5f, 0x4f, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x41, - 0x4c, 0x10, 0x01, 0x12, 0x1d, 0x0a, 0x19, 0x46, 0x45, 0x41, 0x54, 0x55, 0x52, 0x45, 0x5f, 0x53, - 0x55, 0x50, 0x50, 0x4f, 0x52, 0x54, 0x53, 0x5f, 0x45, 0x44, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x53, - 0x10, 0x02, 0x42, 0x72, 0x0a, 0x1c, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, - 0x65, 0x72, 0x42, 0x0c, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x73, - 0x5a, 0x29, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, - 0x6f, 0x72, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x79, 0x70, - 0x65, 0x73, 0x2f, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x70, 0x62, 0xaa, 0x02, 0x18, 0x47, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x43, 0x6f, - 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, -} - -var ( - file_google_protobuf_compiler_plugin_proto_rawDescOnce sync.Once - file_google_protobuf_compiler_plugin_proto_rawDescData = file_google_protobuf_compiler_plugin_proto_rawDesc -) - -func file_google_protobuf_compiler_plugin_proto_rawDescGZIP() []byte { - file_google_protobuf_compiler_plugin_proto_rawDescOnce.Do(func() { - file_google_protobuf_compiler_plugin_proto_rawDescData = protoimpl.X.CompressGZIP(file_google_protobuf_compiler_plugin_proto_rawDescData) - }) - return file_google_protobuf_compiler_plugin_proto_rawDescData -} - -var file_google_protobuf_compiler_plugin_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_google_protobuf_compiler_plugin_proto_msgTypes = make([]protoimpl.MessageInfo, 4) -var file_google_protobuf_compiler_plugin_proto_goTypes = []interface{}{ - (CodeGeneratorResponse_Feature)(0), // 0: google.protobuf.compiler.CodeGeneratorResponse.Feature - (*Version)(nil), // 1: google.protobuf.compiler.Version - (*CodeGeneratorRequest)(nil), // 2: google.protobuf.compiler.CodeGeneratorRequest - (*CodeGeneratorResponse)(nil), // 3: google.protobuf.compiler.CodeGeneratorResponse - (*CodeGeneratorResponse_File)(nil), // 4: google.protobuf.compiler.CodeGeneratorResponse.File - (*descriptorpb.FileDescriptorProto)(nil), // 5: google.protobuf.FileDescriptorProto - (*descriptorpb.GeneratedCodeInfo)(nil), // 6: google.protobuf.GeneratedCodeInfo -} -var file_google_protobuf_compiler_plugin_proto_depIdxs = []int32{ - 5, // 0: google.protobuf.compiler.CodeGeneratorRequest.proto_file:type_name -> google.protobuf.FileDescriptorProto - 5, // 1: google.protobuf.compiler.CodeGeneratorRequest.source_file_descriptors:type_name -> google.protobuf.FileDescriptorProto - 1, // 2: google.protobuf.compiler.CodeGeneratorRequest.compiler_version:type_name -> google.protobuf.compiler.Version - 4, // 3: google.protobuf.compiler.CodeGeneratorResponse.file:type_name -> google.protobuf.compiler.CodeGeneratorResponse.File - 6, // 4: google.protobuf.compiler.CodeGeneratorResponse.File.generated_code_info:type_name -> google.protobuf.GeneratedCodeInfo - 5, // [5:5] is the sub-list for method output_type - 5, // [5:5] is the sub-list for method input_type - 5, // [5:5] is the sub-list for extension type_name - 5, // [5:5] is the sub-list for extension extendee - 0, // [0:5] is the sub-list for field type_name -} - -func init() { file_google_protobuf_compiler_plugin_proto_init() } -func file_google_protobuf_compiler_plugin_proto_init() { - if File_google_protobuf_compiler_plugin_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_google_protobuf_compiler_plugin_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Version); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_google_protobuf_compiler_plugin_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CodeGeneratorRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_google_protobuf_compiler_plugin_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CodeGeneratorResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_google_protobuf_compiler_plugin_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CodeGeneratorResponse_File); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_google_protobuf_compiler_plugin_proto_rawDesc, - NumEnums: 1, - NumMessages: 4, - NumExtensions: 0, - NumServices: 0, - }, - GoTypes: file_google_protobuf_compiler_plugin_proto_goTypes, - DependencyIndexes: file_google_protobuf_compiler_plugin_proto_depIdxs, - EnumInfos: file_google_protobuf_compiler_plugin_proto_enumTypes, - MessageInfos: file_google_protobuf_compiler_plugin_proto_msgTypes, - }.Build() - File_google_protobuf_compiler_plugin_proto = out.File - file_google_protobuf_compiler_plugin_proto_rawDesc = nil - file_google_protobuf_compiler_plugin_proto_goTypes = nil - file_google_protobuf_compiler_plugin_proto_depIdxs = nil -} diff --git a/vendor/knative.dev/hack/OWNERS b/vendor/knative.dev/hack/OWNERS new file mode 100644 index 00000000000..4d20bf8cffe --- /dev/null +++ b/vendor/knative.dev/hack/OWNERS @@ -0,0 +1,8 @@ +approvers: + - technical-oversight-committee + - productivity-writers + - knative-release-leads + +reviewers: + - productivity-writers + - productivity-reviewers diff --git a/vendor/knative.dev/hack/OWNERS_ALIASES b/vendor/knative.dev/hack/OWNERS_ALIASES new file mode 100644 index 00000000000..c6c29092ba3 --- /dev/null +++ b/vendor/knative.dev/hack/OWNERS_ALIASES @@ -0,0 +1,140 @@ +# This file is auto-generated from peribolos. +# Do not modify this file, instead modify peribolos/knative.yaml + +aliases: + client-reviewers: + - itsmurugappan + client-wg-leads: + - dsimansk + - rhuss + client-writers: + - dsimansk + - maximilien + - rhuss + - vyasgun + docs-reviewers: + - nainaz + - retocode + - skonto + docs-writers: + - csantanapr + - retocode + - skonto + eventing-reviewers: + - Leo6Leo + - aslom + - cali0707 + - creydr + eventing-wg-leads: + - pierDipi + eventing-writers: + - aliok + - cali0707 + - creydr + - lionelvillard + - matzew + - pierDipi + func-reviewers: + - jrangelramos + - nainaz + func-writers: + - gauron99 + - jrangelramos + - lance + - lkingland + - matejvasek + - matzew + - salaboy + functions-wg-leads: + - lkingland + - salaboy + knative-admin: + - aliok + - cardil + - davidhadas + - dprotaso + - dsimansk + - evankanderson + - knative-automation + - knative-prow-releaser-robot + - knative-prow-robot + - knative-prow-updater-robot + - knative-test-reporter-robot + - nainaz + - psschwei + - salaboy + - upodroid + knative-release-leads: [] + knative-robots: + - knative-automation + - knative-prow-releaser-robot + - knative-prow-robot + - knative-prow-updater-robot + - knative-test-reporter-robot + operations-reviewers: + - aliok + - houshengbo + - matzew + - maximilien + operations-wg-leads: + - houshengbo + operations-writers: + - aliok + - houshengbo + - matzew + - maximilien + productivity-leads: + - cardil + - upodroid + productivity-reviewers: + - evankanderson + - mgencur + productivity-wg-leads: + - cardil + - upodroid + productivity-writers: + - cardil + - upodroid + security-wg-leads: + - davidhadas + - evankanderson + security-writers: + - davidhadas + - evankanderson + serving-approvers: + - ReToCode + - skonto + serving-reviewers: + - izabelacg + - retocode + - skonto + serving-triage: + - izabelacg + - retocode + - skonto + serving-wg-leads: + - dprotaso + serving-writers: + - ReToCode + - dprotaso + - skonto + steering-committee: + - aliok + - evankanderson + - nainaz + - salaboy + technical-oversight-committee: + - davidhadas + - dprotaso + - dsimansk + - psschwei + ux-wg-leads: + - cali0707 + - leo6leo + - mmejia02 + - zainabhusain227 + ux-writers: + - cali0707 + - leo6leo + - mmejia02 + - zainabhusain227 diff --git a/vendor/modules.txt b/vendor/modules.txt index 6c3c5875fb0..9985d8d0284 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,15 +1,25 @@ -# cloud.google.com/go v0.72.0 -## explicit; go 1.11 -cloud.google.com/go -cloud.google.com/go/compute/metadata -cloud.google.com/go/iam +# cloud.google.com/go v0.110.0 +## explicit; go 1.19 cloud.google.com/go/internal cloud.google.com/go/internal/optional cloud.google.com/go/internal/trace cloud.google.com/go/internal/version -# cloud.google.com/go/storage v1.10.0 -## explicit; go 1.11 +# cloud.google.com/go/compute v1.19.1 +## explicit; go 1.19 +cloud.google.com/go/compute/internal +# cloud.google.com/go/compute/metadata v0.2.3 +## explicit; go 1.19 +cloud.google.com/go/compute/metadata +# cloud.google.com/go/iam v0.13.0 +## explicit; go 1.19 +cloud.google.com/go/iam +cloud.google.com/go/iam/apiv1/iampb +# cloud.google.com/go/storage v1.28.1 +## explicit; go 1.19 cloud.google.com/go/storage +cloud.google.com/go/storage/internal +cloud.google.com/go/storage/internal/apiv2 +cloud.google.com/go/storage/internal/apiv2/stubs # github.com/cloudevents/sdk-go/v2 v2.15.2 ## explicit; go 1.18 github.com/cloudevents/sdk-go/v2 @@ -28,14 +38,19 @@ github.com/cloudevents/sdk-go/v2/protocol/http github.com/cloudevents/sdk-go/v2/types # github.com/golang/protobuf v1.5.4 ## explicit; go 1.17 -github.com/golang/protobuf/internal/gengogrpc +github.com/golang/protobuf/jsonpb github.com/golang/protobuf/proto -github.com/golang/protobuf/protoc-gen-go -github.com/golang/protobuf/protoc-gen-go/descriptor github.com/golang/protobuf/ptypes github.com/golang/protobuf/ptypes/any github.com/golang/protobuf/ptypes/duration github.com/golang/protobuf/ptypes/timestamp +# github.com/google/go-cmp v0.5.9 +## explicit; go 1.13 +github.com/google/go-cmp/cmp +github.com/google/go-cmp/cmp/internal/diff +github.com/google/go-cmp/cmp/internal/flags +github.com/google/go-cmp/cmp/internal/function +github.com/google/go-cmp/cmp/internal/value # github.com/google/go-github v17.0.0+incompatible ## explicit github.com/google/go-github/github @@ -45,23 +60,25 @@ github.com/google/go-github/v32/github # github.com/google/go-querystring v1.0.0 ## explicit github.com/google/go-querystring/query -# github.com/google/uuid v1.2.0 +# github.com/google/uuid v1.3.0 ## explicit github.com/google/uuid -# github.com/googleapis/gax-go/v2 v2.0.5 -## explicit +# github.com/googleapis/enterprise-certificate-proxy v0.2.3 +## explicit; go 1.19 +github.com/googleapis/enterprise-certificate-proxy/client +github.com/googleapis/enterprise-certificate-proxy/client/util +# github.com/googleapis/gax-go/v2 v2.7.1 +## explicit; go 1.19 github.com/googleapis/gax-go/v2 +github.com/googleapis/gax-go/v2/apierror +github.com/googleapis/gax-go/v2/apierror/internal/proto +github.com/googleapis/gax-go/v2/internal # github.com/hashicorp/golang-lru v0.5.4 ## explicit; go 1.12 github.com/hashicorp/golang-lru/simplelru # github.com/json-iterator/go v1.1.10 ## explicit; go 1.12 github.com/json-iterator/go -# github.com/jstemmer/go-junit-report v0.9.1 -## explicit; go 1.2 -github.com/jstemmer/go-junit-report -github.com/jstemmer/go-junit-report/formatter -github.com/jstemmer/go-junit-report/parser # github.com/kelseyhightower/envconfig v1.4.0 ## explicit github.com/kelseyhightower/envconfig @@ -71,13 +88,14 @@ github.com/modern-go/concurrent # github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 ## explicit github.com/modern-go/reflect2 -# go.opencensus.io v0.23.0 => go.opencensus.io v0.20.2 +# go.opencensus.io v0.24.0 => go.opencensus.io v0.20.2 ## explicit go.opencensus.io go.opencensus.io/internal go.opencensus.io/internal/tagencoding go.opencensus.io/metric/metricdata go.opencensus.io/metric/metricproducer +go.opencensus.io/plugin/ocgrpc go.opencensus.io/plugin/ochttp go.opencensus.io/plugin/ochttp/propagation/b3 go.opencensus.io/resource @@ -114,33 +132,26 @@ golang.org/x/crypto/openpgp/packet golang.org/x/crypto/openpgp/s2k # golang.org/x/lint v0.0.0-20200302205851-738671d3881b ## explicit; go 1.11 -golang.org/x/lint -golang.org/x/lint/golint -# golang.org/x/mod v0.8.0 -## explicit; go 1.17 -golang.org/x/mod/internal/lazyregexp -golang.org/x/mod/module -golang.org/x/mod/semver # golang.org/x/net v0.23.0 ## explicit; go 1.18 golang.org/x/net/context -golang.org/x/net/context/ctxhttp golang.org/x/net/http/httpguts golang.org/x/net/http2 golang.org/x/net/http2/hpack golang.org/x/net/idna golang.org/x/net/internal/timeseries golang.org/x/net/trace -# golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5 -## explicit; go 1.11 +# golang.org/x/oauth2 v0.7.0 +## explicit; go 1.17 golang.org/x/oauth2 +golang.org/x/oauth2/authhandler golang.org/x/oauth2/google +golang.org/x/oauth2/google/internal/externalaccount golang.org/x/oauth2/internal golang.org/x/oauth2/jws golang.org/x/oauth2/jwt # golang.org/x/sys v0.18.0 ## explicit; go 1.18 -golang.org/x/sys/execabs golang.org/x/sys/unix # golang.org/x/text v0.14.0 ## explicit; go 1.18 @@ -148,28 +159,17 @@ golang.org/x/text/secure/bidirule golang.org/x/text/transform golang.org/x/text/unicode/bidi golang.org/x/text/unicode/norm -# golang.org/x/tools v0.6.0 -## explicit; go 1.18 -golang.org/x/tools/cmd/goimports -golang.org/x/tools/go/ast/astutil -golang.org/x/tools/go/gcexportdata -golang.org/x/tools/internal/event -golang.org/x/tools/internal/event/core -golang.org/x/tools/internal/event/keys -golang.org/x/tools/internal/event/label -golang.org/x/tools/internal/fastwalk -golang.org/x/tools/internal/gcimporter -golang.org/x/tools/internal/gocommand -golang.org/x/tools/internal/gopathwalk -golang.org/x/tools/internal/imports -golang.org/x/tools/internal/pkgbits -golang.org/x/tools/internal/tokeninternal -golang.org/x/tools/internal/typeparams -# google.golang.org/api v0.36.0 -## explicit; go 1.11 +# golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 +## explicit; go 1.17 +golang.org/x/xerrors +golang.org/x/xerrors/internal +# google.golang.org/api v0.114.0 +## explicit; go 1.19 google.golang.org/api/googleapi google.golang.org/api/googleapi/transport +google.golang.org/api/iamcredentials/v1 google.golang.org/api/internal +google.golang.org/api/internal/cert google.golang.org/api/internal/gensupport google.golang.org/api/internal/impersonate google.golang.org/api/internal/third_party/uritemplates @@ -177,10 +177,10 @@ google.golang.org/api/iterator google.golang.org/api/option google.golang.org/api/option/internaloption google.golang.org/api/storage/v1 -google.golang.org/api/transport/cert +google.golang.org/api/transport +google.golang.org/api/transport/grpc google.golang.org/api/transport/http google.golang.org/api/transport/http/internal/propagation -google.golang.org/api/transport/internal/dca # google.golang.org/appengine v1.6.7 ## explicit; go 1.11 google.golang.org/appengine @@ -191,44 +191,65 @@ google.golang.org/appengine/internal/datastore google.golang.org/appengine/internal/log google.golang.org/appengine/internal/modules google.golang.org/appengine/internal/remote_api +google.golang.org/appengine/internal/socket google.golang.org/appengine/internal/urlfetch +google.golang.org/appengine/socket google.golang.org/appengine/urlfetch -# google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d -## explicit; go 1.11 +# google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 +## explicit; go 1.19 +google.golang.org/genproto/googleapis/api google.golang.org/genproto/googleapis/api/annotations google.golang.org/genproto/googleapis/iam/v1 google.golang.org/genproto/googleapis/rpc/code +google.golang.org/genproto/googleapis/rpc/errdetails google.golang.org/genproto/googleapis/rpc/status +google.golang.org/genproto/googleapis/type/date google.golang.org/genproto/googleapis/type/expr -# google.golang.org/grpc v1.36.0 -## explicit; go 1.11 +# google.golang.org/grpc v1.56.3 +## explicit; go 1.17 google.golang.org/grpc google.golang.org/grpc/attributes google.golang.org/grpc/backoff google.golang.org/grpc/balancer google.golang.org/grpc/balancer/base +google.golang.org/grpc/balancer/grpclb +google.golang.org/grpc/balancer/grpclb/grpc_lb_v1 google.golang.org/grpc/balancer/grpclb/state google.golang.org/grpc/balancer/roundrobin google.golang.org/grpc/binarylog/grpc_binarylog_v1 +google.golang.org/grpc/channelz google.golang.org/grpc/codes google.golang.org/grpc/connectivity google.golang.org/grpc/credentials +google.golang.org/grpc/credentials/alts +google.golang.org/grpc/credentials/alts/internal +google.golang.org/grpc/credentials/alts/internal/authinfo +google.golang.org/grpc/credentials/alts/internal/conn +google.golang.org/grpc/credentials/alts/internal/handshaker +google.golang.org/grpc/credentials/alts/internal/handshaker/service +google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp +google.golang.org/grpc/credentials/google +google.golang.org/grpc/credentials/insecure +google.golang.org/grpc/credentials/oauth google.golang.org/grpc/encoding google.golang.org/grpc/encoding/proto google.golang.org/grpc/grpclog google.golang.org/grpc/internal google.golang.org/grpc/internal/backoff +google.golang.org/grpc/internal/balancer/gracefulswitch google.golang.org/grpc/internal/balancerload google.golang.org/grpc/internal/binarylog google.golang.org/grpc/internal/buffer google.golang.org/grpc/internal/channelz google.golang.org/grpc/internal/credentials google.golang.org/grpc/internal/envconfig +google.golang.org/grpc/internal/googlecloud google.golang.org/grpc/internal/grpclog google.golang.org/grpc/internal/grpcrand google.golang.org/grpc/internal/grpcsync google.golang.org/grpc/internal/grpcutil google.golang.org/grpc/internal/metadata +google.golang.org/grpc/internal/pretty google.golang.org/grpc/internal/resolver google.golang.org/grpc/internal/resolver/dns google.golang.org/grpc/internal/resolver/passthrough @@ -250,8 +271,7 @@ google.golang.org/grpc/status google.golang.org/grpc/tap # google.golang.org/protobuf v1.33.0 ## explicit; go 1.17 -google.golang.org/protobuf/cmd/protoc-gen-go/internal_gengo -google.golang.org/protobuf/compiler/protogen +google.golang.org/protobuf/encoding/protojson google.golang.org/protobuf/encoding/prototext google.golang.org/protobuf/encoding/protowire google.golang.org/protobuf/internal/descfmt @@ -259,6 +279,7 @@ google.golang.org/protobuf/internal/descopts google.golang.org/protobuf/internal/detrand google.golang.org/protobuf/internal/editiondefaults google.golang.org/protobuf/internal/encoding/defval +google.golang.org/protobuf/internal/encoding/json google.golang.org/protobuf/internal/encoding/messageset google.golang.org/protobuf/internal/encoding/tag google.golang.org/protobuf/internal/encoding/text @@ -268,7 +289,6 @@ google.golang.org/protobuf/internal/filetype google.golang.org/protobuf/internal/flags google.golang.org/protobuf/internal/genid google.golang.org/protobuf/internal/impl -google.golang.org/protobuf/internal/msgfmt google.golang.org/protobuf/internal/order google.golang.org/protobuf/internal/pragma google.golang.org/protobuf/internal/set @@ -276,19 +296,17 @@ google.golang.org/protobuf/internal/strs google.golang.org/protobuf/internal/version google.golang.org/protobuf/proto google.golang.org/protobuf/reflect/protodesc -google.golang.org/protobuf/reflect/protopath -google.golang.org/protobuf/reflect/protorange google.golang.org/protobuf/reflect/protoreflect google.golang.org/protobuf/reflect/protoregistry google.golang.org/protobuf/runtime/protoiface google.golang.org/protobuf/runtime/protoimpl google.golang.org/protobuf/types/descriptorpb -google.golang.org/protobuf/types/dynamicpb google.golang.org/protobuf/types/gofeaturespb google.golang.org/protobuf/types/known/anypb google.golang.org/protobuf/types/known/durationpb +google.golang.org/protobuf/types/known/emptypb +google.golang.org/protobuf/types/known/fieldmaskpb google.golang.org/protobuf/types/known/timestamppb -google.golang.org/protobuf/types/pluginpb # gopkg.in/go-playground/assert.v1 v1.2.1 ## explicit # gopkg.in/go-playground/webhooks.v3 v3.13.0 From ea250d242450a8f72a77e6e374db30ad86cb12eb Mon Sep 17 00:00:00 2001 From: SHRAVANI KAWARE <97099574+ShravaniAK@users.noreply.github.com> Date: Wed, 7 Aug 2024 18:49:11 +0530 Subject: [PATCH 18/26] alignment issued resolved on home page (#6072) --- overrides/assets/stylesheets/home.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/overrides/assets/stylesheets/home.css b/overrides/assets/stylesheets/home.css index 13b1db7f3e2..0e1e57b338b 100644 --- a/overrides/assets/stylesheets/home.css +++ b/overrides/assets/stylesheets/home.css @@ -388,8 +388,8 @@ position: relative; cursor: pointer; } -.case-studies-container h1 { - margin-bottom: 0.45em; +.md-typeset>h1:first-of-type { + margin:0; } .case-studies-container .cases-table { @@ -397,6 +397,7 @@ position: relative; justify-content: center; max-width: 100%; margin: 1rem; + margin-top: 0; align-items: center; } @@ -509,7 +510,6 @@ position: relative; /* cncf notice container css */ .cncf-notice-container { background-color: white; - padding-top: 1rem; } .cncf-notice-container h3 { From bf0e06d3097df4274de1703947c2b684c2898f8f Mon Sep 17 00:00:00 2001 From: SHRAVANI KAWARE <97099574+ShravaniAK@users.noreply.github.com> Date: Wed, 7 Aug 2024 18:51:44 +0530 Subject: [PATCH 19/26] improved blog and case study section (#5988) * improved blog and case study section * changed the alignment of line for mobile view * text, color and font family changes --- docs/about/case-studies/README.md | 23 +++++++++++++++++++ docs/about/testimonials.md | 4 ++-- docs/stylesheets/extra.css | 38 +++++++++++++++++++++---------- 3 files changed, 51 insertions(+), 14 deletions(-) diff --git a/docs/about/case-studies/README.md b/docs/about/case-studies/README.md index 3f6e8f4c5d9..60102889da5 100644 --- a/docs/about/case-studies/README.md +++ b/docs/about/case-studies/README.md @@ -4,6 +4,29 @@ hide: --- # Knative Case Studies + +
diff --git a/docs/about/testimonials.md b/docs/about/testimonials.md index 43d2fdfed09..f79907ce946 100644 --- a/docs/about/testimonials.md +++ b/docs/about/testimonials.md @@ -1,6 +1,6 @@
-

Enterprise-grade Serverless on your own terms.

-

Understanding Knative

+

Testimonials

+

Enterprise-grade Serverless on your own terms

diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css index 4a008bcd66b..df29f63b0bc 100644 --- a/docs/stylesheets/extra.css +++ b/docs/stylesheets/extra.css @@ -417,7 +417,7 @@ border-radius: 0.7rem 0 0 0 ; } .testimonials h1 { - color: var(--md-primary-fg-color--dark); + color:black; margin-bottom: -26px; } @@ -437,22 +437,19 @@ border-radius: 0.7rem 0 0 0 ; .testimonials .testimonial .img { margin: auto 30px auto 60px; + max-width: 130px; } .testimonials .quote { margin: auto 0; text-align: start; padding: 0 2em; - color: var(--md-primary-fg-color--light); + color: var(--md-primary-fg-color--dark); font-weight: 500; line-height: 1.1; - font-family: inherit; + font-family: serif; font-size: .85rem; - border-left: var(--md-default-fg-color--light) 4.5px solid; -} - -.testimonials .testimonial img { - max-width: 130px; + border-left: var(--md-primary-fg-color--dark) 4.5px solid; } .testimonials .testimonial.blue img { @@ -461,20 +458,21 @@ border-radius: 0.7rem 0 0 0 ; } .testimonials .testimonial.blue { - border-top: var(--md-primary-fg-color--light) 2.5px solid; + border-top: var(--md-primary-fg-color--dark) 2.5px solid; padding-top: 60px; } .testimonials .testimonial.blue .quote { font-size: 1.3rem; font-weight: 500; - color: var(--md-primary-fg-color--light); + font-family: serif; + color: var(--md-primary-fg-color--dark); border: none; } .testimonials .quote .phrase { font-size: 1.15rem; - font-style: italic; + font-style: serif; font-weight: bold; font-family: serif; } @@ -492,7 +490,23 @@ border-radius: 0.7rem 0 0 0 ; .testimonials .find-links { padding-top: 16px; } - +@media screen and (max-width: 530px){ +.testimonial{ + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} +.testimonials .quote { + padding: 1rem; + margin-top: 1rem; + border-left: none; + border-top: var(--md-primary-fg-color--dark) 4.5px solid; +} +.testimonials .testimonial .img { + margin: auto 30px auto 30px; +} +} @media screen and (max-width: 76.1875em) { .md-nav--primary .md-nav__item--active>.md-nav__link { color: var(--nav-item-color); From e0fec4fe5a1dc3efcd6c75037861d9faed81dc22 Mon Sep 17 00:00:00 2001 From: Knative Automation Date: Wed, 7 Aug 2024 21:36:26 -0400 Subject: [PATCH 20/26] Update community files (#6090) Signed-off-by: Knative Automation --- OWNERS_ALIASES | 1 + 1 file changed, 1 insertion(+) diff --git a/OWNERS_ALIASES b/OWNERS_ALIASES index c6c29092ba3..23c72f3d52b 100644 --- a/OWNERS_ALIASES +++ b/OWNERS_ALIASES @@ -28,6 +28,7 @@ aliases: eventing-wg-leads: - pierDipi eventing-writers: + - Leo6Leo - aliok - cali0707 - creydr From f9aff92357e7c88a07dbed8259281d98c9ff4806 Mon Sep 17 00:00:00 2001 From: Knative Automation Date: Thu, 8 Aug 2024 09:14:32 -0400 Subject: [PATCH 21/26] upgrade to latest dependencies (#6089) bumping knative.dev/hack 441a19f...452e340: > 452e340 Update community files (# 392) Signed-off-by: Knative Automation --- go.mod | 2 +- go.sum | 4 +- vendor/knative.dev/hack/OWNERS | 8 -- vendor/knative.dev/hack/OWNERS_ALIASES | 140 ------------------------- vendor/modules.txt | 2 +- 5 files changed, 4 insertions(+), 152 deletions(-) delete mode 100644 vendor/knative.dev/hack/OWNERS delete mode 100644 vendor/knative.dev/hack/OWNERS_ALIASES diff --git a/go.mod b/go.mod index 81f4e959eff..ad50c63b47f 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( google.golang.org/grpc v1.56.3 gopkg.in/go-playground/webhooks.v3 v3.13.0 gopkg.in/yaml.v2 v2.3.0 - knative.dev/hack v0.0.0-20240801232131-441a19fc9ead + knative.dev/hack v0.0.0-20240808014239-452e340cbb4b ) require ( diff --git a/go.sum b/go.sum index 9e3b4a10a27..58e7b5659e0 100644 --- a/go.sum +++ b/go.sum @@ -241,5 +241,5 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.5 h1:nI5egYTGJakVyOryqLs1cQO5dO0ksin5XXs2pspk75k= honnef.co/go/tools v0.0.1-2020.1.5/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -knative.dev/hack v0.0.0-20240801232131-441a19fc9ead h1:ViH1OEO0LViKa6W61YKUpLzOp7CJCFL9yLyIojHIuQ8= -knative.dev/hack v0.0.0-20240801232131-441a19fc9ead/go.mod h1:R0ritgYtjLDO9527h5vb5X6gfvt5LCrJ55BNbVDsWiY= +knative.dev/hack v0.0.0-20240808014239-452e340cbb4b h1:pDzlX6d8cCbp5PDU9BdEIPJVI/4HLTM4mV2gMN1bKlk= +knative.dev/hack v0.0.0-20240808014239-452e340cbb4b/go.mod h1:R0ritgYtjLDO9527h5vb5X6gfvt5LCrJ55BNbVDsWiY= diff --git a/vendor/knative.dev/hack/OWNERS b/vendor/knative.dev/hack/OWNERS deleted file mode 100644 index 4d20bf8cffe..00000000000 --- a/vendor/knative.dev/hack/OWNERS +++ /dev/null @@ -1,8 +0,0 @@ -approvers: - - technical-oversight-committee - - productivity-writers - - knative-release-leads - -reviewers: - - productivity-writers - - productivity-reviewers diff --git a/vendor/knative.dev/hack/OWNERS_ALIASES b/vendor/knative.dev/hack/OWNERS_ALIASES deleted file mode 100644 index c6c29092ba3..00000000000 --- a/vendor/knative.dev/hack/OWNERS_ALIASES +++ /dev/null @@ -1,140 +0,0 @@ -# This file is auto-generated from peribolos. -# Do not modify this file, instead modify peribolos/knative.yaml - -aliases: - client-reviewers: - - itsmurugappan - client-wg-leads: - - dsimansk - - rhuss - client-writers: - - dsimansk - - maximilien - - rhuss - - vyasgun - docs-reviewers: - - nainaz - - retocode - - skonto - docs-writers: - - csantanapr - - retocode - - skonto - eventing-reviewers: - - Leo6Leo - - aslom - - cali0707 - - creydr - eventing-wg-leads: - - pierDipi - eventing-writers: - - aliok - - cali0707 - - creydr - - lionelvillard - - matzew - - pierDipi - func-reviewers: - - jrangelramos - - nainaz - func-writers: - - gauron99 - - jrangelramos - - lance - - lkingland - - matejvasek - - matzew - - salaboy - functions-wg-leads: - - lkingland - - salaboy - knative-admin: - - aliok - - cardil - - davidhadas - - dprotaso - - dsimansk - - evankanderson - - knative-automation - - knative-prow-releaser-robot - - knative-prow-robot - - knative-prow-updater-robot - - knative-test-reporter-robot - - nainaz - - psschwei - - salaboy - - upodroid - knative-release-leads: [] - knative-robots: - - knative-automation - - knative-prow-releaser-robot - - knative-prow-robot - - knative-prow-updater-robot - - knative-test-reporter-robot - operations-reviewers: - - aliok - - houshengbo - - matzew - - maximilien - operations-wg-leads: - - houshengbo - operations-writers: - - aliok - - houshengbo - - matzew - - maximilien - productivity-leads: - - cardil - - upodroid - productivity-reviewers: - - evankanderson - - mgencur - productivity-wg-leads: - - cardil - - upodroid - productivity-writers: - - cardil - - upodroid - security-wg-leads: - - davidhadas - - evankanderson - security-writers: - - davidhadas - - evankanderson - serving-approvers: - - ReToCode - - skonto - serving-reviewers: - - izabelacg - - retocode - - skonto - serving-triage: - - izabelacg - - retocode - - skonto - serving-wg-leads: - - dprotaso - serving-writers: - - ReToCode - - dprotaso - - skonto - steering-committee: - - aliok - - evankanderson - - nainaz - - salaboy - technical-oversight-committee: - - davidhadas - - dprotaso - - dsimansk - - psschwei - ux-wg-leads: - - cali0707 - - leo6leo - - mmejia02 - - zainabhusain227 - ux-writers: - - cali0707 - - leo6leo - - mmejia02 - - zainabhusain227 diff --git a/vendor/modules.txt b/vendor/modules.txt index 9985d8d0284..2744788a88e 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -318,7 +318,7 @@ gopkg.in/go-playground/webhooks.v3/github gopkg.in/yaml.v2 # honnef.co/go/tools v0.0.1-2020.1.5 ## explicit; go 1.11 -# knative.dev/hack v0.0.0-20240801232131-441a19fc9ead +# knative.dev/hack v0.0.0-20240808014239-452e340cbb4b ## explicit; go 1.21 knative.dev/hack # go.opencensus.io => go.opencensus.io v0.20.2 From 0ff0007a049ffeb9f3930a7db521a221fd084810 Mon Sep 17 00:00:00 2001 From: Reto Lehmann Date: Fri, 9 Aug 2024 10:27:35 +0200 Subject: [PATCH 22/26] Improve startup probe hint about progress deadline (#6091) --- docs/serving/services/configure-probing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/serving/services/configure-probing.md b/docs/serving/services/configure-probing.md index e84736584af..2c4ed57d64b 100644 --- a/docs/serving/services/configure-probing.md +++ b/docs/serving/services/configure-probing.md @@ -90,7 +90,7 @@ Supported probe types are: ## Progress Deadline and Startup Probes -It is important to know that Knative has a deadline until a Knative Service should initially start up (or rollout). This is called [progress deadline](../configuration/deployment.md#configuring-progress-deadlines). When using Startup probes, the progress deadline is set to a value that is higher than the maximal Startup probe timeout (e.g. `initialDelaySeconds + success/failureThreshold` * `periodSeconds` * `timeoutSeconds`). Otherwise, the Startup probe might never pass before the progress deadline is reached, and the Service will never successfully start up. The Knative Service will then mark this in the status of the Service object: +It is important to know that Knative has a deadline until a Knative Service should initially start up (or rollout). This is called [progress deadline](../configuration/deployment.md#configuring-progress-deadlines). When using Startup probes, the user has to ensure that the progress deadline is set to a value that is higher than the maximum time the Startup probe can take. Consider your configuration of `initialDelaySeconds`, `success/failureThreshold`, `periodSeconds` and `timeoutSeconds` for this. Otherwise, the Startup probe might never pass before the progress deadline is reached, and the Service will never successfully start up. The Knative Service will then mark this in the status of the Service object: ```json [ From 3ba98cc6992d6c6ab18c59ca51d8d096ab6a9573 Mon Sep 17 00:00:00 2001 From: Calum Murray Date: Fri, 9 Aug 2024 09:57:12 -0400 Subject: [PATCH 23/26] feat: documented new trigger filters are GA (#6060) * feat: documented new trigger filters are GA Signed-off-by: Calum Murray * fix: formatting Signed-off-by: Calum Murray * cleanup: remove trigger filters feature file Signed-off-by: Calum Murray * fix: redirect should work for experimental-features/new-trigger-filters Signed-off-by: Calum Murray --------- Signed-off-by: Calum Murray --- config/nav.yml | 1 - config/redirects.yml | 3 +- docs/eventing/features/README.md | 1 - docs/eventing/features/new-trigger-filters.md | 188 ---------------- docs/eventing/triggers/README.md | 203 +++++++++++++++++- 5 files changed, 194 insertions(+), 202 deletions(-) delete mode 100644 docs/eventing/features/new-trigger-filters.md diff --git a/config/nav.yml b/config/nav.yml index a9721a60381..bf41f544666 100644 --- a/config/nav.yml +++ b/config/nav.yml @@ -297,7 +297,6 @@ nav: - About Eventing features: eventing/features/README.md - DeliverySpec.Timeout field: eventing/features/delivery-timeout.md - DeliverySpec.RetryAfterMax field: eventing/features/delivery-retryafter.md - - New Trigger Filters: eventing/features/new-trigger-filters.md - New APIServerSource Filters: eventing/features/new-apiserversource-filters.md - KReference.Group field: eventing/features/kreference-group.md - Knative reference mapping: eventing/features/kreference-mapping.md diff --git a/config/redirects.yml b/config/redirects.yml index 45cad385e94..3f1be0a181b 100644 --- a/config/redirects.yml +++ b/config/redirects.yml @@ -5,12 +5,13 @@ plugins: eventing/experimental-features/README.md: eventing/features/README.md eventing/experimental-features/delivery-timeout.md: eventing/features/delivery-timeout.md eventing/experimental-features/delivery-retryafter.md: eventing/features/delivery-retryafter.md - eventing/experimental-features/new-trigger-filters.md: eventing/features/new-trigger-filters.md + eventing/experimental-features/new-trigger-filters.md: eventing/triggers/README.md eventing/experimental-features/kreference-group.md: eventing/features/kreference-group.md eventing/experimental-features/kreference-mapping.md: eventing/features/kreference-mapping.md eventing/experimental-features/eventtype-auto-creation.md: eventing/features/eventtype-auto-creation.md eventing/experimental-features/transport-encryption.md: eventing/features/transport-encryption.md eventing/experimental-features/sender-identity.md: eventing/features/sender-identity.md + eventing/features/new-trigger-filters.md: eventing/triggers/README.md eventing/broker/kafka-broker/kafka-configmap.md: eventing/configuration/kafka-channel-configuration.md eventing/broker/create-mtbroker.md: eventing/brokers/create-broker.md eventing/broker/example-mtbroker.md: eventing/brokers/broker-developer-config-options.md diff --git a/docs/eventing/features/README.md b/docs/eventing/features/README.md index 7d94c7cc8fa..90e87bdb368 100644 --- a/docs/eventing/features/README.md +++ b/docs/eventing/features/README.md @@ -72,7 +72,6 @@ Knative Eventing: | [DeliverySpec.Timeout field](delivery-timeout.md) | `delivery-timeout` | When using the `delivery` spec to configure event delivery parameters, you can use the`timeout` field to specify the timeout for each sent HTTP request. | Beta, enabled by default | | [KReference.Group field](kreference-group.md) | `kreference-group` | Specify the API `group` of `KReference` resources without the API version. | Alpha, disabled by default | | [Knative reference mapping](kreference-mapping.md) | `kreference-mapping` | Provide mappings from a [Knative reference](https://github.com/knative/specs/blob/main/specs/eventing/overview.md#destination) to a templated URI. | Alpha, disabled by default | -| [New trigger filters](new-trigger-filters.md) | `new-trigger-filters` | Enables a new Trigger `filters` field that supports a set of powerful filter expressions. | Beta, enabled by default | | [Transport encryption](transport-encryption.md) | `transport-encryption` | Enables components to encrypt traffic using TLS by exposing HTTPS URL. | Beta, disabled by default | | [Sender Identity](sender-identity.md) | `authentication-oidc` | Enables Eventing sources to send authenticated requests and addressables to require authenticated requests. | Alpha, disabled by default | | [Eventing with Istio](istio-integration.md) | `istio` | Enables Eventing components to communicate with workloads in an Istio mesh. | Beta, disabled by default | diff --git a/docs/eventing/features/new-trigger-filters.md b/docs/eventing/features/new-trigger-filters.md deleted file mode 100644 index e57c8839d2a..00000000000 --- a/docs/eventing/features/new-trigger-filters.md +++ /dev/null @@ -1,188 +0,0 @@ -# New trigger filters - -**Flag name**: `new-trigger-filters` - -**Stage**: Beta, enabled by default - -**Tracking issue**: [#5204](https://github.com/knative/eventing/issues/5204) -## Overview -This feature enables a new `filters` field in Triggers that conforms to the filters API field defined in the [`CloudEvents Subscriptions API`](https://github.com/cloudevents/spec/blob/main/subscriptions/spec.md#324-filters). It allows users to specify a set of powerful filter expressions, where each expression evaluates to either true or false for each event. - -The following example shows a Trigger using the new `filters` field: - -```yaml -apiVersion: eventing.knative.dev/v1 -kind: Trigger -metadata: - name: my-service-trigger -spec: - broker: default - filters: - - cesql: "source LIKE '%commerce%' AND type IN ('order.created', 'order.updated', 'order.canceled')" - subscriber: - ref: - apiVersion: serving.knative.dev/v1 - kind: Service - name: my-service -``` - -## About the filters field -* An array of filter expressions that evaluates to true or false. If any filter expression in the array evaluates to false, the event will not be sent to the `subscriber`. -* Each filter expression follows a dialect that defines the type of filter and the set of additional properties that are allowed within the filter expression. - -## Supported filter dialects - -The `filters` field supports the following dialects: - -### `exact` - -CloudEvent attribute String value must exactly match the specified String value. Matching is case-sensitive. - -```yaml -apiVersion: eventing.knative.dev/v1 -kind: Trigger -metadata: - ... -spec: - ... - filters: - - exact: - type: com.github.push -``` - -### `prefix` - -CloudEvent attribute String value must start with the specified String value. Matching is case-sensitive. - -```yaml -apiVersion: eventing.knative.dev/v1 -kind: Trigger -metadata: - ... -spec: - ... - filters: - - prefix: - type: com.github. -``` - -### `suffix` - -CloudEvent attribute String value must end with the specified String value. Matching is case-sensitive. - -```yaml -apiVersion: eventing.knative.dev/v1 -kind: Trigger -metadata: - ... -spec: - ... - filters: - - suffix: - type: .created -``` - -### `all` - -All nested filter expressions must evaluate to true. - -```yaml -apiVersion: eventing.knative.dev/v1 -kind: Trigger -metadata: - ... -spec: - ... - filters: - - all: - - exact: - type: com.github.push - - exact: - subject: https://github.com/cloudevents/spec -``` - -### `any` - -At least one nested filter expression must evaluate to true. - -```yaml -apiVersion: eventing.knative.dev/v1 -kind: Trigger -metadata: - ... -spec: - ... - filters: - - any: - - exact: - type: com.github.push - - exact: - subject: https://github.com/cloudevents/spec -``` - -### `not` - -The nested expression evaluated must evaluate to false. - -```yaml -apiVersion: eventing.knative.dev/v1 -kind: Trigger -metadata: - ... -spec: - ... - filters: - - not: - exact: - type: com.github.push -``` -### `cesql` - -The provided [CloudEvents SQL Expression](https://github.com/cloudevents/spec/blob/main/cesql/spec.md) must evaluate to true. - -```yaml -apiVersion: eventing.knative.dev/v1 -kind: Trigger -metadata: - ... -spec: - ... - filters: - - cesql: "source LIKE '%commerce%' AND type IN ('order.created', 'order.updated', 'order.canceled')" -``` - -## Conflict with the current `filter` field - -The current `filter` field will continue to be supported. However, if you enable this feature and an object includes both `filter` and `filters`, the new `filters` field overrides the `filter` field. This allows you to try the new `filters` field without compromising existing filters, and you can introduce it to existing `Trigger` objects gradually. - -```yaml -apiVersion: eventing.knative.dev/v1 -kind: Trigger -metadata: - name: my-service-trigger -spec: - broker: default - # Current filter field. Will be ignored. - filter: - attributes: - type: dev.knative.foo.bar - myextension: my-extension-value - # Enhanced filters field. This will override the old filter field. - filters: - - cesql: "type = 'dev.knative.foo.bar' AND myextension = 'my-extension-value'" - subscriber: - ref: - apiVersion: serving.knative.dev/v1 - kind: Service - name: my-service -``` - -## FAQ - -### Why add yet another field? Why not make the current `filter` field more robust? - -The reason is twofold. First, at the time of developing `Trigger` APIs, there was no Subscriptions API in CloudEvents Project, so it makes sense to experiment with an API that is closer to the Subscriptions API. Second, we still want to support users workload with the old `filter` field, and give them the possibility to transition to the new `filters` field. - -### Why `filters` and not another name that wouldn't conflict with the `filter` field? - -We considered other names, such as `cefilters`, `subscriptionsAPIFilters`, or `enhancedFilters`, but we decided that this would be a step further from aligning with the Subscriptions API. Instead, we decided it is a good opportunity to conform with the Subscriptions API, at least at the field name level, and to leverage the safety of this being a feature. diff --git a/docs/eventing/triggers/README.md b/docs/eventing/triggers/README.md index 2915ceecaa3..f1daa2d89fa 100644 --- a/docs/eventing/triggers/README.md +++ b/docs/eventing/triggers/README.md @@ -62,16 +62,21 @@ delivers them to the custom path `/my-custom-path` for the Kubernetes service `m ## Trigger filtering -Exact match filtering on any number of CloudEvents attributes as well as -extensions are supported. If your filter sets multiple attributes, an event must -have all of the attributes for the trigger to filter it. Note that we only -support exact matching on string values. +Various forms of filtering based on any number of CloudEvents attributes and extensions +are supported. If multiple `filters` are provided, all of them must evaluate to true +in order for the event to be passed to the subscriber of the trigger. Note that we +do not support filtering on the `data` field of CloudEvents. + +!!! important + The filters described in this section are currently only supported in the Apache Kafka Broker + and the MTChannelBasedBroker. For other brokers, please refer to the [Legacy attribute filter](#legacy-attributes-filter). + ### Example This example filters events from the `default` broker that are of type -`dev.knative.foo.bar` and have the extension `myextension` with the value -`my-extension-value`. +`dev.knative.foo.bar` and have the extension `myextension` which ends +with `-extensions. 1. Create a YAML file using the following example: @@ -82,10 +87,11 @@ This example filters events from the `default` broker that are of type name: my-service-trigger spec: broker: default - filter: - attributes: + filters: + exact: type: dev.knative.foo.bar - myextension: my-extension-value + suffix: + myextension: -value subscriber: ref: apiVersion: serving.knative.dev/v1 @@ -100,9 +106,184 @@ This example filters events from the `default` broker that are of type ``` Where `` is the name of the file you created in the previous step. -### New trigger filters +### Supported filter dialects + +#### `exact` + +CloudEvent attribute String value must exactly match the specified String value. Matching is case-sensitive. +If the attribute is not a String, the filter will compare a String representation of the attribute to the +specified String value. + +```yaml +apiVersion: eventing.knative.dev/v1 +kind: Trigger +metadata: + ... +spec: + ... + filters: + - exact: + type: com.github.push +``` + +#### `prefix` + +CloudEvent attribute String value must start with the specified String value. Matching is case-sensitive. +If the attribute is not a String, the filter will compare a String representation of the attribute to the +specified String value. + +```yaml +apiVersion: eventing.knative.dev/v1 +kind: Trigger +metadata: + ... +spec: + ... + filters: + - prefix: + type: com.github. +``` + +#### `suffix` + +CloudEvent attribute String value must end with the specified String value. Matching is case-sensitive. +If the attribute is not a String, the filter will compare a String representation of the attribute to the +specified String value. + +```yaml +apiVersion: eventing.knative.dev/v1 +kind: Trigger +metadata: + ... +spec: + ... + filters: + - suffix: + type: .created +``` + +#### `all` + +All nested filter expressions must evaluate to true. + +```yaml +apiVersion: eventing.knative.dev/v1 +kind: Trigger +metadata: + ... +spec: + ... + filters: + - all: + - exact: + type: com.github.push + - exact: + subject: https://github.com/cloudevents/spec +``` + +#### `any` + +At least one nested filter expression must evaluate to true. + +```yaml +apiVersion: eventing.knative.dev/v1 +kind: Trigger +metadata: + ... +spec: + ... + filters: + - any: + - exact: + type: com.github.push + - exact: + subject: https://github.com/cloudevents/spec +``` + +#### `not` + +The nested expression evaluated must evaluate to false. + +```yaml +apiVersion: eventing.knative.dev/v1 +kind: Trigger +metadata: + ... +spec: + ... + filters: + - not: + exact: + type: com.github.push +``` +#### `cesql` + +The provided [CloudEvents SQL Expression](https://github.com/cloudevents/spec/blob/cesql/v1.0.0/cesql/spec.md) must evaluate to true. + +!!! important + Knative 1.15+ only supports the CloudEvents SQL v1.0 specification. Any CESQL expressions written prior to Knative v1.15 should + be verified, as there were some changes in the CESQL specification. + +```yaml +apiVersion: eventing.knative.dev/v1 +kind: Trigger +metadata: + ... +spec: + ... + filters: + - cesql: "source LIKE '%commerce%' AND type IN ('order.created', 'order.updated', 'order.canceled')" +``` + +### Legacy attributes filter + +The legacy attributes filter provides exact match filtering on any number of CloudEvents attributes as well as extensions. +It's semantics and behaviour are the same as the `exact` filter dialect and wherever possible users should move to the +`exact` filter. However, for backwards compatability the attributes filter will continue to work for all users. The following +example filters events from the `default` broker that are of type `dev.knative.foo.bar` and have the extension `myextension` +with the value `my-extension-value`. + +```yaml +apiVersion: eventing.knative.dev/v1 +kind: Trigger +metadata: + name: my-service-trigger +spec: + broker: default + filter: + attributes: + type: dev.knative.foo.bar + myextension: my-extension-value + subscriber: + ref: + apiVersion: serving.knative.dev/v1 + kind: Service + name: my-service +``` + +Whenver both the `filters` field and the `filter` field are both provided, the `filters` field will override the `filter` field. For example, +in the following trigger events with type `dev.knative.a` will be delivered, while events with type `dev.knative.b` will not. + +```yaml +apiVersion: eventing.knative.dev/v1 +kind: Trigger +metadata: + name: my-service-trigger +spec: + broker: default + filters: + exact: + type: dev.knative.a + filter: + attributes: + type: dev.knative.b + subscriber: + ref: + apiVersion: serving.knative.dev/v1 + kind: Service + name: my-service +``` -If you need more powerful filtering options, you can use the [new trigger filters](../features/new-trigger-filters.md). ## Trigger annotations You can modify a Trigger's behavior by setting the following two annotations: From e7073c52df776a35c35eea4b19bb81688c2c64ee Mon Sep 17 00:00:00 2001 From: Knative Automation Date: Thu, 15 Aug 2024 01:13:20 -0400 Subject: [PATCH 24/26] upgrade to latest dependencies (#6098) bumping knative.dev/hack 452e340...06f7aff: > 06f7aff tag images using ko (# 393) Signed-off-by: Knative Automation --- go.mod | 2 +- go.sum | 4 ++-- vendor/knative.dev/hack/release.sh | 2 ++ vendor/modules.txt | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index ad50c63b47f..007ad7c77e2 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( google.golang.org/grpc v1.56.3 gopkg.in/go-playground/webhooks.v3 v3.13.0 gopkg.in/yaml.v2 v2.3.0 - knative.dev/hack v0.0.0-20240808014239-452e340cbb4b + knative.dev/hack v0.0.0-20240814130635-06f7aff93954 ) require ( diff --git a/go.sum b/go.sum index 58e7b5659e0..27a2e985bcf 100644 --- a/go.sum +++ b/go.sum @@ -241,5 +241,5 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.5 h1:nI5egYTGJakVyOryqLs1cQO5dO0ksin5XXs2pspk75k= honnef.co/go/tools v0.0.1-2020.1.5/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -knative.dev/hack v0.0.0-20240808014239-452e340cbb4b h1:pDzlX6d8cCbp5PDU9BdEIPJVI/4HLTM4mV2gMN1bKlk= -knative.dev/hack v0.0.0-20240808014239-452e340cbb4b/go.mod h1:R0ritgYtjLDO9527h5vb5X6gfvt5LCrJ55BNbVDsWiY= +knative.dev/hack v0.0.0-20240814130635-06f7aff93954 h1:dGMK5VoL75szvrYQTL9NqhPYHu1f5dGaXx1hJI8fAFM= +knative.dev/hack v0.0.0-20240814130635-06f7aff93954/go.mod h1:R0ritgYtjLDO9527h5vb5X6gfvt5LCrJ55BNbVDsWiY= diff --git a/vendor/knative.dev/hack/release.sh b/vendor/knative.dev/hack/release.sh index 5cc8f323585..450c0671b11 100644 --- a/vendor/knative.dev/hack/release.sh +++ b/vendor/knative.dev/hack/release.sh @@ -694,6 +694,8 @@ function main() { (( SKIP_TESTS )) && echo "- Tests will NOT be run" || echo "- Tests will be run" if (( TAG_RELEASE )); then echo "- Artifacts will be tagged '${TAG}'" + # We want to add git tags to the container images built by ko + KO_FLAGS+=" --tags=latest,${TAG}" else echo "- Artifacts WILL NOT be tagged" fi diff --git a/vendor/modules.txt b/vendor/modules.txt index 2744788a88e..c6adbe23110 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -318,7 +318,7 @@ gopkg.in/go-playground/webhooks.v3/github gopkg.in/yaml.v2 # honnef.co/go/tools v0.0.1-2020.1.5 ## explicit; go 1.11 -# knative.dev/hack v0.0.0-20240808014239-452e340cbb4b +# knative.dev/hack v0.0.0-20240814130635-06f7aff93954 ## explicit; go 1.21 knative.dev/hack # go.opencensus.io => go.opencensus.io v0.20.2 From e3dcd55039d2d286c379afb3dda672a84ac8345b Mon Sep 17 00:00:00 2001 From: SHRAVANI KAWARE <97099574+ShravaniAK@users.noreply.github.com> Date: Wed, 21 Aug 2024 18:54:44 +0530 Subject: [PATCH 25/26] fixed the home page Footer mobile responsive issue (#5964) * fixed the home page mobile responsive issue * custom color and spacing * spacing * pipe --- overrides/assets/stylesheets/home.css | 40 +++++++++++++++------------ overrides/partials/footer.html | 18 ++++++++---- 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/overrides/assets/stylesheets/home.css b/overrides/assets/stylesheets/home.css index 0e1e57b338b..1ed4fdc4e07 100644 --- a/overrides/assets/stylesheets/home.css +++ b/overrides/assets/stylesheets/home.css @@ -383,7 +383,7 @@ position: relative; justify-content: center; color: black; display: flex; - background-color: #f3f1f2; + background-color: var(--md-primary-fg-color); padding: 1rem; cursor: pointer; } @@ -524,12 +524,6 @@ position: relative; margin: 1rem; } -@media only screen and (max-width: 1219px) { - .md-header__topic { - margin: 0; - } -} - @media only screen and (max-width: 800px) { .component-flex, .case-studies-container .cases-table { flex-wrap: wrap; @@ -537,8 +531,7 @@ position: relative; .knative-components-container .text-table .normal-text { width: 80%; - text-align: center; - + text-align: center; } .knative-components-container .text-table .normal-text:first-child { @@ -570,18 +563,26 @@ footer nav.md-footer__inner { .md-footer-meta{ padding: 1em 0; } + .md-footer-copyright{ margin-right: 18px; } + @media (max-width: 1024px){ -.md-footer-copyright{ - margin: auto; - text-align: center; -} -.md-social{ - margin: auto; -} + .md-header__topic { + margin: 0; + } + + .md-footer-copyright{ + margin: auto; + text-align: center; + } + + .md-social{ + margin: auto; + } } + @media (max-width: 861px) { .md-footer-meta{ flex-direction: column; @@ -596,6 +597,7 @@ footer nav.md-footer__inner { display: block; margin-bottom: 0.5rem; } + .md-footer__button { display: none; } @@ -610,6 +612,7 @@ footer nav.md-footer__inner { margin: 2rem; flex-wrap: wrap; } + .md-footer-copyright a{ margin: 8px; } @@ -618,10 +621,13 @@ footer nav.md-footer__inner { display: flex; flex-direction: column; order: 1; - } .md-social { margin-top: 1rem; } + + .pipe{ + display:none; + } } diff --git a/overrides/partials/footer.html b/overrides/partials/footer.html index 0a20993c4b5..85979139568 100644 --- a/overrides/partials/footer.html +++ b/overrides/partials/footer.html @@ -73,13 +73,19 @@
+
+ From 9919c4031d0569f6997a166317a46b472464eae2 Mon Sep 17 00:00:00 2001 From: "Jason (Jay) Smith" Date: Wed, 21 Aug 2024 15:35:23 -0700 Subject: [PATCH 26/26] Created a "Which Knative" page per Issue 5932 (#6055) * first pass at issue 5932 * added Knative Functions to which-knative.md --- docs/getting-started/which-knative.md | 60 +++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 docs/getting-started/which-knative.md diff --git a/docs/getting-started/which-knative.md b/docs/getting-started/which-knative.md new file mode 100644 index 00000000000..2c4eccf8944 --- /dev/null +++ b/docs/getting-started/which-knative.md @@ -0,0 +1,60 @@ +# Which Knative Component Should I Use? + +Knative is a project that simplifies the deployment of applications onto Kubernetes. Knative, as a project, contains a few different components. The purpose of this document is to explain them and advise on when you would use a specific component. + + +## Knative Serving + +[Knative Serving](https://knative.dev/docs/serving/) defines a set of objects as Kubernetes Custom Resource Definitions (CRDs). These resources are used to define and control how your serverless workload behaves on the cluster. + +In short, a user is able to deploy a containerized application on Kubernetes using Knative Serving. The Knative Serving components handle traffic routing, scaling, revision tracking as well as security and other configurations. It makes it easy to deploy applications on Kuberntes to where you don't even need to use Kubernetes. + +Knative Serving is best used for applications. Some examples are as follows: + +- frontend web applications +- backend services +- batch processes +- API serving +- AI Inferencing + +One thing worth noting is that most all of these services require an endpoint. While HTTP/S is the most common protocol, there are ways to get [gRPC to work](https://github.com/knative/docs/tree/main/code-samples/serving/grpc-ping-go). + +A simple question to ask is whether or not your service is invoked by an HTTP request. If it is, then Knative Serving is the component to utilize. + + + +## Knative Eventing + +[Knative Eventing](https://knative.dev/docs/eventing/) is a collection of APIs that enable you to use an [event-driven architecture](https://en.wikipedia.org/wiki/Event-driven_architecture) with your applications. You can use these APIs to create components that route events from event producers (known as sources) to event consumers (known as sinks) that receive events. Sinks can also be configured to respond to HTTP requests by sending a response event. + +With Knative Eventing, developers can simplify the binding of event sources to consumers. It acts as an abstraction between your services and the event sources that they must connect to. + +Currently, supported event sources are as follows + +- [API Server Source](https://knative.dev/docs/eventing/sources/apiserversource/) +- [Apache CouchDB](https://couchdb.apache.org/) +- [Apache Kafka](https://kafka.apache.org/) +- [Ceph](https://ceph.io) +- [ContainerSource](https://knative.dev/docs/eventing/custom-event-source/containersource/) +- [GitHub](https://github.com) +- [GitLab](https://gitlab.com) +- [Kogito] (https://kogito.kie.org/) +- [PingSource](https://knative.dev/docs/eventing/sources/ping-source/) +- [RabbitMQ](https://rabbitmq.com) +- [Redis](https://redis.io) +- [SinkBinding](https://knative.dev/docs/eventing/custom-event-source/sinkbinding/) + +There are a number of third-party sources that can be found [here](https://knative.dev/docs/eventing/sources/#third-party-sources). + +Knative Eventing isn't used for applications but rather to bind event producers with event consumers in a declarative way. You wouldn't use Knative Eventing to host a [Python Flask](https://flask.palletsprojects.com/en/3.0.x/) application for example. + +If you are wanting to declaratively bind an event source to your application, you will use Knative Eventing. In particular, if you are using any of the aforementioned applications as a messaging queue or database then you will use Eventing. + +## Knative Functions +A new addition to Knative are [Knative Functions](https://knative.dev/docs/functions/). This is meant for developers who are more familiar/comfortable with [Functions-as-a-Service (FaaS)](https://en.wikipedia.org/wiki/Function_as_a_service). + +Learning containerization does provide a learning curve for some and Knative Functions enables developers to focus purely on code. It is still Kubernetes under the hood so platform engineers still have the flexibility to design their platform. + +Since this is still Kubernetes under the hood, an [Open Container Initiative (OCI) format](https://opencontainers.org/about/overview/) container is still created and deployed. The key here is that the Knative Functions abstraction automates the creation and deployment of the container. + +This option is best for those whose developers may not be as familiar with OCI containers or if you want your developers to focus primarily on their code and not other primitives related to Knative or Kubernetes. \ No newline at end of file