Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
42cd1f8c4b | ||
|
|
1c02ed9115 | ||
|
|
dd8e532d18 | ||
|
|
505f302c96 | ||
|
|
f9dc3e5abf | ||
|
|
b58719b697 | ||
|
|
a3f0e90300 | ||
|
|
fb5b42171d |
No files matched your search
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
## 0.1.0 (Unreleased)
|
## 0.1.0 (October 14, 2020)
|
||||||
|
|
||||||
Initial release!
|
Initial release!
|
||||||
@@ -14,6 +14,12 @@ endif
|
|||||||
tools:
|
tools:
|
||||||
go generate -tags tools tools/tools.go
|
go generate -tags tools tools/tools.go
|
||||||
|
|
||||||
|
fmtcheck:
|
||||||
|
echo "Placeholder"
|
||||||
|
|
||||||
|
test:
|
||||||
|
echo "Placeholder"
|
||||||
|
|
||||||
# Run acceptance tests
|
# Run acceptance tests
|
||||||
testacc:
|
testacc:
|
||||||
TF_ACC=1 go test ./... -v $(TESTARGS) -timeout 120m
|
TF_ACC=1 go test ./... -v $(TESTARGS) -timeout 120m
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ require (
|
|||||||
github.com/circonus-labs/circonusllhist v0.1.4 // indirect
|
github.com/circonus-labs/circonusllhist v0.1.4 // indirect
|
||||||
github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe // indirect
|
github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe // indirect
|
||||||
github.com/golang/snappy v0.0.2 // indirect
|
github.com/golang/snappy v0.0.2 // indirect
|
||||||
github.com/hashicorp/boundary v0.1.0-beta.3.0.20201007181827-029468387634
|
github.com/hashicorp/boundary v0.1.0
|
||||||
github.com/hashicorp/boundary/api v0.0.1
|
github.com/hashicorp/boundary/api v0.0.1
|
||||||
github.com/hashicorp/boundary/sdk v0.0.1
|
github.com/hashicorp/boundary/sdk v0.0.1
|
||||||
github.com/hashicorp/go-immutable-radix v1.3.0 // indirect
|
github.com/hashicorp/go-immutable-radix v1.3.0 // indirect
|
||||||
@@ -27,7 +27,6 @@ require (
|
|||||||
github.com/hashicorp/terraform-plugin-docs v0.2.0
|
github.com/hashicorp/terraform-plugin-docs v0.2.0
|
||||||
github.com/hashicorp/terraform-plugin-sdk/v2 v2.0.4
|
github.com/hashicorp/terraform-plugin-sdk/v2 v2.0.4
|
||||||
github.com/hashicorp/yamux v0.0.0-20200609203250-aecfd211c9ce // indirect
|
github.com/hashicorp/yamux v0.0.0-20200609203250-aecfd211c9ce // indirect
|
||||||
github.com/mattn/go-colorable v0.1.8 // indirect
|
|
||||||
github.com/mitchellh/go-homedir v1.1.0
|
github.com/mitchellh/go-homedir v1.1.0
|
||||||
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
|
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
|
||||||
github.com/oklog/run v1.1.0 // indirect
|
github.com/oklog/run v1.1.0 // indirect
|
||||||
@@ -38,6 +37,5 @@ require (
|
|||||||
github.com/zclconf/go-cty v1.6.1 // indirect
|
github.com/zclconf/go-cty v1.6.1 // indirect
|
||||||
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0 // indirect
|
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0 // indirect
|
||||||
golang.org/x/sys v0.0.0-20201006155630-ac719f4daadf // indirect
|
golang.org/x/sys v0.0.0-20201006155630-ac719f4daadf // indirect
|
||||||
google.golang.org/genproto v0.0.0-20201006033701-bcad7cf615f2 // indirect
|
|
||||||
gopkg.in/ini.v1 v1.62.0 // indirect
|
gopkg.in/ini.v1 v1.62.0 // indirect
|
||||||
)
|
)
|
||||||
@@ -551,8 +551,8 @@ github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t
|
|||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.0.0-beta.5 h1:fhL1nRLxe6ppWSDwbDMhUIQVVJ8rxskTxWMBRJ8RRiI=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.0.0-beta.5 h1:fhL1nRLxe6ppWSDwbDMhUIQVVJ8rxskTxWMBRJ8RRiI=
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.0.0-beta.5/go.mod h1:fR9dOEfEyRM7ltVH0FTpK/QA6L/5BQq8izXNRu/gyVc=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.0.0-beta.5/go.mod h1:fR9dOEfEyRM7ltVH0FTpK/QA6L/5BQq8izXNRu/gyVc=
|
||||||
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
|
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
|
||||||
github.com/hashicorp/boundary v0.1.0-beta.3.0.20201007181827-029468387634 h1:8NVTqL8ppWa7B5eW7eKqkiUk9TA9BlktElTx4OI7g/k=
|
github.com/hashicorp/boundary v0.1.0 h1:ysUKg4jL+t76/GXa7IbuQ5qqOL1OuPVsQmSokEKEC4s=
|
||||||
github.com/hashicorp/boundary v0.1.0-beta.3.0.20201007181827-029468387634/go.mod h1:NBTvxwYHw4rzwxlIImh3J7Hjzm6uFEzmFAWs/JDKOqY=
|
github.com/hashicorp/boundary v0.1.0/go.mod h1:raqsV0ouf+MhN0dTDbJOYzlr4sywZRJi2kx5u5hisHU=
|
||||||
github.com/hashicorp/boundary/api v0.0.1 h1:lF6CjaOyOtLqqq1frIiyrNegk5lsthzjHL1PZnpnoMo=
|
github.com/hashicorp/boundary/api v0.0.1 h1:lF6CjaOyOtLqqq1frIiyrNegk5lsthzjHL1PZnpnoMo=
|
||||||
github.com/hashicorp/boundary/api v0.0.1/go.mod h1:78ARq+P7j7/lCOiSDMca5h+2AfZOaWD0MdZxzvvKKnM=
|
github.com/hashicorp/boundary/api v0.0.1/go.mod h1:78ARq+P7j7/lCOiSDMca5h+2AfZOaWD0MdZxzvvKKnM=
|
||||||
github.com/hashicorp/boundary/sdk v0.0.1 h1:ih8Zt/noZJqVkQBMI+EcEfACHoqbwW4r2y50bBcflyI=
|
github.com/hashicorp/boundary/sdk v0.0.1 h1:ih8Zt/noZJqVkQBMI+EcEfACHoqbwW4r2y50bBcflyI=
|
||||||
@@ -972,8 +972,8 @@ github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0
|
|||||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||||
github.com/pierrec/lz4 v2.5.2+incompatible h1:WCjObylUIOlKy/+7Abdn34TLIkXiA4UWUMhxq9m9ZXI=
|
github.com/pierrec/lz4 v2.5.2+incompatible h1:WCjObylUIOlKy/+7Abdn34TLIkXiA4UWUMhxq9m9ZXI=
|
||||||
github.com/pierrec/lz4 v2.5.2+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
github.com/pierrec/lz4 v2.5.2+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||||
github.com/pires/go-proxyproto v0.1.3 h1:2XEuhsQluSNA5QIQkiUv8PfgZ51sNYIQkq/yFquiSQM=
|
github.com/pires/go-proxyproto v0.2.0 h1:WyYKlv9pkt77b+LjMvPfwrsAxviaGCFhG4KDIy1ofLY=
|
||||||
github.com/pires/go-proxyproto v0.1.3/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9Gw5rnCjcwzAY=
|
github.com/pires/go-proxyproto v0.2.0/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9Gw5rnCjcwzAY=
|
||||||
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
|
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
@@ -1210,7 +1210,6 @@ golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPh
|
|||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200930160638-afb6bcd081ae/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
|
||||||
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 h1:hb9wdF1z5waM+dSIICn1l0DkLVDT3hqhhQsDNUmHPRE=
|
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 h1:hb9wdF1z5waM+dSIICn1l0DkLVDT3hqhhQsDNUmHPRE=
|
||||||
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
@@ -1458,9 +1457,10 @@ golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc
|
|||||||
golang.org/x/tools v0.0.0-20200827163409-021d7c6f1ec3/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
golang.org/x/tools v0.0.0-20200827163409-021d7c6f1ec3/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||||
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
|
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
|
||||||
golang.org/x/tools v0.0.0-20200921190806-0f52b63a40e8/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
golang.org/x/tools v0.0.0-20200921190806-0f52b63a40e8/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||||
golang.org/x/tools v0.0.0-20201001104356-43ebab892c4c/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
|
||||||
golang.org/x/tools v0.0.0-20201002184944-ecd9fd270d5d h1:vWQvJ/Z0Lu+9/8oQ/pAYXNzbc7CMnBl+tULGVHOy3oE=
|
golang.org/x/tools v0.0.0-20201002184944-ecd9fd270d5d h1:vWQvJ/Z0Lu+9/8oQ/pAYXNzbc7CMnBl+tULGVHOy3oE=
|
||||||
golang.org/x/tools v0.0.0-20201002184944-ecd9fd270d5d/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
golang.org/x/tools v0.0.0-20201002184944-ecd9fd270d5d/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||||
|
golang.org/x/tools v0.0.0-20201009032223-96877f285f7e h1:G1acLyqfyttmexrW7XPhzsaS8m6s+P9XsW9djwh10s4=
|
||||||
|
golang.org/x/tools v0.0.0-20201009032223-96877f285f7e/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
@@ -1539,10 +1539,9 @@ google.golang.org/genproto v0.0.0-20200827165113-ac2560b5e952/go.mod h1:FWY/as6D
|
|||||||
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/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-20200921165018-b9da36f5f452/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20200921165018-b9da36f5f452/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20200923140941-5646d36feee1/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20200923140941-5646d36feee1/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20201001141541-efaab9d3c4f7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
|
||||||
google.golang.org/genproto v0.0.0-20201002142447-3860012362da/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20201002142447-3860012362da/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20201006033701-bcad7cf615f2 h1:rBG1miiV00OG3NTbgxg42kPWohjVNn1sGhJyt4xyPLQ=
|
google.golang.org/genproto v0.0.0-20201009135657-4d944d34d83c h1:YhtyeaRgEDy6amoaijBY0B6uzaztIKKZbUcaO2OIFps=
|
||||||
google.golang.org/genproto v0.0.0-20201006033701-bcad7cf615f2/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20201009135657-4d944d34d83c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||||
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||||
|
|||||||
Executable
+31
@@ -0,0 +1,31 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# This script rewrites [GH-nnnn]-style references in the CHANGELOG.md file to
|
||||||
|
# be Markdown links to the given github issues.
|
||||||
|
#
|
||||||
|
# This is run during releases so that the issue references in all of the
|
||||||
|
# released items are presented as clickable links, but we can just use the
|
||||||
|
# easy [GH-nnnn] shorthand for quickly adding items to the "Unrelease" section
|
||||||
|
# while merging things between releases.
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [[ ! -f CHANGELOG.md ]]; then
|
||||||
|
echo "ERROR: CHANGELOG.md not found in pwd."
|
||||||
|
echo "Please run this from the root of the terraform provider repository"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ `uname` == "Darwin" ]]; then
|
||||||
|
echo "Using BSD sed"
|
||||||
|
SED="sed -i.bak -E -e"
|
||||||
|
else
|
||||||
|
echo "Using GNU sed"
|
||||||
|
SED="sed -i.bak -r -e"
|
||||||
|
fi
|
||||||
|
|
||||||
|
PROVIDER_URL="https:\/\/github.com\/terraform-providers\/terraform-provider-http\/issues"
|
||||||
|
|
||||||
|
$SED "s/GH-([0-9]+)/\[#\1\]\($PROVIDER_URL\/\1\)/g" -e 's/\[\[#(.+)([0-9])\)]$/(\[#\1\2))/g' CHANGELOG.md
|
||||||
|
|
||||||
|
rm CHANGELOG.md.bak
|
||||||
Generated
+11
@@ -0,0 +1,11 @@
|
|||||||
|
# Editors
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
*.swp
|
||||||
|
|
||||||
|
# Test files
|
||||||
|
*.test
|
||||||
|
coverage.txt
|
||||||
|
|
||||||
|
# Other
|
||||||
|
.DS_Store
|
||||||
+1695
File diff suppressed because it is too large.
Load diff
+44
@@ -0,0 +1,44 @@
|
|||||||
|
# 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/)
|
||||||
|
|
||||||
+260
@@ -0,0 +1,260 @@
|
|||||||
|
# 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
|
||||||
|
- Stackdriver Error Reporting 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 Stackdriver 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-<numberic project id>@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
|
||||||
+202
@@ -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.
|
||||||
+177
@@ -0,0 +1,177 @@
|
|||||||
|
# Google Cloud Client Libraries for Go
|
||||||
|
|
||||||
|
[](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/
|
||||||
+144
@@ -0,0 +1,144 @@
|
|||||||
|
# Setup 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).
|
||||||
|
|
||||||
|
# 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:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ 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`
|
||||||
|
|
||||||
|
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.
|
||||||
|
1. Navigate to `~/code/gocloud/` 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. `cd internal/version && go generate && cd -`
|
||||||
|
1. Commit the changes, push to your fork, and create a PR.
|
||||||
|
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`.
|
||||||
|
1. Run `go get cloud.google.com/go@vX.Y.Z` then wait for the release
|
||||||
|
to show up on http://pkg.go.dev/cloud.google.com/go (a few minutes).
|
||||||
|
1. Go to the [doc publishing job](http://go/google-cloud-go-publish-docs) and
|
||||||
|
trigger the job with the following environment variables:
|
||||||
|
`MODULE=cloud.google.com,VERSION=vX.Y.Z`.
|
||||||
|
Replace the version with the value for the module you're
|
||||||
|
releasing. See [`publish_docs.sh`](/internal/kokoro/publish_docs.sh).
|
||||||
|
|
||||||
|
# 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 `~/code/gocloud/` 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. `cd internal/version && go generate && cd -`
|
||||||
|
1. Commit the changes, push to your fork, and create a PR.
|
||||||
|
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`.
|
||||||
|
1. Run `go get cloud.google.com/go/datastore@vX.Y.Z` then wait for the release
|
||||||
|
to show up on http://pkg.go.dev/cloud.google.com/go/datastore (a few
|
||||||
|
minutes).
|
||||||
|
1. Go to the [doc publishing job](http://go/google-cloud-go-publish-docs) and
|
||||||
|
trigger the job with the following environment variables:
|
||||||
|
`MODULE=cloud.google.com/go/datastore,VERSION=vX.Y.Z`.
|
||||||
|
Replace the module path and version with the values for the module you're
|
||||||
|
releasing. You can leave all of the other fields blank.
|
||||||
|
See [`publish_docs.sh`](/internal/kokoro/publish_docs.sh).
|
||||||
|
|
||||||
|
# Appendix
|
||||||
|
|
||||||
|
1: This should get better as submodule tooling matures.
|
||||||
+519
@@ -0,0 +1,519 @@
|
|||||||
|
// 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 metadata provides access to Google Compute Engine (GCE)
|
||||||
|
// 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.
|
||||||
|
package metadata // import "cloud.google.com/go/compute/metadata"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// metadataIP is the documented metadata server IP address.
|
||||||
|
metadataIP = "169.254.169.254"
|
||||||
|
|
||||||
|
// metadataHostEnv is the environment variable specifying the
|
||||||
|
// GCE metadata hostname. If empty, the default value of
|
||||||
|
// metadataIP ("169.254.169.254") is used instead.
|
||||||
|
// This is variable name is not defined by any spec, as far as
|
||||||
|
// I know; it was made up for the Go package.
|
||||||
|
metadataHostEnv = "GCE_METADATA_HOST"
|
||||||
|
|
||||||
|
userAgent = "gcloud-golang/0.1"
|
||||||
|
)
|
||||||
|
|
||||||
|
type cachedValue struct {
|
||||||
|
k string
|
||||||
|
trim bool
|
||||||
|
mu sync.Mutex
|
||||||
|
v string
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
projID = &cachedValue{k: "project/project-id", trim: true}
|
||||||
|
projNum = &cachedValue{k: "project/numeric-project-id", trim: true}
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
|
||||||
|
// NotDefinedError is returned when requested metadata is not defined.
|
||||||
|
//
|
||||||
|
// The underlying string is the suffix after "/computeMetadata/v1/".
|
||||||
|
//
|
||||||
|
// This error is not returned if the value is defined to be the empty
|
||||||
|
// string.
|
||||||
|
type NotDefinedError string
|
||||||
|
|
||||||
|
func (suffix NotDefinedError) Error() string {
|
||||||
|
return fmt.Sprintf("metadata: GCE metadata %q not defined", string(suffix))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cachedValue) get(cl *Client) (v string, err error) {
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
c.mu.Lock()
|
||||||
|
if c.v != "" {
|
||||||
|
return c.v, nil
|
||||||
|
}
|
||||||
|
if c.trim {
|
||||||
|
v, err = cl.getTrimmed(c.k)
|
||||||
|
} else {
|
||||||
|
v, err = cl.Get(c.k)
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
c.v = v
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
onGCEOnce sync.Once
|
||||||
|
onGCE bool
|
||||||
|
)
|
||||||
|
|
||||||
|
// OnGCE reports whether this process is running on Google Compute Engine.
|
||||||
|
func OnGCE() bool {
|
||||||
|
onGCEOnce.Do(initOnGCE)
|
||||||
|
return onGCE
|
||||||
|
}
|
||||||
|
|
||||||
|
func initOnGCE() {
|
||||||
|
onGCE = testOnGCE()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testOnGCE() bool {
|
||||||
|
// The user explicitly said they're on GCE, so trust them.
|
||||||
|
if os.Getenv(metadataHostEnv) != "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
resc := make(chan bool, 2)
|
||||||
|
|
||||||
|
// Try two strategies in parallel.
|
||||||
|
// See https://github.com/googleapis/google-cloud-go/issues/194
|
||||||
|
go func() {
|
||||||
|
req, _ := http.NewRequest("GET", "http://"+metadataIP, nil)
|
||||||
|
req.Header.Set("User-Agent", userAgent)
|
||||||
|
res, err := defaultClient.hc.Do(req.WithContext(ctx))
|
||||||
|
if err != nil {
|
||||||
|
resc <- false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
resc <- res.Header.Get("Metadata-Flavor") == "Google"
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
addrs, err := net.DefaultResolver.LookupHost(ctx, "metadata.google.internal")
|
||||||
|
if err != nil || len(addrs) == 0 {
|
||||||
|
resc <- false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resc <- strsContains(addrs, metadataIP)
|
||||||
|
}()
|
||||||
|
|
||||||
|
tryHarder := systemInfoSuggestsGCE()
|
||||||
|
if tryHarder {
|
||||||
|
res := <-resc
|
||||||
|
if res {
|
||||||
|
// The first strategy succeeded, so let's use it.
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// Wait for either the DNS or metadata server probe to
|
||||||
|
// contradict the other one and say we are running on
|
||||||
|
// GCE. Give it a lot of time to do so, since the system
|
||||||
|
// info already suggests we're running on a GCE BIOS.
|
||||||
|
timer := time.NewTimer(5 * time.Second)
|
||||||
|
defer timer.Stop()
|
||||||
|
select {
|
||||||
|
case res = <-resc:
|
||||||
|
return res
|
||||||
|
case <-timer.C:
|
||||||
|
// Too slow. Who knows what this system is.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// There's no hint from the system info that we're running on
|
||||||
|
// GCE, so use the first probe's result as truth, whether it's
|
||||||
|
// true or false. The goal here is to optimize for speed for
|
||||||
|
// users who are NOT running on GCE. We can't assume that
|
||||||
|
// either a DNS lookup or an HTTP request to a blackholed IP
|
||||||
|
// address is fast. Worst case this should return when the
|
||||||
|
// metaClient's Transport.ResponseHeaderTimeout or
|
||||||
|
// Transport.Dial.Timeout fires (in two seconds).
|
||||||
|
return <-resc
|
||||||
|
}
|
||||||
|
|
||||||
|
// systemInfoSuggestsGCE reports whether the local system (without
|
||||||
|
// doing network requests) suggests that we're running on GCE. If this
|
||||||
|
// returns true, testOnGCE tries a bit harder to reach its metadata
|
||||||
|
// server.
|
||||||
|
func systemInfoSuggestsGCE() bool {
|
||||||
|
if runtime.GOOS != "linux" {
|
||||||
|
// We don't have any non-Linux clues available, at least yet.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
slurp, _ := ioutil.ReadFile("/sys/class/dmi/id/product_name")
|
||||||
|
name := strings.TrimSpace(string(slurp))
|
||||||
|
return name == "Google" || name == "Google Compute Engine"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subscribe calls Client.Subscribe on the default client.
|
||||||
|
func Subscribe(suffix string, fn func(v string, ok bool) error) error {
|
||||||
|
return defaultClient.Subscribe(suffix, fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get calls Client.Get on the default client.
|
||||||
|
func Get(suffix string) (string, error) { return defaultClient.Get(suffix) }
|
||||||
|
|
||||||
|
// ProjectID returns the current instance's project ID string.
|
||||||
|
func ProjectID() (string, error) { return defaultClient.ProjectID() }
|
||||||
|
|
||||||
|
// NumericProjectID returns the current instance's numeric project ID.
|
||||||
|
func NumericProjectID() (string, error) { return defaultClient.NumericProjectID() }
|
||||||
|
|
||||||
|
// InternalIP returns the instance's primary internal IP address.
|
||||||
|
func InternalIP() (string, error) { return defaultClient.InternalIP() }
|
||||||
|
|
||||||
|
// ExternalIP returns the instance's primary external (public) IP address.
|
||||||
|
func ExternalIP() (string, error) { return defaultClient.ExternalIP() }
|
||||||
|
|
||||||
|
// Email calls Client.Email on the default client.
|
||||||
|
func Email(serviceAccount string) (string, error) { return defaultClient.Email(serviceAccount) }
|
||||||
|
|
||||||
|
// Hostname returns the instance's hostname. This will be of the form
|
||||||
|
// "<instanceID>.c.<projID>.internal".
|
||||||
|
func Hostname() (string, error) { return defaultClient.Hostname() }
|
||||||
|
|
||||||
|
// InstanceTags returns the list of user-defined instance tags,
|
||||||
|
// assigned when initially creating a GCE instance.
|
||||||
|
func InstanceTags() ([]string, error) { return defaultClient.InstanceTags() }
|
||||||
|
|
||||||
|
// InstanceID returns the current VM's numeric instance ID.
|
||||||
|
func InstanceID() (string, error) { return defaultClient.InstanceID() }
|
||||||
|
|
||||||
|
// InstanceName returns the current VM's instance ID string.
|
||||||
|
func InstanceName() (string, error) { return defaultClient.InstanceName() }
|
||||||
|
|
||||||
|
// Zone returns the current VM's zone, such as "us-central1-b".
|
||||||
|
func Zone() (string, error) { return defaultClient.Zone() }
|
||||||
|
|
||||||
|
// InstanceAttributes calls Client.InstanceAttributes on the default client.
|
||||||
|
func InstanceAttributes() ([]string, error) { return defaultClient.InstanceAttributes() }
|
||||||
|
|
||||||
|
// ProjectAttributes calls Client.ProjectAttributes on the default client.
|
||||||
|
func ProjectAttributes() ([]string, error) { return defaultClient.ProjectAttributes() }
|
||||||
|
|
||||||
|
// InstanceAttributeValue calls Client.InstanceAttributeValue on the default client.
|
||||||
|
func InstanceAttributeValue(attr string) (string, error) {
|
||||||
|
return defaultClient.InstanceAttributeValue(attr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProjectAttributeValue calls Client.ProjectAttributeValue on the default client.
|
||||||
|
func ProjectAttributeValue(attr string) (string, error) {
|
||||||
|
return defaultClient.ProjectAttributeValue(attr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scopes calls Client.Scopes on the default client.
|
||||||
|
func Scopes(serviceAccount string) ([]string, error) { return defaultClient.Scopes(serviceAccount) }
|
||||||
|
|
||||||
|
func strsContains(ss []string, s string) bool {
|
||||||
|
for _, v := range ss {
|
||||||
|
if v == s {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Client provides metadata.
|
||||||
|
type Client struct {
|
||||||
|
hc *http.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClient returns a Client that can be used to fetch metadata.
|
||||||
|
// Returns the client that uses the specified http.Client for HTTP requests.
|
||||||
|
// If nil is specified, returns the default client.
|
||||||
|
func NewClient(c *http.Client) *Client {
|
||||||
|
if c == nil {
|
||||||
|
return defaultClient
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Client{hc: c}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
// 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
|
||||||
|
// variable GCE_METADATA_HOST is first inspected to decide where metadata
|
||||||
|
// requests shall go.
|
||||||
|
host := os.Getenv(metadataHostEnv)
|
||||||
|
if host == "" {
|
||||||
|
// Using 169.254.169.254 instead of "metadata" here because Go
|
||||||
|
// binaries built with the "netgo" tag and without cgo won't
|
||||||
|
// know the search suffix for "metadata" is
|
||||||
|
// ".google.internal", and this IP address is documented as
|
||||||
|
// being stable anyway.
|
||||||
|
host = metadataIP
|
||||||
|
}
|
||||||
|
suffix = strings.TrimLeft(suffix, "/")
|
||||||
|
u := "http://" + host + "/computeMetadata/v1/" + suffix
|
||||||
|
req, err := http.NewRequest("GET", u, nil)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
req.Header.Set("Metadata-Flavor", "Google")
|
||||||
|
req.Header.Set("User-Agent", userAgent)
|
||||||
|
res, err := c.hc.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
if res.StatusCode == http.StatusNotFound {
|
||||||
|
return "", "", NotDefinedError(suffix)
|
||||||
|
}
|
||||||
|
all, err := ioutil.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
if res.StatusCode != 200 {
|
||||||
|
return "", "", &Error{Code: res.StatusCode, Message: string(all)}
|
||||||
|
}
|
||||||
|
return string(all), res.Header.Get("Etag"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns a value from the metadata service.
|
||||||
|
// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
|
||||||
|
//
|
||||||
|
// If the GCE_METADATA_HOST environment variable is not defined, a default of
|
||||||
|
// 169.254.169.254 will be used instead.
|
||||||
|
//
|
||||||
|
// If the requested metadata is not defined, the returned error will
|
||||||
|
// be of type NotDefinedError.
|
||||||
|
func (c *Client) Get(suffix string) (string, error) {
|
||||||
|
val, _, err := c.getETag(suffix)
|
||||||
|
return val, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) getTrimmed(suffix string) (s string, err error) {
|
||||||
|
s, err = c.Get(suffix)
|
||||||
|
s = strings.TrimSpace(s)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) lines(suffix string) ([]string, error) {
|
||||||
|
j, err := c.Get(suffix)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
s := strings.Split(strings.TrimSpace(j), "\n")
|
||||||
|
for i := range s {
|
||||||
|
s[i] = strings.TrimSpace(s[i])
|
||||||
|
}
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProjectID returns the current instance's project ID string.
|
||||||
|
func (c *Client) ProjectID() (string, error) { return projID.get(c) }
|
||||||
|
|
||||||
|
// NumericProjectID returns the current instance's numeric project ID.
|
||||||
|
func (c *Client) NumericProjectID() (string, error) { return projNum.get(c) }
|
||||||
|
|
||||||
|
// InstanceID returns the current VM's numeric instance ID.
|
||||||
|
func (c *Client) InstanceID() (string, error) { return instID.get(c) }
|
||||||
|
|
||||||
|
// InternalIP returns the instance's primary internal IP address.
|
||||||
|
func (c *Client) InternalIP() (string, error) {
|
||||||
|
return c.getTrimmed("instance/network-interfaces/0/ip")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Email returns the email address associated with the service account.
|
||||||
|
// The account may be empty or the string "default" to use the instance's
|
||||||
|
// main account.
|
||||||
|
func (c *Client) Email(serviceAccount string) (string, error) {
|
||||||
|
if serviceAccount == "" {
|
||||||
|
serviceAccount = "default"
|
||||||
|
}
|
||||||
|
return c.getTrimmed("instance/service-accounts/" + serviceAccount + "/email")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExternalIP returns the instance's primary external (public) IP address.
|
||||||
|
func (c *Client) ExternalIP() (string, error) {
|
||||||
|
return c.getTrimmed("instance/network-interfaces/0/access-configs/0/external-ip")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hostname returns the instance's hostname. This will be of the form
|
||||||
|
// "<instanceID>.c.<projID>.internal".
|
||||||
|
func (c *Client) Hostname() (string, error) {
|
||||||
|
return c.getTrimmed("instance/hostname")
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstanceTags returns the list of user-defined instance tags,
|
||||||
|
// assigned when initially creating a GCE instance.
|
||||||
|
func (c *Client) InstanceTags() ([]string, error) {
|
||||||
|
var s []string
|
||||||
|
j, err := c.Get("instance/tags")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := json.NewDecoder(strings.NewReader(j)).Decode(&s); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstanceName returns the current VM's instance ID string.
|
||||||
|
func (c *Client) InstanceName() (string, error) {
|
||||||
|
return c.getTrimmed("instance/name")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zone returns the current VM's zone, such as "us-central1-b".
|
||||||
|
func (c *Client) Zone() (string, error) {
|
||||||
|
zone, err := c.getTrimmed("instance/zone")
|
||||||
|
// zone is of the form "projects/<projNum>/zones/<zoneName>".
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return zone[strings.LastIndex(zone, "/")+1:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// InstanceAttributes returns the list of user-defined attributes,
|
||||||
|
// assigned when initially creating a GCE VM instance. The value of an
|
||||||
|
// attribute can be obtained with InstanceAttributeValue.
|
||||||
|
func (c *Client) InstanceAttributes() ([]string, error) { return c.lines("instance/attributes/") }
|
||||||
|
|
||||||
|
// ProjectAttributes returns the list of user-defined attributes
|
||||||
|
// applying to the project as a whole, not just this VM. The value of
|
||||||
|
// an attribute can be obtained with ProjectAttributeValue.
|
||||||
|
func (c *Client) ProjectAttributes() ([]string, error) { return c.lines("project/attributes/") }
|
||||||
|
|
||||||
|
// InstanceAttributeValue returns the value of the provided VM
|
||||||
|
// instance attribute.
|
||||||
|
//
|
||||||
|
// If the requested attribute is not defined, the returned error will
|
||||||
|
// be of type NotDefinedError.
|
||||||
|
//
|
||||||
|
// InstanceAttributeValue may return ("", nil) if the attribute was
|
||||||
|
// defined to be the empty string.
|
||||||
|
func (c *Client) InstanceAttributeValue(attr string) (string, error) {
|
||||||
|
return c.Get("instance/attributes/" + attr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProjectAttributeValue returns the value of the provided
|
||||||
|
// project attribute.
|
||||||
|
//
|
||||||
|
// If the requested attribute is not defined, the returned error will
|
||||||
|
// be of type NotDefinedError.
|
||||||
|
//
|
||||||
|
// ProjectAttributeValue may return ("", nil) if the attribute was
|
||||||
|
// defined to be the empty string.
|
||||||
|
func (c *Client) ProjectAttributeValue(attr string) (string, error) {
|
||||||
|
return c.Get("project/attributes/" + attr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scopes returns the service account scopes for the given account.
|
||||||
|
// The account may be empty or the string "default" to use the instance's
|
||||||
|
// main account.
|
||||||
|
func (c *Client) Scopes(serviceAccount string) ([]string, error) {
|
||||||
|
if serviceAccount == "" {
|
||||||
|
serviceAccount = "default"
|
||||||
|
}
|
||||||
|
return c.lines("instance/service-accounts/" + serviceAccount + "/scopes")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subscribe subscribes to a value from the metadata service.
|
||||||
|
// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
|
||||||
|
// The suffix may contain query parameters.
|
||||||
|
//
|
||||||
|
// Subscribe calls fn with the latest metadata value indicated by the provided
|
||||||
|
// suffix. If the metadata value is deleted, fn is called with the empty string
|
||||||
|
// and ok false. Subscribe blocks until fn returns a non-nil error or the value
|
||||||
|
// is deleted. Subscribe returns the error value returned from the last call to
|
||||||
|
// fn, which may be nil when ok == false.
|
||||||
|
func (c *Client) Subscribe(suffix string, fn func(v string, ok bool) error) error {
|
||||||
|
const failedSubscribeSleep = time.Second * 5
|
||||||
|
|
||||||
|
// First check to see if the metadata value exists at all.
|
||||||
|
val, lastETag, err := c.getETag(suffix)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := fn(val, true); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ok := true
|
||||||
|
if strings.ContainsRune(suffix, '?') {
|
||||||
|
suffix += "&wait_for_change=true&last_etag="
|
||||||
|
} else {
|
||||||
|
suffix += "?wait_for_change=true&last_etag="
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
val, etag, err := c.getETag(suffix + url.QueryEscape(lastETag))
|
||||||
|
if err != nil {
|
||||||
|
if _, deleted := err.(NotDefinedError); !deleted {
|
||||||
|
time.Sleep(failedSubscribeSleep)
|
||||||
|
continue // Retry on other errors.
|
||||||
|
}
|
||||||
|
ok = false
|
||||||
|
}
|
||||||
|
lastETag = etag
|
||||||
|
|
||||||
|
if err := fn(val, ok); err != nil || !ok {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error contains an error response from the server.
|
||||||
|
type Error struct {
|
||||||
|
// Code is the HTTP response status code.
|
||||||
|
Code int
|
||||||
|
// Message is the server response message.
|
||||||
|
Message string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Error) Error() string {
|
||||||
|
return fmt.Sprintf("compute: Received %d `%s`", e.Code, e.Message)
|
||||||
|
}
|
||||||
+109
@@ -0,0 +1,109 @@
|
|||||||
|
// 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"
|
||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
module cloud.google.com/go
|
||||||
|
|
||||||
|
go 1.11
|
||||||
|
|
||||||
|
require (
|
||||||
|
cloud.google.com/go/storage v1.10.0
|
||||||
|
github.com/golang/mock v1.4.4
|
||||||
|
github.com/golang/protobuf v1.4.2
|
||||||
|
github.com/google/go-cmp v0.5.2
|
||||||
|
github.com/google/martian/v3 v3.0.0
|
||||||
|
github.com/google/pprof v0.0.0-20200905233945-acf8798be1f7
|
||||||
|
github.com/googleapis/gax-go/v2 v2.0.5
|
||||||
|
github.com/jstemmer/go-junit-report v0.9.1
|
||||||
|
go.opencensus.io v0.22.4
|
||||||
|
golang.org/x/lint v0.0.0-20200302205851-738671d3881b
|
||||||
|
golang.org/x/net v0.0.0-20200927032502-5d4f70055728
|
||||||
|
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43
|
||||||
|
golang.org/x/text v0.3.3
|
||||||
|
golang.org/x/tools v0.0.0-20201002184944-ecd9fd270d5d
|
||||||
|
google.golang.org/api v0.32.0
|
||||||
|
google.golang.org/genproto v0.0.0-20201002142447-3860012362da
|
||||||
|
google.golang.org/grpc v1.32.0
|
||||||
|
)
|
||||||
+526
@@ -0,0 +1,526 @@
|
|||||||
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||||
|
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||||
|
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||||
|
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||||
|
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||||
|
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||||
|
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
||||||
|
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
||||||
|
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
||||||
|
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||||
|
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||||
|
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||||
|
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||||
|
cloud.google.com/go/bigquery v1.0.1 h1:hL+ycaJpVE9M7nLoiXb/Pn10ENE2u+oddxbD8uu0ZVU=
|
||||||
|
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||||
|
cloud.google.com/go/bigquery v1.3.0 h1:sAbMqjY1PEQKZBWfbu6Y6bsupJ9c4QdHnzg/VvYTLcE=
|
||||||
|
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||||
|
cloud.google.com/go/bigquery v1.4.0 h1:xE3CPsOgttP4ACBePh79zTKALtXwn/Edhcr16R5hMWU=
|
||||||
|
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 h1:a/O/bK/vWrYGOTFtH8di4rBxMZnmkjy+Y5LxpDwo+dA=
|
||||||
|
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 h1:Kt+gOPPp2LEPWp8CSfxhsM8ik9CcyE/gYu+0r+RnZvM=
|
||||||
|
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||||
|
cloud.google.com/go/datastore v1.1.0 h1:/May9ojXjRkPBNVrq+oWLqmWCkr4OU5uRY29bu0mRyQ=
|
||||||
|
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||||
|
cloud.google.com/go/pubsub v1.0.1 h1:W9tAK3E57P75u0XLLR82LZyw8VpAnhmyTOxW9qzmyj8=
|
||||||
|
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||||
|
cloud.google.com/go/pubsub v1.1.0 h1:9/vpR43S4aJaROxqQHQ3nH9lfyKKV0dC3vOmnw8ebQQ=
|
||||||
|
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||||
|
cloud.google.com/go/pubsub v1.2.0 h1:Lpy6hKgdcl7a3WGSfJIFmxmcdjSpP6OmBEfcOv1Y680=
|
||||||
|
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||||
|
cloud.google.com/go/pubsub v1.3.1 h1:ukjixP1wl0LpnZ6LWtZJ0mX5tBmjp1f8Sqer8Z2OMUU=
|
||||||
|
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 h1:VV2nUM3wwLLGh9lSABFgZMjInyUbJeaRSE64WuAIQ+4=
|
||||||
|
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||||
|
cloud.google.com/go/storage v1.5.0 h1:RPUcBvDeYgQFMfQu1eBMq6piD1SXmLH+vK3qjewZPus=
|
||||||
|
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||||
|
cloud.google.com/go/storage v1.6.0 h1:UDpwYIwla4jHGzZJaEJYx1tOejbgSoNqsAfHAUYe2r8=
|
||||||
|
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||||
|
cloud.google.com/go/storage v1.8.0 h1:86K1Gel7BQ9/WmNWn7dTKMvTLFzwtBe5FNqYbi9X35g=
|
||||||
|
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=
|
||||||
|
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/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 h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8=
|
||||||
|
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||||
|
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||||
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
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/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
|
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||||
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
|
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
|
||||||
|
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 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk=
|
||||||
|
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s=
|
||||||
|
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||||
|
github.com/golang/mock v1.4.0 h1:Rd1kQnQu0Hq3qvJppYSG0HtP+f5LPPUiDswTLiEegLg=
|
||||||
|
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 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw=
|
||||||
|
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||||
|
github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
|
||||||
|
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 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
|
||||||
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||||
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
|
||||||
|
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 h1:oOuy+ugB+P/kBdUnG5QaMXSIyJ1q38wWSojYCb3z5VQ=
|
||||||
|
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||||
|
github.com/golang/protobuf v1.4.1 h1:ZFgWrT+bLgsYPirOnRfKLYJLvssAegOj/hgyMFdJZe0=
|
||||||
|
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||||
|
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
|
||||||
|
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw=
|
||||||
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
|
github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
|
||||||
|
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
|
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
||||||
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
|
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
|
||||||
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
|
||||||
|
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 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
|
||||||
|
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k=
|
||||||
|
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
|
||||||
|
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
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 h1:pMen7vLs8nvgEYhywH3KDWJIJTeEr2ULsVWHWYHQyBs=
|
||||||
|
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||||
|
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57 h1:eqyIo2HjKhKe/mJzTG8n4VqvLXIOEG+SLdDqX7xGtkY=
|
||||||
|
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
|
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f h1:Jnx61latede7zDD3DiiP4gmNz33uK0U5HDUaF0a/HVQ=
|
||||||
|
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 h1:Ak8CrdlwwXwAZxzS66vgPt4U8yUZX7JwLvVR58FN5jM=
|
||||||
|
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
|
github.com/google/pprof v0.0.0-20200905233945-acf8798be1f7 h1:k+KkMRk8mGOu1xG38StS7dQ+Z6oW1i9n3dgrAVU9Q/E=
|
||||||
|
github.com/google/pprof v0.0.0-20200905233945-acf8798be1f7/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.0.4 h1:hU4mGcQI4DaAYW+IbTun+2qEZVFxK0ySjQLTbS0VQKc=
|
||||||
|
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/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
|
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6 h1:UDMh68UUwekSh5iP2OMhRRZJiiBccgV7axzUG8vi56c=
|
||||||
|
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
|
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024 h1:rBMNdlhTLzJjJSDIjNEXX1Pz3Hmwmz91v+zycvx9PJc=
|
||||||
|
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/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
|
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
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.21.0 h1:mU6zScU4U1YAFPHEHYk+3JC4SY7JxgkqS10ZOSyksNg=
|
||||||
|
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||||
|
go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4=
|
||||||
|
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||||
|
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
|
go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8=
|
||||||
|
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
|
go.opencensus.io v0.22.4 h1:LYy1Hy3MJdrCdMwwzxA/dRok4ejH+RwNGbuoD9fCjto=
|
||||||
|
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
|
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/exp v0.0.0-20190121172915-509febef88a4 h1:c2HOrn5iMezYjSlGPncknSEr/8x5LELb/ilJbXi9DEA=
|
||||||
|
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 h1:OeRHuibLsmZkFj773W4LcfAGsSxJgfPONhr8cmO+eLA=
|
||||||
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
|
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979 h1:Agxu5KLo8o7Bb634SVDnhIfpTvxmzUwhbYAzBvXt6h4=
|
||||||
|
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 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y=
|
||||||
|
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 h1:hX65Cu3JDlGH3uEdK7I99Ii+9kjD6mvnnpfLdEAH0x4=
|
||||||
|
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 h1:QzoH/1pFpZguR8NrRHLcO6jKqfv2zpuSqZLgdm7ZmjI=
|
||||||
|
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac h1:8R1esu+8QioDxo4E4mX6bFztO+dMTM49DNAaWfO5OeY=
|
||||||
|
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 h1:0IiAsCRByjO2QjX7ZPkw5oU9x+n1YqRL802rjC0c3Aw=
|
||||||
|
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 h1:WG0RUwxtNT4qqaXX3DPA8zHFNm/D9xaBpxzHt1WcA/E=
|
||||||
|
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 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
|
||||||
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
|
||||||
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c h1:uOCk1iQW6Vc18bnC13MfzScl+wdKBmM9Y9kU7Z83/lw=
|
||||||
|
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 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
|
||||||
|
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 h1:WQ8q63x+f/zpC8Ac1s9wLElVoHhm32p6tudrU72n1QA=
|
||||||
|
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
|
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f h1:QBjCr1Fz5kw158VqdE9JfI9cJnl/ymnJWAdMuinqL7Y=
|
||||||
|
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 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4=
|
||||||
|
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
|
golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
|
||||||
|
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
|
golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
|
||||||
|
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
|
golang.org/x/net v0.0.0-20200927032502-5d4f70055728 h1:5wtQIAulKU5AbLQOkjxl32UufnIOqgBX72pS0AV14H0=
|
||||||
|
golang.org/x/net v0.0.0-20200927032502-5d4f70055728/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421 h1:Wo7BWFiOk0QRFMLYMqJGFMd9CgUAcGx7V+qEg/h5IBI=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
|
||||||
|
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 h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43 h1:ld7aEMNHoBnnDAX15v1T6z31v8HwR2A9FYOuAhWqkwc=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 h1:bjcUS9ztw9kFmmIxJInhon/0Is3p+EHBKNgquIzo1OI=
|
||||||
|
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
|
||||||
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03iWnKLEWinaScsxF2Vm2o=
|
||||||
|
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA=
|
||||||
|
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
|
||||||
|
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-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b h1:ag/x1USPSsqHud38I9BAC88qdNLDHHtQ4mlgQIZPPNA=
|
||||||
|
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 h1:HyfiK1WMnHj5FXFXatD+Qs1A/xC2Run6RzeW1SyHxpc=
|
||||||
|
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 h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
|
||||||
|
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 h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
|
||||||
|
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 h1:hq86ru83GdWTlfQFZGO4nZJTU4Bs2wfHl8oFHRaXsfc=
|
||||||
|
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25 h1:OKbAoGs4fGM5cPLlVQLZGYkFC8OnOfgo6tt0Smf9XhM=
|
||||||
|
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 h1:rITEj+UZHYC927n8GT97eC3zrpzXdb/voyeOuVKS46o=
|
||||||
|
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642 h1:B6caxRw+hozq68X2MY7jEpZh/cr4/aHLv9xU8Kkadrw=
|
||||||
|
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f h1:Fqb3ao1hUmOR3GkUOg/Y+BadLwykBIzs5q8Ez2SbHyc=
|
||||||
|
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 h1:z99zHgr7hKfrUcX/KsoJk5FJfjTceCKIp96+biqP4To=
|
||||||
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||||
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
|
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c h1:fqgJT0MGcGpPgpWU7VRdRjuArfcOvC4AoJmILihzhDg=
|
||||||
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
|
||||||
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138 h1:H3uGjxCR/6Ds0Mjgyp7LMK81+LvmbvWWEnJhzk1Pi9E=
|
||||||
|
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 h1:97SnQk1GYRXJgvwZ8fadnxDOWfKvkNQHH3CtZntPSrM=
|
||||||
|
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 h1:Dh6fw+p6FyRl5x/FvNswO1ji0lIGzm3KP8Y9VkS9PTE=
|
||||||
|
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 h1:On1qIo75ByTwFJ4/W2bIqHcwJ9XAqtSWUs8GwRrIhtc=
|
||||||
|
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||||
|
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||||
|
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||||
|
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d h1:lzLdP95xJmMpwQ6LUHwrc5V7js93hTiY7gkznu0BgmY=
|
||||||
|
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
|
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88 h1:4j84u0sokprDu3IdSYHJMmou+YSLflMz8p7yAx/QI4g=
|
||||||
|
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 h1:szSOL78iTCl0LF1AMjhSWJj8tIM0KixlUUnBtYXsmd8=
|
||||||
|
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-20201002184944-ecd9fd270d5d h1:vWQvJ/Z0Lu+9/8oQ/pAYXNzbc7CMnBl+tULGVHOy3oE=
|
||||||
|
golang.org/x/tools v0.0.0-20201002184944-ecd9fd270d5d/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||||
|
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 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||||
|
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||||
|
google.golang.org/api v0.8.0 h1:VGGbLNyPF7dvYHhcUGYBBGCRDDK0RRJAI6KCvo0CL+E=
|
||||||
|
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||||
|
google.golang.org/api v0.9.0 h1:jbyannxz0XFD3zdjgrSUsaJbgpH4eTrkdhRChkHPfO8=
|
||||||
|
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 h1:yzlyyDW/J0w8yNFJIhiAJy4kq74S+1DOLdawELNxFMA=
|
||||||
|
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||||
|
google.golang.org/api v0.17.0 h1:0q95w+VuFtv4PAx4PZVQdBMmYbaCHbnfKaEiDIcVyag=
|
||||||
|
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 h1:J1Pl9P2lnmYFSJvgs70DKELqHNh8CNWXPbud4njEE2s=
|
||||||
|
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||||
|
google.golang.org/api v0.24.0 h1:cG03eaksBzhfSIk7JRGctfp3lanklcOM/mTGvow7BbQ=
|
||||||
|
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 h1:BaiDisFir8O4IJxvAabCGGkQ6yCJegNQqSVoYUNAnbk=
|
||||||
|
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||||
|
google.golang.org/api v0.30.0 h1:yfrXXP61wVuLb0vBcG6qaOoIoqYEzOQS8jum51jkv2w=
|
||||||
|
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||||
|
google.golang.org/api v0.32.0 h1:Le77IccnTqEa8ryp9wIpX5W3zYm7Gf9LhOp9PHcwFts=
|
||||||
|
google.golang.org/api v0.32.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
|
||||||
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
|
google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
|
||||||
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c=
|
||||||
|
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I=
|
||||||
|
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||||
|
google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
|
||||||
|
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
|
google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc=
|
||||||
|
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19 h1:Lj2SnHtxkRGJDqnGaSjo+CCdIieEnwVazbOXILwQemk=
|
||||||
|
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873 h1:nfPFGzJkUDX6uBmpN/pSw7MbOAWegH5QDQuoXFHedLg=
|
||||||
|
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64 h1:iKtrH9Y8mcbADOP0YFaEMth7OfuHY9xHOwNj4znpM1A=
|
||||||
|
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51 h1:Ex1mq5jaJof+kRnYi3SlYJ8KKa9Ao3NHyIT5XJ1gF6U=
|
||||||
|
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 h1:pSLkPbrjnPyLDYUO2VM9mDLqo2V6CFBY84lFSZAfoi4=
|
||||||
|
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380 h1:xriR1EgvKfkKxIoU2uUvrMVl+H26359loFFUleSMXFo=
|
||||||
|
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 h1:Lq4llNryJoaVFRmvrIwC/ZHH7tNt4tUYIu8+se2aayY=
|
||||||
|
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-20201002142447-3860012362da h1:DTQYk4u7nICKkkVZsBv0/0po0ChISxAJ5CTAfUhO0PQ=
|
||||||
|
google.golang.org/genproto v0.0.0-20201002142447-3860012362da/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/grpc v1.19.0 h1:cfg4PD8YEdSFnm7qLV4++93WcmhH2nIUhMjhdCvl3j8=
|
||||||
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
|
google.golang.org/grpc v1.20.1 h1:Hz2g2wirWK7H0qIIhGIqRGTuMwTE8HEKFnDZZ7lm9NU=
|
||||||
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
|
google.golang.org/grpc v1.21.1 h1:j6XxA85m/6txkUCHvzlV5f+HBNl/1r5cZ2A/3IEFOO8=
|
||||||
|
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 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg=
|
||||||
|
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
|
google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk=
|
||||||
|
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 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4=
|
||||||
|
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 h1:T7P4R73V3SSDPhH7WW7ATbfViLtmamH0DKrP3f9AuDI=
|
||||||
|
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
|
google.golang.org/grpc v1.31.1 h1:SfXqXS5hkufcdZ/mHtYCh53P2b+92WQq/DZcKLgsFRs=
|
||||||
|
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
|
google.golang.org/grpc v1.32.0 h1:zWTV+LMdc3kaiJMSTOFz2UgSBgx8RNQoTGiZu3fR9S0=
|
||||||
|
google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
|
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 h1:qdOKuR/EIArgaWNjetjgTzgVTAZ+S/WXVrq9HW9zimw=
|
||||||
|
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||||
|
google.golang.org/protobuf v1.22.0 h1:cJv5/xdbk1NnMPR1VP9+HU6gupuG9MLBoH1r6RHZ2MY=
|
||||||
|
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
|
||||||
|
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc h1:TnonUr8u3himcMY0vSh23jFOXA+cnucl1gB6EQTReBI=
|
||||||
|
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA=
|
||||||
|
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||||
|
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
|
||||||
|
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a h1:/8zB6iBfHCl1qAnEAWwGPNrUvapuy6CPla1VM0k8hQw=
|
||||||
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a h1:LJwr7TCTghdatWv40WobzlKXc9c4s8oGa7QKJUtHhWA=
|
||||||
|
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 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
||||||
|
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||||
|
honnef.co/go/tools v0.0.1-2020.1.3 h1:sXmLre5bzIR6ypkjXCDI3jHPssRhc8KD/Ome589sc3U=
|
||||||
|
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||||
|
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||||
|
rsc.io/binaryregexp v0.2.0 h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE=
|
||||||
|
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||||
|
rsc.io/quote/v3 v3.1.0 h1:9JKUTTIUgS6kzR9mK1YuGKv6Nl+DijDNIc0ghT58FaY=
|
||||||
|
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||||
|
rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4=
|
||||||
|
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||||
+387
@@ -0,0 +1,387 @@
|
|||||||
|
// Copyright 2016 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 iam supports the resource-specific operations of Google Cloud
|
||||||
|
// IAM (Identity and Access Management) for the Google Cloud Libraries.
|
||||||
|
// See https://cloud.google.com/iam for more about IAM.
|
||||||
|
//
|
||||||
|
// Users of the Google Cloud Libraries will typically not use this package
|
||||||
|
// directly. Instead they will begin with some resource that supports IAM, like
|
||||||
|
// a pubsub topic, and call its IAM method to get a Handle for that resource.
|
||||||
|
package iam
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// client abstracts the IAMPolicy API to allow multiple implementations.
|
||||||
|
type client interface {
|
||||||
|
Get(ctx context.Context, resource string) (*pb.Policy, error)
|
||||||
|
Set(ctx context.Context, resource string, p *pb.Policy) error
|
||||||
|
Test(ctx context.Context, resource string, perms []string) ([]string, error)
|
||||||
|
GetWithVersion(ctx context.Context, resource string, requestedPolicyVersion int32) (*pb.Policy, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// grpcClient implements client for the standard gRPC-based IAMPolicy service.
|
||||||
|
type grpcClient struct {
|
||||||
|
c pb.IAMPolicyClient
|
||||||
|
}
|
||||||
|
|
||||||
|
var withRetry = gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnCodes([]codes.Code{
|
||||||
|
codes.DeadlineExceeded,
|
||||||
|
codes.Unavailable,
|
||||||
|
}, gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 60 * time.Second,
|
||||||
|
Multiplier: 1.3,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
func (g *grpcClient) Get(ctx context.Context, resource string) (*pb.Policy, error) {
|
||||||
|
return g.GetWithVersion(ctx, resource, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *grpcClient) GetWithVersion(ctx context.Context, resource string, requestedPolicyVersion int32) (*pb.Policy, error) {
|
||||||
|
var proto *pb.Policy
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", resource))
|
||||||
|
ctx = insertMetadata(ctx, md)
|
||||||
|
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, _ gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
proto, err = g.c.GetIamPolicy(ctx, &pb.GetIamPolicyRequest{
|
||||||
|
Resource: resource,
|
||||||
|
Options: &pb.GetPolicyOptions{
|
||||||
|
RequestedPolicyVersion: requestedPolicyVersion,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}, withRetry)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return proto, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *grpcClient) Set(ctx context.Context, resource string, p *pb.Policy) error {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", resource))
|
||||||
|
ctx = insertMetadata(ctx, md)
|
||||||
|
|
||||||
|
return gax.Invoke(ctx, func(ctx context.Context, _ gax.CallSettings) error {
|
||||||
|
_, err := g.c.SetIamPolicy(ctx, &pb.SetIamPolicyRequest{
|
||||||
|
Resource: resource,
|
||||||
|
Policy: p,
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}, withRetry)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *grpcClient) Test(ctx context.Context, resource string, perms []string) ([]string, error) {
|
||||||
|
var res *pb.TestIamPermissionsResponse
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", resource))
|
||||||
|
ctx = insertMetadata(ctx, md)
|
||||||
|
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, _ gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
res, err = g.c.TestIamPermissions(ctx, &pb.TestIamPermissionsRequest{
|
||||||
|
Resource: resource,
|
||||||
|
Permissions: perms,
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}, withRetry)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return res.Permissions, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Handle provides IAM operations for a resource.
|
||||||
|
type Handle struct {
|
||||||
|
c client
|
||||||
|
resource string
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Handle3 provides IAM operations for a resource. It is similar to a Handle, but provides access to newer IAM features (e.g., conditions).
|
||||||
|
type Handle3 struct {
|
||||||
|
c client
|
||||||
|
resource string
|
||||||
|
version int32
|
||||||
|
}
|
||||||
|
|
||||||
|
// InternalNewHandle is for use by the Google Cloud Libraries only.
|
||||||
|
//
|
||||||
|
// InternalNewHandle returns a Handle for resource.
|
||||||
|
// The conn parameter refers to a server that must support the IAMPolicy service.
|
||||||
|
func InternalNewHandle(conn grpc.ClientConnInterface, resource string) *Handle {
|
||||||
|
return InternalNewHandleGRPCClient(pb.NewIAMPolicyClient(conn), resource)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InternalNewHandleGRPCClient is for use by the Google Cloud Libraries only.
|
||||||
|
//
|
||||||
|
// InternalNewHandleClient returns a Handle for resource using the given
|
||||||
|
// grpc service that implements IAM as a mixin
|
||||||
|
func InternalNewHandleGRPCClient(c pb.IAMPolicyClient, resource string) *Handle {
|
||||||
|
return InternalNewHandleClient(&grpcClient{c: c}, resource)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InternalNewHandleClient is for use by the Google Cloud Libraries only.
|
||||||
|
//
|
||||||
|
// InternalNewHandleClient returns a Handle for resource using the given
|
||||||
|
// client implementation.
|
||||||
|
func InternalNewHandleClient(c client, resource string) *Handle {
|
||||||
|
return &Handle{
|
||||||
|
c: c,
|
||||||
|
resource: resource,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// V3 returns a Handle3, which is like Handle except it sets
|
||||||
|
// requestedPolicyVersion to 3 when retrieving a policy and policy.version to 3
|
||||||
|
// when storing a policy.
|
||||||
|
func (h *Handle) V3() *Handle3 {
|
||||||
|
return &Handle3{
|
||||||
|
c: h.c,
|
||||||
|
resource: h.resource,
|
||||||
|
version: 3,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Policy retrieves the IAM policy for the resource.
|
||||||
|
func (h *Handle) Policy(ctx context.Context) (*Policy, error) {
|
||||||
|
proto, err := h.c.Get(ctx, h.resource)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Policy{InternalProto: proto}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPolicy replaces the resource's current policy with the supplied Policy.
|
||||||
|
//
|
||||||
|
// If policy was created from a prior call to Get, then the modification will
|
||||||
|
// only succeed if the policy has not changed since the Get.
|
||||||
|
func (h *Handle) SetPolicy(ctx context.Context, policy *Policy) error {
|
||||||
|
return h.c.Set(ctx, h.resource, policy.InternalProto)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestPermissions returns the subset of permissions that the caller has on the resource.
|
||||||
|
func (h *Handle) TestPermissions(ctx context.Context, permissions []string) ([]string, error) {
|
||||||
|
return h.c.Test(ctx, h.resource, permissions)
|
||||||
|
}
|
||||||
|
|
||||||
|
// A RoleName is a name representing a collection of permissions.
|
||||||
|
type RoleName string
|
||||||
|
|
||||||
|
// Common role names.
|
||||||
|
const (
|
||||||
|
Owner RoleName = "roles/owner"
|
||||||
|
Editor RoleName = "roles/editor"
|
||||||
|
Viewer RoleName = "roles/viewer"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// AllUsers is a special member that denotes all users, even unauthenticated ones.
|
||||||
|
AllUsers = "allUsers"
|
||||||
|
|
||||||
|
// AllAuthenticatedUsers is a special member that denotes all authenticated users.
|
||||||
|
AllAuthenticatedUsers = "allAuthenticatedUsers"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Policy is a list of Bindings representing roles
|
||||||
|
// granted to members.
|
||||||
|
//
|
||||||
|
// The zero Policy is a valid policy with no bindings.
|
||||||
|
type Policy struct {
|
||||||
|
// TODO(jba): when type aliases are available, put Policy into an internal package
|
||||||
|
// and provide an exported alias here.
|
||||||
|
|
||||||
|
// This field is exported for use by the Google Cloud Libraries only.
|
||||||
|
// It may become unexported in a future release.
|
||||||
|
InternalProto *pb.Policy
|
||||||
|
}
|
||||||
|
|
||||||
|
// Members returns the list of members with the supplied role.
|
||||||
|
// The return value should not be modified. Use Add and Remove
|
||||||
|
// to modify the members of a role.
|
||||||
|
func (p *Policy) Members(r RoleName) []string {
|
||||||
|
b := p.binding(r)
|
||||||
|
if b == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return b.Members
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasRole reports whether member has role r.
|
||||||
|
func (p *Policy) HasRole(member string, r RoleName) bool {
|
||||||
|
return memberIndex(member, p.binding(r)) >= 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add adds member member to role r if it is not already present.
|
||||||
|
// A new binding is created if there is no binding for the role.
|
||||||
|
func (p *Policy) Add(member string, r RoleName) {
|
||||||
|
b := p.binding(r)
|
||||||
|
if b == nil {
|
||||||
|
if p.InternalProto == nil {
|
||||||
|
p.InternalProto = &pb.Policy{}
|
||||||
|
}
|
||||||
|
p.InternalProto.Bindings = append(p.InternalProto.Bindings, &pb.Binding{
|
||||||
|
Role: string(r),
|
||||||
|
Members: []string{member},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if memberIndex(member, b) < 0 {
|
||||||
|
b.Members = append(b.Members, member)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove removes member from role r if it is present.
|
||||||
|
func (p *Policy) Remove(member string, r RoleName) {
|
||||||
|
bi := p.bindingIndex(r)
|
||||||
|
if bi < 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bindings := p.InternalProto.Bindings
|
||||||
|
b := bindings[bi]
|
||||||
|
mi := memberIndex(member, b)
|
||||||
|
if mi < 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Order doesn't matter for bindings or members, so to remove, move the last item
|
||||||
|
// into the removed spot and shrink the slice.
|
||||||
|
if len(b.Members) == 1 {
|
||||||
|
// Remove binding.
|
||||||
|
last := len(bindings) - 1
|
||||||
|
bindings[bi] = bindings[last]
|
||||||
|
bindings[last] = nil
|
||||||
|
p.InternalProto.Bindings = bindings[:last]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Remove member.
|
||||||
|
// TODO(jba): worry about multiple copies of m?
|
||||||
|
last := len(b.Members) - 1
|
||||||
|
b.Members[mi] = b.Members[last]
|
||||||
|
b.Members[last] = ""
|
||||||
|
b.Members = b.Members[:last]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Roles returns the names of all the roles that appear in the Policy.
|
||||||
|
func (p *Policy) Roles() []RoleName {
|
||||||
|
if p.InternalProto == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var rns []RoleName
|
||||||
|
for _, b := range p.InternalProto.Bindings {
|
||||||
|
rns = append(rns, RoleName(b.Role))
|
||||||
|
}
|
||||||
|
return rns
|
||||||
|
}
|
||||||
|
|
||||||
|
// binding returns the Binding for the suppied role, or nil if there isn't one.
|
||||||
|
func (p *Policy) binding(r RoleName) *pb.Binding {
|
||||||
|
i := p.bindingIndex(r)
|
||||||
|
if i < 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return p.InternalProto.Bindings[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Policy) bindingIndex(r RoleName) int {
|
||||||
|
if p.InternalProto == nil {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
for i, b := range p.InternalProto.Bindings {
|
||||||
|
if b.Role == string(r) {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
// memberIndex returns the index of m in b's Members, or -1 if not found.
|
||||||
|
func memberIndex(m string, b *pb.Binding) int {
|
||||||
|
if b == nil {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
for i, mm := range b.Members {
|
||||||
|
if mm == m {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
// insertMetadata inserts metadata into the given context
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Policy3 is a list of Bindings representing roles granted to members.
|
||||||
|
//
|
||||||
|
// The zero Policy3 is a valid policy with no bindings.
|
||||||
|
//
|
||||||
|
// It is similar to a Policy, except a Policy3 provides direct access to the
|
||||||
|
// list of Bindings.
|
||||||
|
//
|
||||||
|
// The policy version is always set to 3.
|
||||||
|
type Policy3 struct {
|
||||||
|
etag []byte
|
||||||
|
Bindings []*pb.Binding
|
||||||
|
}
|
||||||
|
|
||||||
|
// Policy retrieves the IAM policy for the resource.
|
||||||
|
//
|
||||||
|
// requestedPolicyVersion is always set to 3.
|
||||||
|
func (h *Handle3) Policy(ctx context.Context) (*Policy3, error) {
|
||||||
|
proto, err := h.c.GetWithVersion(ctx, h.resource, h.version)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Policy3{
|
||||||
|
Bindings: proto.Bindings,
|
||||||
|
etag: proto.Etag,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPolicy replaces the resource's current policy with the supplied Policy.
|
||||||
|
//
|
||||||
|
// If policy was created from a prior call to Get, then the modification will
|
||||||
|
// only succeed if the policy has not changed since the Get.
|
||||||
|
func (h *Handle3) SetPolicy(ctx context.Context, policy *Policy3) error {
|
||||||
|
return h.c.Set(ctx, h.resource, &pb.Policy{
|
||||||
|
Bindings: policy.Bindings,
|
||||||
|
Etag: policy.etag,
|
||||||
|
Version: h.version,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestPermissions returns the subset of permissions that the caller has on the resource.
|
||||||
|
func (h *Handle3) TestPermissions(ctx context.Context, permissions []string) ([]string, error) {
|
||||||
|
return h.c.Test(ctx, h.resource, permissions)
|
||||||
|
}
|
||||||
+898
@@ -0,0 +1,898 @@
|
|||||||
|
{
|
||||||
|
"cloud.google.com/go/analytics/admin/apiv1alpha": {
|
||||||
|
"distribution_name": "cloud.google.com/go/analytics/admin/apiv1alpha",
|
||||||
|
"description": "",
|
||||||
|
"language": "Go",
|
||||||
|
"client_library_type": "generated",
|
||||||
|
"docs_url": "https://pkg.go.dev/cloud.google.com/go/analytics/admin/apiv1alpha",
|
||||||
|
"release_level": "alpha"
|
||||||
|
},
|
||||||
|
"cloud.google.com/go/analytics/data/apiv1alpha": {
|
||||||
|
"distribution_name": "cloud.google.com/go/analytics/data/apiv1alpha",
|
||||||
|
"description": "",
|
||||||
|
"language": "Go",
|
||||||
|
"client_library_type": "generated",
|
||||||
|
"docs_url": "https://pkg.go.dev/cloud.google.com/go/analytics/data/apiv1alpha",
|
||||||
|
"release_level": "alpha"
|
||||||
|
},
|
||||||
|
"cloud.google.com/go/area120/tables/apiv1alpha1": {
|
||||||
|
"distribution_name": "cloud.google.com/go/area120/tables/apiv1alpha1",
|
||||||
|
"description": "",
|
||||||
|
"language": "Go",
|
||||||
|
"client_library_type": "generated",
|
||||||
|
"docs_url": "https://pkg.go.dev/cloud.google.com/go/area120/tables/apiv1alpha1",
|
||||||
|
"release_level": "alpha"
|
||||||
|
},
|
||||||
|
"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/apiv1",
|
||||||
|
"release_level": "ga"
|
||||||
|
},
|
||||||
|
"cloud.google.com/go/asset/apiv1beta1": {
|
||||||
|
"distribution_name": "cloud.google.com/go/asset/apiv1beta1",
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"cloud.google.com/go/assuredworkloads/apiv1beta1": {
|
||||||
|
"distribution_name": "cloud.google.com/go/assuredworkloads/apiv1beta1",
|
||||||
|
"description": "",
|
||||||
|
"language": "Go",
|
||||||
|
"client_library_type": "generated",
|
||||||
|
"docs_url": "https://pkg.go.dev/cloud.google.com/go/assuredworkloads/apiv1beta1",
|
||||||
|
"release_level": "beta"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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/reservation/apiv1",
|
||||||
|
"release_level": "ga"
|
||||||
|
},
|
||||||
|
"cloud.google.com/go/bigquery/reservation/apiv1beta1": {
|
||||||
|
"distribution_name": "cloud.google.com/go/bigquery/reservation/apiv1beta1",
|
||||||
|
"description": "BigQuery Reservation API",
|
||||||
|
"language": "Go",
|
||||||
|
"client_library_type": "generated",
|
||||||
|
"docs_url": "https://pkg.go.dev/cloud.google.com/go/bigquery/reservation/apiv1beta1",
|
||||||
|
"release_level": "beta"
|
||||||
|
},
|
||||||
|
"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/apiv1",
|
||||||
|
"release_level": "ga"
|
||||||
|
},
|
||||||
|
"cloud.google.com/go/bigquery/storage/apiv1alpha2": {
|
||||||
|
"distribution_name": "cloud.google.com/go/bigquery/storage/apiv1alpha2",
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"cloud.google.com/go/billing/budgets/apiv1beta1": {
|
||||||
|
"distribution_name": "cloud.google.com/go/billing/budgets/apiv1beta1",
|
||||||
|
"description": "",
|
||||||
|
"language": "Go",
|
||||||
|
"client_library_type": "generated",
|
||||||
|
"docs_url": "https://pkg.go.dev/cloud.google.com/go/billing/budgets/apiv1beta1",
|
||||||
|
"release_level": "beta"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"cloud.google.com/go/dataproc/apiv1beta2": {
|
||||||
|
"distribution_name": "cloud.google.com/go/dataproc/apiv1beta2",
|
||||||
|
"description": "Cloud Dataproc API",
|
||||||
|
"language": "Go",
|
||||||
|
"client_library_type": "generated",
|
||||||
|
"docs_url": "https://pkg.go.dev/cloud.google.com/go/dataproc/apiv1beta2",
|
||||||
|
"release_level": "beta"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"cloud.google.com/go/errorreporting": {
|
||||||
|
"distribution_name": "cloud.google.com/go/errorreporting",
|
||||||
|
"description": "Stackdriver Error Reporting API",
|
||||||
|
"language": "Go",
|
||||||
|
"client_library_type": "manual",
|
||||||
|
"docs_url": "https://pkg.go.dev/cloud.google.com/go/errorreporting",
|
||||||
|
"release_level": "beta"
|
||||||
|
},
|
||||||
|
"cloud.google.com/go/errorreporting/apiv1beta1": {
|
||||||
|
"distribution_name": "cloud.google.com/go/errorreporting/apiv1beta1",
|
||||||
|
"description": "Stackdriver Error Reporting API",
|
||||||
|
"language": "Go",
|
||||||
|
"client_library_type": "generated",
|
||||||
|
"docs_url": "https://pkg.go.dev/cloud.google.com/go/errorreporting/apiv1beta1",
|
||||||
|
"release_level": "beta"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"cloud.google.com/go/firestore/apiv1/admin": {
|
||||||
|
"distribution_name": "cloud.google.com/go/firestore/apiv1/admin",
|
||||||
|
"description": "Google Cloud Firestore Admin API",
|
||||||
|
"language": "Go",
|
||||||
|
"client_library_type": "generated",
|
||||||
|
"docs_url": "https://pkg.go.dev/cloud.google.com/go/firestore/apiv1/admin",
|
||||||
|
"release_level": "ga"
|
||||||
|
},
|
||||||
|
"cloud.google.com/go/functions/apiv1": {
|
||||||
|
"distribution_name": "cloud.google.com/go/functions/apiv1",
|
||||||
|
"description": "",
|
||||||
|
"language": "Go",
|
||||||
|
"client_library_type": "generated",
|
||||||
|
"docs_url": "https://pkg.go.dev/cloud.google.com/go/functions/apiv1",
|
||||||
|
"release_level": "beta"
|
||||||
|
},
|
||||||
|
"cloud.google.com/go/gaming/apiv1": {
|
||||||
|
"distribution_name": "cloud.google.com/go/gaming/apiv1",
|
||||||
|
"description": "",
|
||||||
|
"language": "Go",
|
||||||
|
"client_library_type": "generated",
|
||||||
|
"docs_url": "https://pkg.go.dev/cloud.google.com/go/gaming/apiv1",
|
||||||
|
"release_level": "beta"
|
||||||
|
},
|
||||||
|
"cloud.google.com/go/gaming/apiv1beta": {
|
||||||
|
"distribution_name": "cloud.google.com/go/gaming/apiv1beta",
|
||||||
|
"description": "",
|
||||||
|
"language": "Go",
|
||||||
|
"client_library_type": "generated",
|
||||||
|
"docs_url": "https://pkg.go.dev/cloud.google.com/go/gaming/apiv1beta",
|
||||||
|
"release_level": "beta"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"cloud.google.com/go/logging": {
|
||||||
|
"distribution_name": "cloud.google.com/go/logging",
|
||||||
|
"description": "Stackdriver Logging API",
|
||||||
|
"language": "Go",
|
||||||
|
"client_library_type": "manual",
|
||||||
|
"docs_url": "https://pkg.go.dev/cloud.google.com/go/logging",
|
||||||
|
"release_level": "ga"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"cloud.google.com/go/monitoring/dashboard/apiv1": {
|
||||||
|
"distribution_name": "cloud.google.com/go/monitoring/dashboard/apiv1",
|
||||||
|
"description": "",
|
||||||
|
"language": "Go",
|
||||||
|
"client_library_type": "generated",
|
||||||
|
"docs_url": "https://pkg.go.dev/cloud.google.com/go/monitoring/dashboard/apiv1",
|
||||||
|
"release_level": "beta"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"cloud.google.com/go/osconfig/agentendpoint/apiv1": {
|
||||||
|
"distribution_name": "cloud.google.com/go/osconfig/agentendpoint/apiv1",
|
||||||
|
"description": "Cloud 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"
|
||||||
|
},
|
||||||
|
"cloud.google.com/go/osconfig/agentendpoint/apiv1beta": {
|
||||||
|
"distribution_name": "cloud.google.com/go/osconfig/agentendpoint/apiv1beta",
|
||||||
|
"description": "Cloud 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"
|
||||||
|
},
|
||||||
|
"cloud.google.com/go/osconfig/apiv1": {
|
||||||
|
"distribution_name": "cloud.google.com/go/osconfig/apiv1",
|
||||||
|
"description": "Cloud OS Config API",
|
||||||
|
"language": "Go",
|
||||||
|
"client_library_type": "generated",
|
||||||
|
"docs_url": "https://pkg.go.dev/cloud.google.com/go/osconfig/apiv1",
|
||||||
|
"release_level": "ga"
|
||||||
|
},
|
||||||
|
"cloud.google.com/go/osconfig/apiv1beta": {
|
||||||
|
"distribution_name": "cloud.google.com/go/osconfig/apiv1beta",
|
||||||
|
"description": "Cloud OS Config API",
|
||||||
|
"language": "Go",
|
||||||
|
"client_library_type": "generated",
|
||||||
|
"docs_url": "https://pkg.go.dev/cloud.google.com/go/osconfig/apiv1beta",
|
||||||
|
"release_level": "beta"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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": "beta"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"cloud.google.com/go/pubsublite/apiv1": {
|
||||||
|
"distribution_name": "cloud.google.com/go/pubsublite/apiv1",
|
||||||
|
"description": "",
|
||||||
|
"language": "Go",
|
||||||
|
"client_library_type": "generated",
|
||||||
|
"docs_url": "https://pkg.go.dev/cloud.google.com/go/pubsublite/apiv1",
|
||||||
|
"release_level": "beta"
|
||||||
|
},
|
||||||
|
"cloud.google.com/go/recaptchaenterprise/apiv1": {
|
||||||
|
"distribution_name": "cloud.google.com/go/recaptchaenterprise/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": "beta"
|
||||||
|
},
|
||||||
|
"cloud.google.com/go/recaptchaenterprise/apiv1beta1": {
|
||||||
|
"distribution_name": "cloud.google.com/go/recaptchaenterprise/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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"cloud.google.com/go/secretmanager/apiv1beta1": {
|
||||||
|
"distribution_name": "cloud.google.com/go/secretmanager/apiv1beta1",
|
||||||
|
"description": "Secret Manager API",
|
||||||
|
"language": "Go",
|
||||||
|
"client_library_type": "generated",
|
||||||
|
"docs_url": "https://pkg.go.dev/cloud.google.com/go/secretmanager/apiv1beta1",
|
||||||
|
"release_level": "beta"
|
||||||
|
},
|
||||||
|
"cloud.google.com/go/security/privateca/apiv1beta1": {
|
||||||
|
"distribution_name": "cloud.google.com/go/security/privateca/apiv1beta1",
|
||||||
|
"description": "",
|
||||||
|
"language": "Go",
|
||||||
|
"client_library_type": "generated",
|
||||||
|
"docs_url": "https://pkg.go.dev/cloud.google.com/go/security/privateca/apiv1beta1",
|
||||||
|
"release_level": "beta"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"cloud.google.com/go/spanner/admin/database/apiv1": {
|
||||||
|
"distribution_name": "cloud.google.com/go/spanner/admin/database/apiv1",
|
||||||
|
"description": "Cloud Spanner Database Admin API",
|
||||||
|
"language": "Go",
|
||||||
|
"client_library_type": "generated",
|
||||||
|
"docs_url": "https://pkg.go.dev/cloud.google.com/go/spanner/admin/database/apiv1",
|
||||||
|
"release_level": "ga"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"cloud.google.com/go/talent/apiv4": {
|
||||||
|
"distribution_name": "cloud.google.com/go/talent/apiv4",
|
||||||
|
"description": "",
|
||||||
|
"language": "Go",
|
||||||
|
"client_library_type": "generated",
|
||||||
|
"docs_url": "https://pkg.go.dev/cloud.google.com/go/talent/apiv4",
|
||||||
|
"release_level": "beta"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"cloud.google.com/go/trace": {
|
||||||
|
"distribution_name": "cloud.google.com/go/trace",
|
||||||
|
"description": "Stackdriver Trace",
|
||||||
|
"language": "Go",
|
||||||
|
"client_library_type": "manual",
|
||||||
|
"docs_url": "https://pkg.go.dev/cloud.google.com/go/trace",
|
||||||
|
"release_level": "ga"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"cloud.google.com/go/video/transcoder/apiv1beta1": {
|
||||||
|
"distribution_name": "cloud.google.com/go/video/transcoder/apiv1beta1",
|
||||||
|
"description": "",
|
||||||
|
"language": "Go",
|
||||||
|
"client_library_type": "generated",
|
||||||
|
"docs_url": "https://pkg.go.dev/cloud.google.com/go/video/transcoder/apiv1beta1",
|
||||||
|
"release_level": "beta"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"cloud.google.com/go/vision/apiv1": {
|
||||||
|
"distribution_name": "cloud.google.com/go/vision/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"
|
||||||
|
},
|
||||||
|
"cloud.google.com/go/vision/apiv1p1beta1": {
|
||||||
|
"distribution_name": "cloud.google.com/go/vision/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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"cloud.google.com/go/workflows/apiv1beta": {
|
||||||
|
"distribution_name": "cloud.google.com/go/workflows/apiv1beta",
|
||||||
|
"description": "",
|
||||||
|
"language": "Go",
|
||||||
|
"client_library_type": "generated",
|
||||||
|
"docs_url": "https://pkg.go.dev/cloud.google.com/go/workflows/apiv1beta",
|
||||||
|
"release_level": "beta"
|
||||||
|
},
|
||||||
|
"cloud.google.com/go/workflows/executions/apiv1beta": {
|
||||||
|
"distribution_name": "cloud.google.com/go/workflows/executions/apiv1beta",
|
||||||
|
"description": "",
|
||||||
|
"language": "Go",
|
||||||
|
"client_library_type": "generated",
|
||||||
|
"docs_url": "https://pkg.go.dev/cloud.google.com/go/workflows/executions/apiv1beta",
|
||||||
|
"release_level": "beta"
|
||||||
|
}
|
||||||
|
}
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
# Internal
|
||||||
|
|
||||||
|
This directory contains internal code for cloud.google.com/go packages.
|
||||||
|
|
||||||
|
## .repo-metadata-full.json
|
||||||
|
|
||||||
|
`.repo-metadata-full.json` contains metadata about the packages in this repo. It
|
||||||
|
is generated by `internal/gapicgen/generator`. It's processed by external tools
|
||||||
|
to build lists of all of the packages.
|
||||||
|
|
||||||
|
Don't make breaking changes to the format without consulting with the external
|
||||||
|
tools.
|
||||||
|
|
||||||
|
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.
|
||||||
+54
@@ -0,0 +1,54 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"google.golang.org/api/googleapi"
|
||||||
|
"google.golang.org/grpc/status"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Annotate prepends msg to the error message in err, attempting
|
||||||
|
// to preserve other information in err, like an error code.
|
||||||
|
//
|
||||||
|
// Annotate panics if err is nil.
|
||||||
|
//
|
||||||
|
// Annotate knows about these error types:
|
||||||
|
// - "google.golang.org/grpc/status".Status
|
||||||
|
// - "google.golang.org/api/googleapi".Error
|
||||||
|
// If the error is not one of these types, Annotate behaves
|
||||||
|
// like
|
||||||
|
// fmt.Errorf("%s: %v", msg, err)
|
||||||
|
func Annotate(err error, msg string) error {
|
||||||
|
if err == nil {
|
||||||
|
panic("Annotate called with nil")
|
||||||
|
}
|
||||||
|
if s, ok := status.FromError(err); ok {
|
||||||
|
p := s.Proto()
|
||||||
|
p.Message = msg + ": " + p.Message
|
||||||
|
return status.ErrorProto(p)
|
||||||
|
}
|
||||||
|
if g, ok := err.(*googleapi.Error); ok {
|
||||||
|
g.Message = msg + ": " + g.Message
|
||||||
|
return g
|
||||||
|
}
|
||||||
|
return fmt.Errorf("%s: %v", msg, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Annotatef uses format and args to format a string, then calls Annotate.
|
||||||
|
func Annotatef(err error, format string, args ...interface{}) error {
|
||||||
|
return Annotate(err, fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
+108
@@ -0,0 +1,108 @@
|
|||||||
|
// Copyright 2016 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 optional provides versions of primitive types that can
|
||||||
|
// be nil. These are useful in methods that update some of an API object's
|
||||||
|
// fields.
|
||||||
|
package optional
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
// Bool is either a bool or nil.
|
||||||
|
Bool interface{}
|
||||||
|
|
||||||
|
// String is either a string or nil.
|
||||||
|
String interface{}
|
||||||
|
|
||||||
|
// Int is either an int or nil.
|
||||||
|
Int interface{}
|
||||||
|
|
||||||
|
// Uint is either a uint or nil.
|
||||||
|
Uint interface{}
|
||||||
|
|
||||||
|
// Float64 is either a float64 or nil.
|
||||||
|
Float64 interface{}
|
||||||
|
|
||||||
|
// Duration is either a time.Duration or nil.
|
||||||
|
Duration interface{}
|
||||||
|
)
|
||||||
|
|
||||||
|
// ToBool returns its argument as a bool.
|
||||||
|
// It panics if its argument is nil or not a bool.
|
||||||
|
func ToBool(v Bool) bool {
|
||||||
|
x, ok := v.(bool)
|
||||||
|
if !ok {
|
||||||
|
doPanic("Bool", v)
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToString returns its argument as a string.
|
||||||
|
// It panics if its argument is nil or not a string.
|
||||||
|
func ToString(v String) string {
|
||||||
|
x, ok := v.(string)
|
||||||
|
if !ok {
|
||||||
|
doPanic("String", v)
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToInt returns its argument as an int.
|
||||||
|
// It panics if its argument is nil or not an int.
|
||||||
|
func ToInt(v Int) int {
|
||||||
|
x, ok := v.(int)
|
||||||
|
if !ok {
|
||||||
|
doPanic("Int", v)
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToUint returns its argument as a uint.
|
||||||
|
// It panics if its argument is nil or not a uint.
|
||||||
|
func ToUint(v Uint) uint {
|
||||||
|
x, ok := v.(uint)
|
||||||
|
if !ok {
|
||||||
|
doPanic("Uint", v)
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToFloat64 returns its argument as a float64.
|
||||||
|
// It panics if its argument is nil or not a float64.
|
||||||
|
func ToFloat64(v Float64) float64 {
|
||||||
|
x, ok := v.(float64)
|
||||||
|
if !ok {
|
||||||
|
doPanic("Float64", v)
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToDuration returns its argument as a time.Duration.
|
||||||
|
// It panics if its argument is nil or not a time.Duration.
|
||||||
|
func ToDuration(v Duration) time.Duration {
|
||||||
|
x, ok := v.(time.Duration)
|
||||||
|
if !ok {
|
||||||
|
doPanic("Duration", v)
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
func doPanic(capType string, v interface{}) {
|
||||||
|
panic(fmt.Sprintf("optional.%s value should be %s, got %T", capType, strings.ToLower(capType), v))
|
||||||
|
}
|
||||||
+54
@@ -0,0 +1,54 @@
|
|||||||
|
// Copyright 2016 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
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
gax "github.com/googleapis/gax-go/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Retry calls the supplied function f repeatedly according to the provided
|
||||||
|
// backoff parameters. It returns when one of the following occurs:
|
||||||
|
// When f's first return value is true, Retry immediately returns with f's second
|
||||||
|
// return value.
|
||||||
|
// When the provided context is done, Retry returns with an error that
|
||||||
|
// includes both ctx.Error() and the last error returned by f.
|
||||||
|
func Retry(ctx context.Context, bo gax.Backoff, f func() (stop bool, err error)) error {
|
||||||
|
return retry(ctx, bo, f, gax.Sleep)
|
||||||
|
}
|
||||||
|
|
||||||
|
func retry(ctx context.Context, bo gax.Backoff, f func() (stop bool, err error),
|
||||||
|
sleep func(context.Context, time.Duration) error) error {
|
||||||
|
var lastErr error
|
||||||
|
for {
|
||||||
|
stop, err := f()
|
||||||
|
if stop {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Remember the last "real" error from f.
|
||||||
|
if err != nil && err != context.Canceled && err != context.DeadlineExceeded {
|
||||||
|
lastErr = err
|
||||||
|
}
|
||||||
|
p := bo.Pause()
|
||||||
|
if cerr := sleep(ctx, p); cerr != nil {
|
||||||
|
if lastErr != nil {
|
||||||
|
return Annotatef(lastErr, "retry failed with %v; last error", cerr)
|
||||||
|
}
|
||||||
|
return cerr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+109
@@ -0,0 +1,109 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
package trace
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"go.opencensus.io/trace"
|
||||||
|
"google.golang.org/api/googleapi"
|
||||||
|
"google.golang.org/genproto/googleapis/rpc/code"
|
||||||
|
"google.golang.org/grpc/status"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StartSpan adds a span to the trace with the given name.
|
||||||
|
func StartSpan(ctx context.Context, name string) context.Context {
|
||||||
|
ctx, _ = trace.StartSpan(ctx, name)
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
// EndSpan ends a span with the given error.
|
||||||
|
func EndSpan(ctx context.Context, err error) {
|
||||||
|
span := trace.FromContext(ctx)
|
||||||
|
if err != nil {
|
||||||
|
span.SetStatus(toStatus(err))
|
||||||
|
}
|
||||||
|
span.End()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
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()}
|
||||||
|
} else {
|
||||||
|
return trace.Status{Code: int32(code.Code_UNKNOWN), Message: err.Error()}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(deklerk): switch to using OpenCensus function when it becomes available.
|
||||||
|
// Reference: https://github.com/googleapis/googleapis/blob/26b634d2724ac5dd30ae0b0cbfb01f07f2e4050e/google/rpc/code.proto
|
||||||
|
func httpStatusCodeToOCCode(httpStatusCode int) int32 {
|
||||||
|
switch httpStatusCode {
|
||||||
|
case 200:
|
||||||
|
return int32(code.Code_OK)
|
||||||
|
case 499:
|
||||||
|
return int32(code.Code_CANCELLED)
|
||||||
|
case 500:
|
||||||
|
return int32(code.Code_UNKNOWN) // Could also be Code_INTERNAL, Code_DATA_LOSS
|
||||||
|
case 400:
|
||||||
|
return int32(code.Code_INVALID_ARGUMENT) // Could also be Code_OUT_OF_RANGE
|
||||||
|
case 504:
|
||||||
|
return int32(code.Code_DEADLINE_EXCEEDED)
|
||||||
|
case 404:
|
||||||
|
return int32(code.Code_NOT_FOUND)
|
||||||
|
case 409:
|
||||||
|
return int32(code.Code_ALREADY_EXISTS) // Could also be Code_ABORTED
|
||||||
|
case 403:
|
||||||
|
return int32(code.Code_PERMISSION_DENIED)
|
||||||
|
case 401:
|
||||||
|
return int32(code.Code_UNAUTHENTICATED)
|
||||||
|
case 429:
|
||||||
|
return int32(code.Code_RESOURCE_EXHAUSTED)
|
||||||
|
case 501:
|
||||||
|
return int32(code.Code_UNIMPLEMENTED)
|
||||||
|
case 503:
|
||||||
|
return int32(code.Code_UNAVAILABLE)
|
||||||
|
default:
|
||||||
|
return int32(code.Code_UNKNOWN)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: (odeke-em): perhaps just pass around spans due to the cost
|
||||||
|
// incurred from using trace.FromContext(ctx) yet we could avoid
|
||||||
|
// throwing away the work done by ctx, span := trace.StartSpan.
|
||||||
|
func TracePrintf(ctx context.Context, attrMap map[string]interface{}, format string, args ...interface{}) {
|
||||||
|
var attrs []trace.Attribute
|
||||||
|
for k, v := range attrMap {
|
||||||
|
var a trace.Attribute
|
||||||
|
switch v := v.(type) {
|
||||||
|
case string:
|
||||||
|
a = trace.StringAttribute(k, v)
|
||||||
|
case bool:
|
||||||
|
a = trace.BoolAttribute(k, v)
|
||||||
|
case int:
|
||||||
|
a = trace.Int64Attribute(k, int64(v))
|
||||||
|
case int64:
|
||||||
|
a = trace.Int64Attribute(k, v)
|
||||||
|
default:
|
||||||
|
a = trace.StringAttribute(k, fmt.Sprintf("%#v", v))
|
||||||
|
}
|
||||||
|
attrs = append(attrs, a)
|
||||||
|
}
|
||||||
|
trace.FromContext(ctx).Annotatef(attrs, format, args...)
|
||||||
|
}
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
today=$(date +%Y%m%d)
|
||||||
|
|
||||||
|
sed -i -r -e 's/const Repo = "([0-9]{8})"/const Repo = "'$today'"/' $GOFILE
|
||||||
|
|
||||||
+71
@@ -0,0 +1,71 @@
|
|||||||
|
// Copyright 2016 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:generate ./update_version.sh
|
||||||
|
|
||||||
|
// Package version contains version information for Google Cloud Client
|
||||||
|
// Libraries for Go, as reported in request headers.
|
||||||
|
package version
|
||||||
|
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"unicode"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Repo is the current version of the client libraries in this
|
||||||
|
// repo. It should be a date in YYYYMMDD format.
|
||||||
|
const Repo = "20201002"
|
||||||
|
|
||||||
|
// Go returns the Go runtime version. The returned string
|
||||||
|
// has no whitespace.
|
||||||
|
func Go() string {
|
||||||
|
return goVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
var goVersion = goVer(runtime.Version())
|
||||||
|
|
||||||
|
const develPrefix = "devel +"
|
||||||
|
|
||||||
|
func goVer(s string) string {
|
||||||
|
if strings.HasPrefix(s, develPrefix) {
|
||||||
|
s = s[len(develPrefix):]
|
||||||
|
if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 {
|
||||||
|
s = s[:p]
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
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 ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func notSemverRune(r rune) bool {
|
||||||
|
return !strings.ContainsRune("0123456789.", r)
|
||||||
|
}
|
||||||
+118
@@ -0,0 +1,118 @@
|
|||||||
|
// Copyright 2020 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 kms is an auto-generated package for the
|
||||||
|
// Cloud Key Management Service (KMS) API.
|
||||||
|
//
|
||||||
|
// Manages keys and performs cryptographic operations in a central cloud
|
||||||
|
// service, for direct use by other cloud resources and applications.
|
||||||
|
//
|
||||||
|
// 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 pkg.go.dev/cloud.google.com/go.
|
||||||
|
package kms // import "cloud.google.com/go/kms/apiv1"
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
const versionClient = "20201002"
|
||||||
|
|
||||||
|
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/cloudkms",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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"
|
||||||
|
}
|
||||||
+40
@@ -0,0 +1,40 @@
|
|||||||
|
// 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
|
||||||
|
//
|
||||||
|
// 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 kms
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cloud.google.com/go/iam"
|
||||||
|
kmspb "google.golang.org/genproto/googleapis/cloud/kms/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// KeyRingIAM returns a handle to inspect and change permissions of a KeyRing.
|
||||||
|
//
|
||||||
|
// Deprecated: Please use ResourceIAM and provide the KeyRing.Name as input.
|
||||||
|
func (c *KeyManagementClient) KeyRingIAM(keyRing *kmspb.KeyRing) *iam.Handle {
|
||||||
|
return iam.InternalNewHandle(c.Connection(), keyRing.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CryptoKeyIAM returns a handle to inspect and change permissions of a CryptoKey.
|
||||||
|
//
|
||||||
|
// Deprecated: Please use ResourceIAM and provide the CryptoKey.Name as input.
|
||||||
|
func (c *KeyManagementClient) CryptoKeyIAM(cryptoKey *kmspb.CryptoKey) *iam.Handle {
|
||||||
|
return iam.InternalNewHandle(c.Connection(), cryptoKey.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResourceIAM returns a handle to inspect and change permissions of the resource
|
||||||
|
// indicated by the given resource path.
|
||||||
|
func (c *KeyManagementClient) ResourceIAM(resourcePath string) *iam.Handle {
|
||||||
|
return iam.InternalNewHandle(c.Connection(), resourcePath)
|
||||||
|
}
|
||||||
+1265
File diff suppressed because it is too large.
Load diff
+330
@@ -0,0 +1,330 @@
|
|||||||
|
// Copyright 2020 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 monitoring
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"net/url"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
gax "github.com/googleapis/gax-go/v2"
|
||||||
|
"google.golang.org/api/iterator"
|
||||||
|
"google.golang.org/api/option"
|
||||||
|
gtransport "google.golang.org/api/transport/grpc"
|
||||||
|
monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/codes"
|
||||||
|
"google.golang.org/grpc/metadata"
|
||||||
|
)
|
||||||
|
|
||||||
|
var newAlertPolicyClientHook clientHook
|
||||||
|
|
||||||
|
// AlertPolicyCallOptions contains the retry settings for each method of AlertPolicyClient.
|
||||||
|
type AlertPolicyCallOptions struct {
|
||||||
|
ListAlertPolicies []gax.CallOption
|
||||||
|
GetAlertPolicy []gax.CallOption
|
||||||
|
CreateAlertPolicy []gax.CallOption
|
||||||
|
DeleteAlertPolicy []gax.CallOption
|
||||||
|
UpdateAlertPolicy []gax.CallOption
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultAlertPolicyClientOptions() []option.ClientOption {
|
||||||
|
return []option.ClientOption{
|
||||||
|
option.WithEndpoint("monitoring.googleapis.com:443"),
|
||||||
|
option.WithGRPCDialOption(grpc.WithDisableServiceConfig()),
|
||||||
|
option.WithScopes(DefaultAuthScopes()...),
|
||||||
|
option.WithGRPCDialOption(grpc.WithDefaultCallOptions(
|
||||||
|
grpc.MaxCallRecvMsgSize(math.MaxInt32))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultAlertPolicyCallOptions() *AlertPolicyCallOptions {
|
||||||
|
return &AlertPolicyCallOptions{
|
||||||
|
ListAlertPolicies: []gax.CallOption{
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnCodes([]codes.Code{
|
||||||
|
codes.DeadlineExceeded,
|
||||||
|
codes.Unavailable,
|
||||||
|
}, gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 30000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
GetAlertPolicy: []gax.CallOption{
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnCodes([]codes.Code{
|
||||||
|
codes.DeadlineExceeded,
|
||||||
|
codes.Unavailable,
|
||||||
|
}, gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 30000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
CreateAlertPolicy: []gax.CallOption{},
|
||||||
|
DeleteAlertPolicy: []gax.CallOption{
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnCodes([]codes.Code{
|
||||||
|
codes.DeadlineExceeded,
|
||||||
|
codes.Unavailable,
|
||||||
|
}, gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 30000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
UpdateAlertPolicy: []gax.CallOption{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AlertPolicyClient is a client for interacting with Cloud Monitoring API.
|
||||||
|
//
|
||||||
|
// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls.
|
||||||
|
type AlertPolicyClient struct {
|
||||||
|
// Connection pool of gRPC connections to the service.
|
||||||
|
connPool gtransport.ConnPool
|
||||||
|
|
||||||
|
// The gRPC API client.
|
||||||
|
alertPolicyClient monitoringpb.AlertPolicyServiceClient
|
||||||
|
|
||||||
|
// The call options for this service.
|
||||||
|
CallOptions *AlertPolicyCallOptions
|
||||||
|
|
||||||
|
// The x-goog-* metadata to be sent with each request.
|
||||||
|
xGoogMetadata metadata.MD
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAlertPolicyClient creates a new alert policy service client.
|
||||||
|
//
|
||||||
|
// The AlertPolicyService API is used to manage (list, create, delete,
|
||||||
|
// edit) alert policies in Stackdriver Monitoring. An alerting policy is
|
||||||
|
// a description of the conditions under which some aspect of your
|
||||||
|
// system is considered to be “unhealthy” and the ways to notify
|
||||||
|
// people or services about this state. In addition to using this API, alert
|
||||||
|
// policies can also be managed through
|
||||||
|
// Stackdriver Monitoring (at https://cloud.google.com/monitoring/docs/),
|
||||||
|
// which can be reached by clicking the “Monitoring” tab in
|
||||||
|
// Cloud Console (at https://console.cloud.google.com/).
|
||||||
|
func NewAlertPolicyClient(ctx context.Context, opts ...option.ClientOption) (*AlertPolicyClient, error) {
|
||||||
|
clientOpts := defaultAlertPolicyClientOptions()
|
||||||
|
|
||||||
|
if newAlertPolicyClientHook != nil {
|
||||||
|
hookOpts, err := newAlertPolicyClientHook(ctx, clientHookParams{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
clientOpts = append(clientOpts, hookOpts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
connPool, err := gtransport.DialPool(ctx, append(clientOpts, opts...)...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
c := &AlertPolicyClient{
|
||||||
|
connPool: connPool,
|
||||||
|
CallOptions: defaultAlertPolicyCallOptions(),
|
||||||
|
|
||||||
|
alertPolicyClient: monitoringpb.NewAlertPolicyServiceClient(connPool),
|
||||||
|
}
|
||||||
|
c.setGoogleClientInfo()
|
||||||
|
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connection returns a connection to the API service.
|
||||||
|
//
|
||||||
|
// Deprecated.
|
||||||
|
func (c *AlertPolicyClient) Connection() *grpc.ClientConn {
|
||||||
|
return c.connPool.Conn()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close closes the connection to the API service. The user should invoke this when
|
||||||
|
// the client is no longer required.
|
||||||
|
func (c *AlertPolicyClient) Close() error {
|
||||||
|
return c.connPool.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 *AlertPolicyClient) setGoogleClientInfo(keyval ...string) {
|
||||||
|
kv := append([]string{"gl-go", versionGo()}, keyval...)
|
||||||
|
kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version)
|
||||||
|
c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListAlertPolicies lists the existing alerting policies for the project.
|
||||||
|
func (c *AlertPolicyClient) ListAlertPolicies(ctx context.Context, req *monitoringpb.ListAlertPoliciesRequest, opts ...gax.CallOption) *AlertPolicyIterator {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.ListAlertPolicies[0:len(c.CallOptions.ListAlertPolicies):len(c.CallOptions.ListAlertPolicies)], opts...)
|
||||||
|
it := &AlertPolicyIterator{}
|
||||||
|
req = proto.Clone(req).(*monitoringpb.ListAlertPoliciesRequest)
|
||||||
|
it.InternalFetch = func(pageSize int, pageToken string) ([]*monitoringpb.AlertPolicy, string, error) {
|
||||||
|
var resp *monitoringpb.ListAlertPoliciesResponse
|
||||||
|
req.PageToken = pageToken
|
||||||
|
if pageSize > math.MaxInt32 {
|
||||||
|
req.PageSize = math.MaxInt32
|
||||||
|
} else {
|
||||||
|
req.PageSize = int32(pageSize)
|
||||||
|
}
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.alertPolicyClient.ListAlertPolicies(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
it.Response = resp
|
||||||
|
return resp.AlertPolicies, resp.NextPageToken, 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.PageSize)
|
||||||
|
it.pageInfo.Token = req.PageToken
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAlertPolicy gets a single alerting policy.
|
||||||
|
func (c *AlertPolicyClient) GetAlertPolicy(ctx context.Context, req *monitoringpb.GetAlertPolicyRequest, opts ...gax.CallOption) (*monitoringpb.AlertPolicy, error) {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.GetAlertPolicy[0:len(c.CallOptions.GetAlertPolicy):len(c.CallOptions.GetAlertPolicy)], opts...)
|
||||||
|
var resp *monitoringpb.AlertPolicy
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.alertPolicyClient.GetAlertPolicy(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateAlertPolicy creates a new alerting policy.
|
||||||
|
func (c *AlertPolicyClient) CreateAlertPolicy(ctx context.Context, req *monitoringpb.CreateAlertPolicyRequest, opts ...gax.CallOption) (*monitoringpb.AlertPolicy, error) {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.CreateAlertPolicy[0:len(c.CallOptions.CreateAlertPolicy):len(c.CallOptions.CreateAlertPolicy)], opts...)
|
||||||
|
var resp *monitoringpb.AlertPolicy
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.alertPolicyClient.CreateAlertPolicy(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteAlertPolicy deletes an alerting policy.
|
||||||
|
func (c *AlertPolicyClient) DeleteAlertPolicy(ctx context.Context, req *monitoringpb.DeleteAlertPolicyRequest, opts ...gax.CallOption) error {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.DeleteAlertPolicy[0:len(c.CallOptions.DeleteAlertPolicy):len(c.CallOptions.DeleteAlertPolicy)], opts...)
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
_, err = c.alertPolicyClient.DeleteAlertPolicy(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateAlertPolicy updates an alerting policy. You can either replace the entire policy with
|
||||||
|
// a new one or replace only certain fields in the current alerting policy by
|
||||||
|
// specifying the fields to be updated via updateMask. Returns the
|
||||||
|
// updated alerting policy.
|
||||||
|
func (c *AlertPolicyClient) UpdateAlertPolicy(ctx context.Context, req *monitoringpb.UpdateAlertPolicyRequest, opts ...gax.CallOption) (*monitoringpb.AlertPolicy, error) {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "alert_policy.name", url.QueryEscape(req.GetAlertPolicy().GetName())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.UpdateAlertPolicy[0:len(c.CallOptions.UpdateAlertPolicy):len(c.CallOptions.UpdateAlertPolicy)], opts...)
|
||||||
|
var resp *monitoringpb.AlertPolicy
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.alertPolicyClient.UpdateAlertPolicy(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AlertPolicyIterator manages a stream of *monitoringpb.AlertPolicy.
|
||||||
|
type AlertPolicyIterator struct {
|
||||||
|
items []*monitoringpb.AlertPolicy
|
||||||
|
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 []*monitoringpb.AlertPolicy, nextPageToken string, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
|
||||||
|
func (it *AlertPolicyIterator) 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 *AlertPolicyIterator) Next() (*monitoringpb.AlertPolicy, error) {
|
||||||
|
var item *monitoringpb.AlertPolicy
|
||||||
|
if err := it.nextFunc(); err != nil {
|
||||||
|
return item, err
|
||||||
|
}
|
||||||
|
item = it.items[0]
|
||||||
|
it.items = it.items[1:]
|
||||||
|
return item, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *AlertPolicyIterator) bufLen() int {
|
||||||
|
return len(it.items)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *AlertPolicyIterator) takeBuf() interface{} {
|
||||||
|
b := it.items
|
||||||
|
it.items = nil
|
||||||
|
return b
|
||||||
|
}
|
||||||
+114
@@ -0,0 +1,114 @@
|
|||||||
|
// Copyright 2020 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 monitoring is an auto-generated package for the
|
||||||
|
// Cloud Monitoring API.
|
||||||
|
//
|
||||||
|
// Manages your Cloud Monitoring data and configurations. Most projects must
|
||||||
|
// be associated with a Workspace, with a few exceptions as noted on the
|
||||||
|
// individual method pages. The table entries below are presented in
|
||||||
|
// alphabetical order, not in order of common use. For explanations of the
|
||||||
|
// concepts found in the table entries, read the [Cloud Monitoring
|
||||||
|
// documentation](https://cloud.google.com/monitoring/docs).
|
||||||
|
//
|
||||||
|
// 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 godoc.org/cloud.google.com/go.
|
||||||
|
//
|
||||||
|
// Deprecated: Please use cloud.google.com/go/monitoring/apiv3/v2.
|
||||||
|
package monitoring // import "cloud.google.com/go/monitoring/apiv3"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"runtime"
|
||||||
|
"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)
|
||||||
|
|
||||||
|
const versionClient = "20200416"
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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/monitoring",
|
||||||
|
"https://www.googleapis.com/auth/monitoring.read",
|
||||||
|
"https://www.googleapis.com/auth/monitoring.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"
|
||||||
|
}
|
||||||
+444
@@ -0,0 +1,444 @@
|
|||||||
|
// Copyright 2020 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 monitoring
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"net/url"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
gax "github.com/googleapis/gax-go/v2"
|
||||||
|
"google.golang.org/api/iterator"
|
||||||
|
"google.golang.org/api/option"
|
||||||
|
gtransport "google.golang.org/api/transport/grpc"
|
||||||
|
monitoredrespb "google.golang.org/genproto/googleapis/api/monitoredres"
|
||||||
|
monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/codes"
|
||||||
|
"google.golang.org/grpc/metadata"
|
||||||
|
)
|
||||||
|
|
||||||
|
var newGroupClientHook clientHook
|
||||||
|
|
||||||
|
// GroupCallOptions contains the retry settings for each method of GroupClient.
|
||||||
|
type GroupCallOptions struct {
|
||||||
|
ListGroups []gax.CallOption
|
||||||
|
GetGroup []gax.CallOption
|
||||||
|
CreateGroup []gax.CallOption
|
||||||
|
UpdateGroup []gax.CallOption
|
||||||
|
DeleteGroup []gax.CallOption
|
||||||
|
ListGroupMembers []gax.CallOption
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultGroupClientOptions() []option.ClientOption {
|
||||||
|
return []option.ClientOption{
|
||||||
|
option.WithEndpoint("monitoring.googleapis.com:443"),
|
||||||
|
option.WithGRPCDialOption(grpc.WithDisableServiceConfig()),
|
||||||
|
option.WithScopes(DefaultAuthScopes()...),
|
||||||
|
option.WithGRPCDialOption(grpc.WithDefaultCallOptions(
|
||||||
|
grpc.MaxCallRecvMsgSize(math.MaxInt32))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultGroupCallOptions() *GroupCallOptions {
|
||||||
|
return &GroupCallOptions{
|
||||||
|
ListGroups: []gax.CallOption{
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnCodes([]codes.Code{
|
||||||
|
codes.DeadlineExceeded,
|
||||||
|
codes.Unavailable,
|
||||||
|
}, gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 30000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
GetGroup: []gax.CallOption{
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnCodes([]codes.Code{
|
||||||
|
codes.DeadlineExceeded,
|
||||||
|
codes.Unavailable,
|
||||||
|
}, gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 30000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
CreateGroup: []gax.CallOption{},
|
||||||
|
UpdateGroup: []gax.CallOption{
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnCodes([]codes.Code{
|
||||||
|
codes.DeadlineExceeded,
|
||||||
|
codes.Unavailable,
|
||||||
|
}, gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 30000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
DeleteGroup: []gax.CallOption{
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnCodes([]codes.Code{
|
||||||
|
codes.DeadlineExceeded,
|
||||||
|
codes.Unavailable,
|
||||||
|
}, gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 30000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
ListGroupMembers: []gax.CallOption{
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnCodes([]codes.Code{
|
||||||
|
codes.DeadlineExceeded,
|
||||||
|
codes.Unavailable,
|
||||||
|
}, gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 30000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GroupClient is a client for interacting with Cloud Monitoring API.
|
||||||
|
//
|
||||||
|
// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls.
|
||||||
|
type GroupClient struct {
|
||||||
|
// Connection pool of gRPC connections to the service.
|
||||||
|
connPool gtransport.ConnPool
|
||||||
|
|
||||||
|
// The gRPC API client.
|
||||||
|
groupClient monitoringpb.GroupServiceClient
|
||||||
|
|
||||||
|
// The call options for this service.
|
||||||
|
CallOptions *GroupCallOptions
|
||||||
|
|
||||||
|
// The x-goog-* metadata to be sent with each request.
|
||||||
|
xGoogMetadata metadata.MD
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGroupClient creates a new group service client.
|
||||||
|
//
|
||||||
|
// The Group API lets you inspect and manage your
|
||||||
|
// groups (at #google.monitoring.v3.Group).
|
||||||
|
//
|
||||||
|
// A group is a named filter that is used to identify
|
||||||
|
// a collection of monitored resources. Groups are typically used to
|
||||||
|
// mirror the physical and/or logical topology of the environment.
|
||||||
|
// Because group membership is computed dynamically, monitored
|
||||||
|
// resources that are started in the future are automatically placed
|
||||||
|
// in matching groups. By using a group to name monitored resources in,
|
||||||
|
// for example, an alert policy, the target of that alert policy is
|
||||||
|
// updated automatically as monitored resources are added and removed
|
||||||
|
// from the infrastructure.
|
||||||
|
func NewGroupClient(ctx context.Context, opts ...option.ClientOption) (*GroupClient, error) {
|
||||||
|
clientOpts := defaultGroupClientOptions()
|
||||||
|
|
||||||
|
if newGroupClientHook != nil {
|
||||||
|
hookOpts, err := newGroupClientHook(ctx, clientHookParams{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
clientOpts = append(clientOpts, hookOpts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
connPool, err := gtransport.DialPool(ctx, append(clientOpts, opts...)...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
c := &GroupClient{
|
||||||
|
connPool: connPool,
|
||||||
|
CallOptions: defaultGroupCallOptions(),
|
||||||
|
|
||||||
|
groupClient: monitoringpb.NewGroupServiceClient(connPool),
|
||||||
|
}
|
||||||
|
c.setGoogleClientInfo()
|
||||||
|
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connection returns a connection to the API service.
|
||||||
|
//
|
||||||
|
// Deprecated.
|
||||||
|
func (c *GroupClient) Connection() *grpc.ClientConn {
|
||||||
|
return c.connPool.Conn()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close closes the connection to the API service. The user should invoke this when
|
||||||
|
// the client is no longer required.
|
||||||
|
func (c *GroupClient) Close() error {
|
||||||
|
return c.connPool.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 *GroupClient) setGoogleClientInfo(keyval ...string) {
|
||||||
|
kv := append([]string{"gl-go", versionGo()}, keyval...)
|
||||||
|
kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version)
|
||||||
|
c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListGroups lists the existing groups.
|
||||||
|
func (c *GroupClient) ListGroups(ctx context.Context, req *monitoringpb.ListGroupsRequest, opts ...gax.CallOption) *GroupIterator {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.ListGroups[0:len(c.CallOptions.ListGroups):len(c.CallOptions.ListGroups)], opts...)
|
||||||
|
it := &GroupIterator{}
|
||||||
|
req = proto.Clone(req).(*monitoringpb.ListGroupsRequest)
|
||||||
|
it.InternalFetch = func(pageSize int, pageToken string) ([]*monitoringpb.Group, string, error) {
|
||||||
|
var resp *monitoringpb.ListGroupsResponse
|
||||||
|
req.PageToken = pageToken
|
||||||
|
if pageSize > math.MaxInt32 {
|
||||||
|
req.PageSize = math.MaxInt32
|
||||||
|
} else {
|
||||||
|
req.PageSize = int32(pageSize)
|
||||||
|
}
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.groupClient.ListGroups(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
it.Response = resp
|
||||||
|
return resp.Group, resp.NextPageToken, 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.PageSize)
|
||||||
|
it.pageInfo.Token = req.PageToken
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGroup gets a single group.
|
||||||
|
func (c *GroupClient) GetGroup(ctx context.Context, req *monitoringpb.GetGroupRequest, opts ...gax.CallOption) (*monitoringpb.Group, error) {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.GetGroup[0:len(c.CallOptions.GetGroup):len(c.CallOptions.GetGroup)], opts...)
|
||||||
|
var resp *monitoringpb.Group
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.groupClient.GetGroup(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateGroup creates a new group.
|
||||||
|
func (c *GroupClient) CreateGroup(ctx context.Context, req *monitoringpb.CreateGroupRequest, opts ...gax.CallOption) (*monitoringpb.Group, error) {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.CreateGroup[0:len(c.CallOptions.CreateGroup):len(c.CallOptions.CreateGroup)], opts...)
|
||||||
|
var resp *monitoringpb.Group
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.groupClient.CreateGroup(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateGroup updates an existing group.
|
||||||
|
// You can change any group attributes except name.
|
||||||
|
func (c *GroupClient) UpdateGroup(ctx context.Context, req *monitoringpb.UpdateGroupRequest, opts ...gax.CallOption) (*monitoringpb.Group, error) {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "group.name", url.QueryEscape(req.GetGroup().GetName())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.UpdateGroup[0:len(c.CallOptions.UpdateGroup):len(c.CallOptions.UpdateGroup)], opts...)
|
||||||
|
var resp *monitoringpb.Group
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.groupClient.UpdateGroup(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteGroup deletes an existing group.
|
||||||
|
func (c *GroupClient) DeleteGroup(ctx context.Context, req *monitoringpb.DeleteGroupRequest, opts ...gax.CallOption) error {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.DeleteGroup[0:len(c.CallOptions.DeleteGroup):len(c.CallOptions.DeleteGroup)], opts...)
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
_, err = c.groupClient.DeleteGroup(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListGroupMembers lists the monitored resources that are members of a group.
|
||||||
|
func (c *GroupClient) ListGroupMembers(ctx context.Context, req *monitoringpb.ListGroupMembersRequest, opts ...gax.CallOption) *MonitoredResourceIterator {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.ListGroupMembers[0:len(c.CallOptions.ListGroupMembers):len(c.CallOptions.ListGroupMembers)], opts...)
|
||||||
|
it := &MonitoredResourceIterator{}
|
||||||
|
req = proto.Clone(req).(*monitoringpb.ListGroupMembersRequest)
|
||||||
|
it.InternalFetch = func(pageSize int, pageToken string) ([]*monitoredrespb.MonitoredResource, string, error) {
|
||||||
|
var resp *monitoringpb.ListGroupMembersResponse
|
||||||
|
req.PageToken = pageToken
|
||||||
|
if pageSize > math.MaxInt32 {
|
||||||
|
req.PageSize = math.MaxInt32
|
||||||
|
} else {
|
||||||
|
req.PageSize = int32(pageSize)
|
||||||
|
}
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.groupClient.ListGroupMembers(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
it.Response = resp
|
||||||
|
return resp.Members, resp.NextPageToken, 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.PageSize)
|
||||||
|
it.pageInfo.Token = req.PageToken
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
|
||||||
|
// GroupIterator manages a stream of *monitoringpb.Group.
|
||||||
|
type GroupIterator struct {
|
||||||
|
items []*monitoringpb.Group
|
||||||
|
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 []*monitoringpb.Group, nextPageToken string, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
|
||||||
|
func (it *GroupIterator) 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 *GroupIterator) Next() (*monitoringpb.Group, error) {
|
||||||
|
var item *monitoringpb.Group
|
||||||
|
if err := it.nextFunc(); err != nil {
|
||||||
|
return item, err
|
||||||
|
}
|
||||||
|
item = it.items[0]
|
||||||
|
it.items = it.items[1:]
|
||||||
|
return item, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *GroupIterator) bufLen() int {
|
||||||
|
return len(it.items)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *GroupIterator) takeBuf() interface{} {
|
||||||
|
b := it.items
|
||||||
|
it.items = nil
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// MonitoredResourceIterator manages a stream of *monitoredrespb.MonitoredResource.
|
||||||
|
type MonitoredResourceIterator struct {
|
||||||
|
items []*monitoredrespb.MonitoredResource
|
||||||
|
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 []*monitoredrespb.MonitoredResource, nextPageToken string, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
|
||||||
|
func (it *MonitoredResourceIterator) 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 *MonitoredResourceIterator) Next() (*monitoredrespb.MonitoredResource, error) {
|
||||||
|
var item *monitoredrespb.MonitoredResource
|
||||||
|
if err := it.nextFunc(); err != nil {
|
||||||
|
return item, err
|
||||||
|
}
|
||||||
|
item = it.items[0]
|
||||||
|
it.items = it.items[1:]
|
||||||
|
return item, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *MonitoredResourceIterator) bufLen() int {
|
||||||
|
return len(it.items)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *MonitoredResourceIterator) takeBuf() interface{} {
|
||||||
|
b := it.items
|
||||||
|
it.items = nil
|
||||||
|
return b
|
||||||
|
}
|
||||||
+557
@@ -0,0 +1,557 @@
|
|||||||
|
// Copyright 2020 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 monitoring
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"net/url"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
gax "github.com/googleapis/gax-go/v2"
|
||||||
|
"google.golang.org/api/iterator"
|
||||||
|
"google.golang.org/api/option"
|
||||||
|
gtransport "google.golang.org/api/transport/grpc"
|
||||||
|
metricpb "google.golang.org/genproto/googleapis/api/metric"
|
||||||
|
monitoredrespb "google.golang.org/genproto/googleapis/api/monitoredres"
|
||||||
|
monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/codes"
|
||||||
|
"google.golang.org/grpc/metadata"
|
||||||
|
)
|
||||||
|
|
||||||
|
var newMetricClientHook clientHook
|
||||||
|
|
||||||
|
// MetricCallOptions contains the retry settings for each method of MetricClient.
|
||||||
|
type MetricCallOptions struct {
|
||||||
|
ListMonitoredResourceDescriptors []gax.CallOption
|
||||||
|
GetMonitoredResourceDescriptor []gax.CallOption
|
||||||
|
ListMetricDescriptors []gax.CallOption
|
||||||
|
GetMetricDescriptor []gax.CallOption
|
||||||
|
CreateMetricDescriptor []gax.CallOption
|
||||||
|
DeleteMetricDescriptor []gax.CallOption
|
||||||
|
ListTimeSeries []gax.CallOption
|
||||||
|
CreateTimeSeries []gax.CallOption
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultMetricClientOptions() []option.ClientOption {
|
||||||
|
return []option.ClientOption{
|
||||||
|
option.WithEndpoint("monitoring.googleapis.com:443"),
|
||||||
|
option.WithGRPCDialOption(grpc.WithDisableServiceConfig()),
|
||||||
|
option.WithScopes(DefaultAuthScopes()...),
|
||||||
|
option.WithGRPCDialOption(grpc.WithDefaultCallOptions(
|
||||||
|
grpc.MaxCallRecvMsgSize(math.MaxInt32))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultMetricCallOptions() *MetricCallOptions {
|
||||||
|
return &MetricCallOptions{
|
||||||
|
ListMonitoredResourceDescriptors: []gax.CallOption{
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnCodes([]codes.Code{
|
||||||
|
codes.DeadlineExceeded,
|
||||||
|
codes.Unavailable,
|
||||||
|
}, gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 30000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
GetMonitoredResourceDescriptor: []gax.CallOption{
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnCodes([]codes.Code{
|
||||||
|
codes.DeadlineExceeded,
|
||||||
|
codes.Unavailable,
|
||||||
|
}, gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 30000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
ListMetricDescriptors: []gax.CallOption{
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnCodes([]codes.Code{
|
||||||
|
codes.DeadlineExceeded,
|
||||||
|
codes.Unavailable,
|
||||||
|
}, gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 30000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
GetMetricDescriptor: []gax.CallOption{
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnCodes([]codes.Code{
|
||||||
|
codes.DeadlineExceeded,
|
||||||
|
codes.Unavailable,
|
||||||
|
}, gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 30000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
CreateMetricDescriptor: []gax.CallOption{},
|
||||||
|
DeleteMetricDescriptor: []gax.CallOption{
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnCodes([]codes.Code{
|
||||||
|
codes.DeadlineExceeded,
|
||||||
|
codes.Unavailable,
|
||||||
|
}, gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 30000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
ListTimeSeries: []gax.CallOption{
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnCodes([]codes.Code{
|
||||||
|
codes.DeadlineExceeded,
|
||||||
|
codes.Unavailable,
|
||||||
|
}, gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 30000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
CreateTimeSeries: []gax.CallOption{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MetricClient is a client for interacting with Cloud Monitoring API.
|
||||||
|
//
|
||||||
|
// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls.
|
||||||
|
type MetricClient struct {
|
||||||
|
// Connection pool of gRPC connections to the service.
|
||||||
|
connPool gtransport.ConnPool
|
||||||
|
|
||||||
|
// The gRPC API client.
|
||||||
|
metricClient monitoringpb.MetricServiceClient
|
||||||
|
|
||||||
|
// The call options for this service.
|
||||||
|
CallOptions *MetricCallOptions
|
||||||
|
|
||||||
|
// The x-goog-* metadata to be sent with each request.
|
||||||
|
xGoogMetadata metadata.MD
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMetricClient creates a new metric service client.
|
||||||
|
//
|
||||||
|
// Manages metric descriptors, monitored resource descriptors, and
|
||||||
|
// time series data.
|
||||||
|
func NewMetricClient(ctx context.Context, opts ...option.ClientOption) (*MetricClient, error) {
|
||||||
|
clientOpts := defaultMetricClientOptions()
|
||||||
|
|
||||||
|
if newMetricClientHook != nil {
|
||||||
|
hookOpts, err := newMetricClientHook(ctx, clientHookParams{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
clientOpts = append(clientOpts, hookOpts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
connPool, err := gtransport.DialPool(ctx, append(clientOpts, opts...)...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
c := &MetricClient{
|
||||||
|
connPool: connPool,
|
||||||
|
CallOptions: defaultMetricCallOptions(),
|
||||||
|
|
||||||
|
metricClient: monitoringpb.NewMetricServiceClient(connPool),
|
||||||
|
}
|
||||||
|
c.setGoogleClientInfo()
|
||||||
|
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connection returns a connection to the API service.
|
||||||
|
//
|
||||||
|
// Deprecated.
|
||||||
|
func (c *MetricClient) Connection() *grpc.ClientConn {
|
||||||
|
return c.connPool.Conn()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close closes the connection to the API service. The user should invoke this when
|
||||||
|
// the client is no longer required.
|
||||||
|
func (c *MetricClient) Close() error {
|
||||||
|
return c.connPool.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 *MetricClient) setGoogleClientInfo(keyval ...string) {
|
||||||
|
kv := append([]string{"gl-go", versionGo()}, keyval...)
|
||||||
|
kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version)
|
||||||
|
c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListMonitoredResourceDescriptors lists monitored resource descriptors that match a filter. This method does not require a Workspace.
|
||||||
|
func (c *MetricClient) ListMonitoredResourceDescriptors(ctx context.Context, req *monitoringpb.ListMonitoredResourceDescriptorsRequest, opts ...gax.CallOption) *MonitoredResourceDescriptorIterator {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.ListMonitoredResourceDescriptors[0:len(c.CallOptions.ListMonitoredResourceDescriptors):len(c.CallOptions.ListMonitoredResourceDescriptors)], opts...)
|
||||||
|
it := &MonitoredResourceDescriptorIterator{}
|
||||||
|
req = proto.Clone(req).(*monitoringpb.ListMonitoredResourceDescriptorsRequest)
|
||||||
|
it.InternalFetch = func(pageSize int, pageToken string) ([]*monitoredrespb.MonitoredResourceDescriptor, string, error) {
|
||||||
|
var resp *monitoringpb.ListMonitoredResourceDescriptorsResponse
|
||||||
|
req.PageToken = pageToken
|
||||||
|
if pageSize > math.MaxInt32 {
|
||||||
|
req.PageSize = math.MaxInt32
|
||||||
|
} else {
|
||||||
|
req.PageSize = int32(pageSize)
|
||||||
|
}
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.metricClient.ListMonitoredResourceDescriptors(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
it.Response = resp
|
||||||
|
return resp.ResourceDescriptors, resp.NextPageToken, 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.PageSize)
|
||||||
|
it.pageInfo.Token = req.PageToken
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMonitoredResourceDescriptor gets a single monitored resource descriptor. This method does not require a Workspace.
|
||||||
|
func (c *MetricClient) GetMonitoredResourceDescriptor(ctx context.Context, req *monitoringpb.GetMonitoredResourceDescriptorRequest, opts ...gax.CallOption) (*monitoredrespb.MonitoredResourceDescriptor, error) {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.GetMonitoredResourceDescriptor[0:len(c.CallOptions.GetMonitoredResourceDescriptor):len(c.CallOptions.GetMonitoredResourceDescriptor)], opts...)
|
||||||
|
var resp *monitoredrespb.MonitoredResourceDescriptor
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.metricClient.GetMonitoredResourceDescriptor(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListMetricDescriptors lists metric descriptors that match a filter. This method does not require a Workspace.
|
||||||
|
func (c *MetricClient) ListMetricDescriptors(ctx context.Context, req *monitoringpb.ListMetricDescriptorsRequest, opts ...gax.CallOption) *MetricDescriptorIterator {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.ListMetricDescriptors[0:len(c.CallOptions.ListMetricDescriptors):len(c.CallOptions.ListMetricDescriptors)], opts...)
|
||||||
|
it := &MetricDescriptorIterator{}
|
||||||
|
req = proto.Clone(req).(*monitoringpb.ListMetricDescriptorsRequest)
|
||||||
|
it.InternalFetch = func(pageSize int, pageToken string) ([]*metricpb.MetricDescriptor, string, error) {
|
||||||
|
var resp *monitoringpb.ListMetricDescriptorsResponse
|
||||||
|
req.PageToken = pageToken
|
||||||
|
if pageSize > math.MaxInt32 {
|
||||||
|
req.PageSize = math.MaxInt32
|
||||||
|
} else {
|
||||||
|
req.PageSize = int32(pageSize)
|
||||||
|
}
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.metricClient.ListMetricDescriptors(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
it.Response = resp
|
||||||
|
return resp.MetricDescriptors, resp.NextPageToken, 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.PageSize)
|
||||||
|
it.pageInfo.Token = req.PageToken
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMetricDescriptor gets a single metric descriptor. This method does not require a Workspace.
|
||||||
|
func (c *MetricClient) GetMetricDescriptor(ctx context.Context, req *monitoringpb.GetMetricDescriptorRequest, opts ...gax.CallOption) (*metricpb.MetricDescriptor, error) {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.GetMetricDescriptor[0:len(c.CallOptions.GetMetricDescriptor):len(c.CallOptions.GetMetricDescriptor)], opts...)
|
||||||
|
var resp *metricpb.MetricDescriptor
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.metricClient.GetMetricDescriptor(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateMetricDescriptor creates a new metric descriptor.
|
||||||
|
// User-created metric descriptors define
|
||||||
|
// custom metrics (at https://cloud.google.com/monitoring/custom-metrics).
|
||||||
|
func (c *MetricClient) CreateMetricDescriptor(ctx context.Context, req *monitoringpb.CreateMetricDescriptorRequest, opts ...gax.CallOption) (*metricpb.MetricDescriptor, error) {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.CreateMetricDescriptor[0:len(c.CallOptions.CreateMetricDescriptor):len(c.CallOptions.CreateMetricDescriptor)], opts...)
|
||||||
|
var resp *metricpb.MetricDescriptor
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.metricClient.CreateMetricDescriptor(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteMetricDescriptor deletes a metric descriptor. Only user-created
|
||||||
|
// custom metrics (at https://cloud.google.com/monitoring/custom-metrics) can be
|
||||||
|
// deleted.
|
||||||
|
func (c *MetricClient) DeleteMetricDescriptor(ctx context.Context, req *monitoringpb.DeleteMetricDescriptorRequest, opts ...gax.CallOption) error {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.DeleteMetricDescriptor[0:len(c.CallOptions.DeleteMetricDescriptor):len(c.CallOptions.DeleteMetricDescriptor)], opts...)
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
_, err = c.metricClient.DeleteMetricDescriptor(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListTimeSeries lists time series that match a filter. This method does not require a Workspace.
|
||||||
|
func (c *MetricClient) ListTimeSeries(ctx context.Context, req *monitoringpb.ListTimeSeriesRequest, opts ...gax.CallOption) *TimeSeriesIterator {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.ListTimeSeries[0:len(c.CallOptions.ListTimeSeries):len(c.CallOptions.ListTimeSeries)], opts...)
|
||||||
|
it := &TimeSeriesIterator{}
|
||||||
|
req = proto.Clone(req).(*monitoringpb.ListTimeSeriesRequest)
|
||||||
|
it.InternalFetch = func(pageSize int, pageToken string) ([]*monitoringpb.TimeSeries, string, error) {
|
||||||
|
var resp *monitoringpb.ListTimeSeriesResponse
|
||||||
|
req.PageToken = pageToken
|
||||||
|
if pageSize > math.MaxInt32 {
|
||||||
|
req.PageSize = math.MaxInt32
|
||||||
|
} else {
|
||||||
|
req.PageSize = int32(pageSize)
|
||||||
|
}
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.metricClient.ListTimeSeries(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
it.Response = resp
|
||||||
|
return resp.TimeSeries, resp.NextPageToken, 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.PageSize)
|
||||||
|
it.pageInfo.Token = req.PageToken
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateTimeSeries creates or adds data to one or more time series.
|
||||||
|
// The response is empty if all time series in the request were written.
|
||||||
|
// If any time series could not be written, a corresponding failure message is
|
||||||
|
// included in the error response.
|
||||||
|
func (c *MetricClient) CreateTimeSeries(ctx context.Context, req *monitoringpb.CreateTimeSeriesRequest, opts ...gax.CallOption) error {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.CreateTimeSeries[0:len(c.CallOptions.CreateTimeSeries):len(c.CallOptions.CreateTimeSeries)], opts...)
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
_, err = c.metricClient.CreateTimeSeries(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// MetricDescriptorIterator manages a stream of *metricpb.MetricDescriptor.
|
||||||
|
type MetricDescriptorIterator struct {
|
||||||
|
items []*metricpb.MetricDescriptor
|
||||||
|
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 []*metricpb.MetricDescriptor, nextPageToken string, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
|
||||||
|
func (it *MetricDescriptorIterator) 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 *MetricDescriptorIterator) Next() (*metricpb.MetricDescriptor, error) {
|
||||||
|
var item *metricpb.MetricDescriptor
|
||||||
|
if err := it.nextFunc(); err != nil {
|
||||||
|
return item, err
|
||||||
|
}
|
||||||
|
item = it.items[0]
|
||||||
|
it.items = it.items[1:]
|
||||||
|
return item, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *MetricDescriptorIterator) bufLen() int {
|
||||||
|
return len(it.items)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *MetricDescriptorIterator) takeBuf() interface{} {
|
||||||
|
b := it.items
|
||||||
|
it.items = nil
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// MonitoredResourceDescriptorIterator manages a stream of *monitoredrespb.MonitoredResourceDescriptor.
|
||||||
|
type MonitoredResourceDescriptorIterator struct {
|
||||||
|
items []*monitoredrespb.MonitoredResourceDescriptor
|
||||||
|
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 []*monitoredrespb.MonitoredResourceDescriptor, nextPageToken string, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
|
||||||
|
func (it *MonitoredResourceDescriptorIterator) 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 *MonitoredResourceDescriptorIterator) Next() (*monitoredrespb.MonitoredResourceDescriptor, error) {
|
||||||
|
var item *monitoredrespb.MonitoredResourceDescriptor
|
||||||
|
if err := it.nextFunc(); err != nil {
|
||||||
|
return item, err
|
||||||
|
}
|
||||||
|
item = it.items[0]
|
||||||
|
it.items = it.items[1:]
|
||||||
|
return item, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *MonitoredResourceDescriptorIterator) bufLen() int {
|
||||||
|
return len(it.items)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *MonitoredResourceDescriptorIterator) takeBuf() interface{} {
|
||||||
|
b := it.items
|
||||||
|
it.items = nil
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// TimeSeriesIterator manages a stream of *monitoringpb.TimeSeries.
|
||||||
|
type TimeSeriesIterator struct {
|
||||||
|
items []*monitoringpb.TimeSeries
|
||||||
|
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 []*monitoringpb.TimeSeries, nextPageToken string, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
|
||||||
|
func (it *TimeSeriesIterator) 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 *TimeSeriesIterator) Next() (*monitoringpb.TimeSeries, error) {
|
||||||
|
var item *monitoringpb.TimeSeries
|
||||||
|
if err := it.nextFunc(); err != nil {
|
||||||
|
return item, err
|
||||||
|
}
|
||||||
|
item = it.items[0]
|
||||||
|
it.items = it.items[1:]
|
||||||
|
return item, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *TimeSeriesIterator) bufLen() int {
|
||||||
|
return len(it.items)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *TimeSeriesIterator) takeBuf() interface{} {
|
||||||
|
b := it.items
|
||||||
|
it.items = nil
|
||||||
|
return b
|
||||||
|
}
|
||||||
+557
@@ -0,0 +1,557 @@
|
|||||||
|
// Copyright 2020 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 monitoring
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"net/url"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
gax "github.com/googleapis/gax-go/v2"
|
||||||
|
"google.golang.org/api/iterator"
|
||||||
|
"google.golang.org/api/option"
|
||||||
|
gtransport "google.golang.org/api/transport/grpc"
|
||||||
|
monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/codes"
|
||||||
|
"google.golang.org/grpc/metadata"
|
||||||
|
)
|
||||||
|
|
||||||
|
var newNotificationChannelClientHook clientHook
|
||||||
|
|
||||||
|
// NotificationChannelCallOptions contains the retry settings for each method of NotificationChannelClient.
|
||||||
|
type NotificationChannelCallOptions struct {
|
||||||
|
ListNotificationChannelDescriptors []gax.CallOption
|
||||||
|
GetNotificationChannelDescriptor []gax.CallOption
|
||||||
|
ListNotificationChannels []gax.CallOption
|
||||||
|
GetNotificationChannel []gax.CallOption
|
||||||
|
CreateNotificationChannel []gax.CallOption
|
||||||
|
UpdateNotificationChannel []gax.CallOption
|
||||||
|
DeleteNotificationChannel []gax.CallOption
|
||||||
|
SendNotificationChannelVerificationCode []gax.CallOption
|
||||||
|
GetNotificationChannelVerificationCode []gax.CallOption
|
||||||
|
VerifyNotificationChannel []gax.CallOption
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultNotificationChannelClientOptions() []option.ClientOption {
|
||||||
|
return []option.ClientOption{
|
||||||
|
option.WithEndpoint("monitoring.googleapis.com:443"),
|
||||||
|
option.WithGRPCDialOption(grpc.WithDisableServiceConfig()),
|
||||||
|
option.WithScopes(DefaultAuthScopes()...),
|
||||||
|
option.WithGRPCDialOption(grpc.WithDefaultCallOptions(
|
||||||
|
grpc.MaxCallRecvMsgSize(math.MaxInt32))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultNotificationChannelCallOptions() *NotificationChannelCallOptions {
|
||||||
|
return &NotificationChannelCallOptions{
|
||||||
|
ListNotificationChannelDescriptors: []gax.CallOption{
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnCodes([]codes.Code{
|
||||||
|
codes.DeadlineExceeded,
|
||||||
|
codes.Unavailable,
|
||||||
|
}, gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 30000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
GetNotificationChannelDescriptor: []gax.CallOption{
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnCodes([]codes.Code{
|
||||||
|
codes.DeadlineExceeded,
|
||||||
|
codes.Unavailable,
|
||||||
|
}, gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 30000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
ListNotificationChannels: []gax.CallOption{
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnCodes([]codes.Code{
|
||||||
|
codes.DeadlineExceeded,
|
||||||
|
codes.Unavailable,
|
||||||
|
}, gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 30000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
GetNotificationChannel: []gax.CallOption{
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnCodes([]codes.Code{
|
||||||
|
codes.DeadlineExceeded,
|
||||||
|
codes.Unavailable,
|
||||||
|
}, gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 30000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
CreateNotificationChannel: []gax.CallOption{},
|
||||||
|
UpdateNotificationChannel: []gax.CallOption{},
|
||||||
|
DeleteNotificationChannel: []gax.CallOption{
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnCodes([]codes.Code{
|
||||||
|
codes.DeadlineExceeded,
|
||||||
|
codes.Unavailable,
|
||||||
|
}, gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 30000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
SendNotificationChannelVerificationCode: []gax.CallOption{},
|
||||||
|
GetNotificationChannelVerificationCode: []gax.CallOption{
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnCodes([]codes.Code{
|
||||||
|
codes.DeadlineExceeded,
|
||||||
|
codes.Unavailable,
|
||||||
|
}, gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 30000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
VerifyNotificationChannel: []gax.CallOption{
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnCodes([]codes.Code{
|
||||||
|
codes.DeadlineExceeded,
|
||||||
|
codes.Unavailable,
|
||||||
|
}, gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 30000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotificationChannelClient is a client for interacting with Cloud Monitoring API.
|
||||||
|
//
|
||||||
|
// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls.
|
||||||
|
type NotificationChannelClient struct {
|
||||||
|
// Connection pool of gRPC connections to the service.
|
||||||
|
connPool gtransport.ConnPool
|
||||||
|
|
||||||
|
// The gRPC API client.
|
||||||
|
notificationChannelClient monitoringpb.NotificationChannelServiceClient
|
||||||
|
|
||||||
|
// The call options for this service.
|
||||||
|
CallOptions *NotificationChannelCallOptions
|
||||||
|
|
||||||
|
// The x-goog-* metadata to be sent with each request.
|
||||||
|
xGoogMetadata metadata.MD
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewNotificationChannelClient creates a new notification channel service client.
|
||||||
|
//
|
||||||
|
// The Notification Channel API provides access to configuration that
|
||||||
|
// controls how messages related to incidents are sent.
|
||||||
|
func NewNotificationChannelClient(ctx context.Context, opts ...option.ClientOption) (*NotificationChannelClient, error) {
|
||||||
|
clientOpts := defaultNotificationChannelClientOptions()
|
||||||
|
|
||||||
|
if newNotificationChannelClientHook != nil {
|
||||||
|
hookOpts, err := newNotificationChannelClientHook(ctx, clientHookParams{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
clientOpts = append(clientOpts, hookOpts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
connPool, err := gtransport.DialPool(ctx, append(clientOpts, opts...)...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
c := &NotificationChannelClient{
|
||||||
|
connPool: connPool,
|
||||||
|
CallOptions: defaultNotificationChannelCallOptions(),
|
||||||
|
|
||||||
|
notificationChannelClient: monitoringpb.NewNotificationChannelServiceClient(connPool),
|
||||||
|
}
|
||||||
|
c.setGoogleClientInfo()
|
||||||
|
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connection returns a connection to the API service.
|
||||||
|
//
|
||||||
|
// Deprecated.
|
||||||
|
func (c *NotificationChannelClient) Connection() *grpc.ClientConn {
|
||||||
|
return c.connPool.Conn()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close closes the connection to the API service. The user should invoke this when
|
||||||
|
// the client is no longer required.
|
||||||
|
func (c *NotificationChannelClient) Close() error {
|
||||||
|
return c.connPool.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 *NotificationChannelClient) setGoogleClientInfo(keyval ...string) {
|
||||||
|
kv := append([]string{"gl-go", versionGo()}, keyval...)
|
||||||
|
kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version)
|
||||||
|
c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListNotificationChannelDescriptors lists the descriptors for supported channel types. The use of descriptors
|
||||||
|
// makes it possible for new channel types to be dynamically added.
|
||||||
|
func (c *NotificationChannelClient) ListNotificationChannelDescriptors(ctx context.Context, req *monitoringpb.ListNotificationChannelDescriptorsRequest, opts ...gax.CallOption) *NotificationChannelDescriptorIterator {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.ListNotificationChannelDescriptors[0:len(c.CallOptions.ListNotificationChannelDescriptors):len(c.CallOptions.ListNotificationChannelDescriptors)], opts...)
|
||||||
|
it := &NotificationChannelDescriptorIterator{}
|
||||||
|
req = proto.Clone(req).(*monitoringpb.ListNotificationChannelDescriptorsRequest)
|
||||||
|
it.InternalFetch = func(pageSize int, pageToken string) ([]*monitoringpb.NotificationChannelDescriptor, string, error) {
|
||||||
|
var resp *monitoringpb.ListNotificationChannelDescriptorsResponse
|
||||||
|
req.PageToken = pageToken
|
||||||
|
if pageSize > math.MaxInt32 {
|
||||||
|
req.PageSize = math.MaxInt32
|
||||||
|
} else {
|
||||||
|
req.PageSize = int32(pageSize)
|
||||||
|
}
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.notificationChannelClient.ListNotificationChannelDescriptors(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
it.Response = resp
|
||||||
|
return resp.ChannelDescriptors, resp.NextPageToken, 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.PageSize)
|
||||||
|
it.pageInfo.Token = req.PageToken
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNotificationChannelDescriptor gets a single channel descriptor. The descriptor indicates which fields
|
||||||
|
// are expected / permitted for a notification channel of the given type.
|
||||||
|
func (c *NotificationChannelClient) GetNotificationChannelDescriptor(ctx context.Context, req *monitoringpb.GetNotificationChannelDescriptorRequest, opts ...gax.CallOption) (*monitoringpb.NotificationChannelDescriptor, error) {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.GetNotificationChannelDescriptor[0:len(c.CallOptions.GetNotificationChannelDescriptor):len(c.CallOptions.GetNotificationChannelDescriptor)], opts...)
|
||||||
|
var resp *monitoringpb.NotificationChannelDescriptor
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.notificationChannelClient.GetNotificationChannelDescriptor(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListNotificationChannels lists the notification channels that have been created for the project.
|
||||||
|
func (c *NotificationChannelClient) ListNotificationChannels(ctx context.Context, req *monitoringpb.ListNotificationChannelsRequest, opts ...gax.CallOption) *NotificationChannelIterator {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.ListNotificationChannels[0:len(c.CallOptions.ListNotificationChannels):len(c.CallOptions.ListNotificationChannels)], opts...)
|
||||||
|
it := &NotificationChannelIterator{}
|
||||||
|
req = proto.Clone(req).(*monitoringpb.ListNotificationChannelsRequest)
|
||||||
|
it.InternalFetch = func(pageSize int, pageToken string) ([]*monitoringpb.NotificationChannel, string, error) {
|
||||||
|
var resp *monitoringpb.ListNotificationChannelsResponse
|
||||||
|
req.PageToken = pageToken
|
||||||
|
if pageSize > math.MaxInt32 {
|
||||||
|
req.PageSize = math.MaxInt32
|
||||||
|
} else {
|
||||||
|
req.PageSize = int32(pageSize)
|
||||||
|
}
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.notificationChannelClient.ListNotificationChannels(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
it.Response = resp
|
||||||
|
return resp.NotificationChannels, resp.NextPageToken, 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.PageSize)
|
||||||
|
it.pageInfo.Token = req.PageToken
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNotificationChannel gets a single notification channel. The channel includes the relevant
|
||||||
|
// configuration details with which the channel was created. However, the
|
||||||
|
// response may truncate or omit passwords, API keys, or other private key
|
||||||
|
// matter and thus the response may not be 100% identical to the information
|
||||||
|
// that was supplied in the call to the create method.
|
||||||
|
func (c *NotificationChannelClient) GetNotificationChannel(ctx context.Context, req *monitoringpb.GetNotificationChannelRequest, opts ...gax.CallOption) (*monitoringpb.NotificationChannel, error) {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.GetNotificationChannel[0:len(c.CallOptions.GetNotificationChannel):len(c.CallOptions.GetNotificationChannel)], opts...)
|
||||||
|
var resp *monitoringpb.NotificationChannel
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.notificationChannelClient.GetNotificationChannel(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateNotificationChannel creates a new notification channel, representing a single notification
|
||||||
|
// endpoint such as an email address, SMS number, or PagerDuty service.
|
||||||
|
func (c *NotificationChannelClient) CreateNotificationChannel(ctx context.Context, req *monitoringpb.CreateNotificationChannelRequest, opts ...gax.CallOption) (*monitoringpb.NotificationChannel, error) {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.CreateNotificationChannel[0:len(c.CallOptions.CreateNotificationChannel):len(c.CallOptions.CreateNotificationChannel)], opts...)
|
||||||
|
var resp *monitoringpb.NotificationChannel
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.notificationChannelClient.CreateNotificationChannel(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateNotificationChannel updates a notification channel. Fields not specified in the field mask
|
||||||
|
// remain unchanged.
|
||||||
|
func (c *NotificationChannelClient) UpdateNotificationChannel(ctx context.Context, req *monitoringpb.UpdateNotificationChannelRequest, opts ...gax.CallOption) (*monitoringpb.NotificationChannel, error) {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "notification_channel.name", url.QueryEscape(req.GetNotificationChannel().GetName())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.UpdateNotificationChannel[0:len(c.CallOptions.UpdateNotificationChannel):len(c.CallOptions.UpdateNotificationChannel)], opts...)
|
||||||
|
var resp *monitoringpb.NotificationChannel
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.notificationChannelClient.UpdateNotificationChannel(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteNotificationChannel deletes a notification channel.
|
||||||
|
func (c *NotificationChannelClient) DeleteNotificationChannel(ctx context.Context, req *monitoringpb.DeleteNotificationChannelRequest, opts ...gax.CallOption) error {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.DeleteNotificationChannel[0:len(c.CallOptions.DeleteNotificationChannel):len(c.CallOptions.DeleteNotificationChannel)], opts...)
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
_, err = c.notificationChannelClient.DeleteNotificationChannel(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendNotificationChannelVerificationCode causes a verification code to be delivered to the channel. The code
|
||||||
|
// can then be supplied in VerifyNotificationChannel to verify the channel.
|
||||||
|
func (c *NotificationChannelClient) SendNotificationChannelVerificationCode(ctx context.Context, req *monitoringpb.SendNotificationChannelVerificationCodeRequest, opts ...gax.CallOption) error {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.SendNotificationChannelVerificationCode[0:len(c.CallOptions.SendNotificationChannelVerificationCode):len(c.CallOptions.SendNotificationChannelVerificationCode)], opts...)
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
_, err = c.notificationChannelClient.SendNotificationChannelVerificationCode(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNotificationChannelVerificationCode requests a verification code for an already verified channel that can then
|
||||||
|
// be used in a call to VerifyNotificationChannel() on a different channel
|
||||||
|
// with an equivalent identity in the same or in a different project. This
|
||||||
|
// makes it possible to copy a channel between projects without requiring
|
||||||
|
// manual reverification of the channel. If the channel is not in the
|
||||||
|
// verified state, this method will fail (in other words, this may only be
|
||||||
|
// used if the SendNotificationChannelVerificationCode and
|
||||||
|
// VerifyNotificationChannel paths have already been used to put the given
|
||||||
|
// channel into the verified state).
|
||||||
|
//
|
||||||
|
// There is no guarantee that the verification codes returned by this method
|
||||||
|
// will be of a similar structure or form as the ones that are delivered
|
||||||
|
// to the channel via SendNotificationChannelVerificationCode; while
|
||||||
|
// VerifyNotificationChannel() will recognize both the codes delivered via
|
||||||
|
// SendNotificationChannelVerificationCode() and returned from
|
||||||
|
// GetNotificationChannelVerificationCode(), it is typically the case that
|
||||||
|
// the verification codes delivered via
|
||||||
|
// SendNotificationChannelVerificationCode() will be shorter and also
|
||||||
|
// have a shorter expiration (e.g. codes such as “G-123456”) whereas
|
||||||
|
// GetVerificationCode() will typically return a much longer, websafe base
|
||||||
|
// 64 encoded string that has a longer expiration time.
|
||||||
|
func (c *NotificationChannelClient) GetNotificationChannelVerificationCode(ctx context.Context, req *monitoringpb.GetNotificationChannelVerificationCodeRequest, opts ...gax.CallOption) (*monitoringpb.GetNotificationChannelVerificationCodeResponse, error) {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.GetNotificationChannelVerificationCode[0:len(c.CallOptions.GetNotificationChannelVerificationCode):len(c.CallOptions.GetNotificationChannelVerificationCode)], opts...)
|
||||||
|
var resp *monitoringpb.GetNotificationChannelVerificationCodeResponse
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.notificationChannelClient.GetNotificationChannelVerificationCode(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyNotificationChannel verifies a NotificationChannel by proving receipt of the code
|
||||||
|
// delivered to the channel as a result of calling
|
||||||
|
// SendNotificationChannelVerificationCode.
|
||||||
|
func (c *NotificationChannelClient) VerifyNotificationChannel(ctx context.Context, req *monitoringpb.VerifyNotificationChannelRequest, opts ...gax.CallOption) (*monitoringpb.NotificationChannel, error) {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.VerifyNotificationChannel[0:len(c.CallOptions.VerifyNotificationChannel):len(c.CallOptions.VerifyNotificationChannel)], opts...)
|
||||||
|
var resp *monitoringpb.NotificationChannel
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.notificationChannelClient.VerifyNotificationChannel(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotificationChannelDescriptorIterator manages a stream of *monitoringpb.NotificationChannelDescriptor.
|
||||||
|
type NotificationChannelDescriptorIterator struct {
|
||||||
|
items []*monitoringpb.NotificationChannelDescriptor
|
||||||
|
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 []*monitoringpb.NotificationChannelDescriptor, nextPageToken string, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
|
||||||
|
func (it *NotificationChannelDescriptorIterator) 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 *NotificationChannelDescriptorIterator) Next() (*monitoringpb.NotificationChannelDescriptor, error) {
|
||||||
|
var item *monitoringpb.NotificationChannelDescriptor
|
||||||
|
if err := it.nextFunc(); err != nil {
|
||||||
|
return item, err
|
||||||
|
}
|
||||||
|
item = it.items[0]
|
||||||
|
it.items = it.items[1:]
|
||||||
|
return item, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *NotificationChannelDescriptorIterator) bufLen() int {
|
||||||
|
return len(it.items)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *NotificationChannelDescriptorIterator) takeBuf() interface{} {
|
||||||
|
b := it.items
|
||||||
|
it.items = nil
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotificationChannelIterator manages a stream of *monitoringpb.NotificationChannel.
|
||||||
|
type NotificationChannelIterator struct {
|
||||||
|
items []*monitoringpb.NotificationChannel
|
||||||
|
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 []*monitoringpb.NotificationChannel, nextPageToken string, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
|
||||||
|
func (it *NotificationChannelIterator) 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 *NotificationChannelIterator) Next() (*monitoringpb.NotificationChannel, error) {
|
||||||
|
var item *monitoringpb.NotificationChannel
|
||||||
|
if err := it.nextFunc(); err != nil {
|
||||||
|
return item, err
|
||||||
|
}
|
||||||
|
item = it.items[0]
|
||||||
|
it.items = it.items[1:]
|
||||||
|
return item, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *NotificationChannelIterator) bufLen() int {
|
||||||
|
return len(it.items)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *NotificationChannelIterator) takeBuf() interface{} {
|
||||||
|
b := it.items
|
||||||
|
it.items = nil
|
||||||
|
return b
|
||||||
|
}
|
||||||
+107
@@ -0,0 +1,107 @@
|
|||||||
|
// 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
|
||||||
|
//
|
||||||
|
// 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 monitoring
|
||||||
|
|
||||||
|
// GroupProjectPath returns the path for the project resource.
|
||||||
|
//
|
||||||
|
// Deprecated: Use
|
||||||
|
// fmt.Sprintf("projects/%s", project)
|
||||||
|
// instead.
|
||||||
|
func GroupProjectPath(project string) string {
|
||||||
|
return "" +
|
||||||
|
"projects/" +
|
||||||
|
project +
|
||||||
|
""
|
||||||
|
}
|
||||||
|
|
||||||
|
// GroupGroupPath returns the path for the group resource.
|
||||||
|
//
|
||||||
|
// Deprecated: Use
|
||||||
|
// fmt.Sprintf("projects/%s/groups/%s", project, group)
|
||||||
|
// instead.
|
||||||
|
func GroupGroupPath(project, group string) string {
|
||||||
|
return "" +
|
||||||
|
"projects/" +
|
||||||
|
project +
|
||||||
|
"/groups/" +
|
||||||
|
group +
|
||||||
|
""
|
||||||
|
}
|
||||||
|
|
||||||
|
// MetricProjectPath returns the path for the project resource.
|
||||||
|
//
|
||||||
|
// Deprecated: Use
|
||||||
|
// fmt.Sprintf("projects/%s", project)
|
||||||
|
// instead.
|
||||||
|
func MetricProjectPath(project string) string {
|
||||||
|
return "" +
|
||||||
|
"projects/" +
|
||||||
|
project +
|
||||||
|
""
|
||||||
|
}
|
||||||
|
|
||||||
|
// MetricMetricDescriptorPath returns the path for the metric descriptor resource.
|
||||||
|
//
|
||||||
|
// Deprecated: Use
|
||||||
|
// fmt.Sprintf("projects/%s/metricDescriptors/%s", project, metricDescriptor)
|
||||||
|
// instead.
|
||||||
|
func MetricMetricDescriptorPath(project, metricDescriptor string) string {
|
||||||
|
return "" +
|
||||||
|
"projects/" +
|
||||||
|
project +
|
||||||
|
"/metricDescriptors/" +
|
||||||
|
metricDescriptor +
|
||||||
|
""
|
||||||
|
}
|
||||||
|
|
||||||
|
// MetricMonitoredResourceDescriptorPath returns the path for the monitored resource descriptor resource.
|
||||||
|
//
|
||||||
|
// Deprecated: Use
|
||||||
|
// fmt.Sprintf("projects/%s/monitoredResourceDescriptors/%s", project, monitoredResourceDescriptor)
|
||||||
|
// instead.
|
||||||
|
func MetricMonitoredResourceDescriptorPath(project, monitoredResourceDescriptor string) string {
|
||||||
|
return "" +
|
||||||
|
"projects/" +
|
||||||
|
project +
|
||||||
|
"/monitoredResourceDescriptors/" +
|
||||||
|
monitoredResourceDescriptor +
|
||||||
|
""
|
||||||
|
}
|
||||||
|
|
||||||
|
// UptimeCheckProjectPath returns the path for the project resource.
|
||||||
|
//
|
||||||
|
// Deprecated: Use
|
||||||
|
// fmt.Sprintf("projects/%s", project)
|
||||||
|
// instead.
|
||||||
|
func UptimeCheckProjectPath(project string) string {
|
||||||
|
return "" +
|
||||||
|
"projects/" +
|
||||||
|
project +
|
||||||
|
""
|
||||||
|
}
|
||||||
|
|
||||||
|
// UptimeCheckUptimeCheckConfigPath returns the path for the uptime check config resource.
|
||||||
|
//
|
||||||
|
// Deprecated: Use
|
||||||
|
// fmt.Sprintf("projects/%s/uptimeCheckConfigs/%s", project, uptimeCheckConfig)
|
||||||
|
// instead.
|
||||||
|
func UptimeCheckUptimeCheckConfigPath(project, uptimeCheckConfig string) string {
|
||||||
|
return "" +
|
||||||
|
"projects/" +
|
||||||
|
project +
|
||||||
|
"/uptimeCheckConfigs/" +
|
||||||
|
uptimeCheckConfig +
|
||||||
|
""
|
||||||
|
}
|
||||||
+517
@@ -0,0 +1,517 @@
|
|||||||
|
// Copyright 2020 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 monitoring
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"net/url"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
gax "github.com/googleapis/gax-go/v2"
|
||||||
|
"google.golang.org/api/iterator"
|
||||||
|
"google.golang.org/api/option"
|
||||||
|
gtransport "google.golang.org/api/transport/grpc"
|
||||||
|
monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/codes"
|
||||||
|
"google.golang.org/grpc/metadata"
|
||||||
|
)
|
||||||
|
|
||||||
|
var newServiceMonitoringClientHook clientHook
|
||||||
|
|
||||||
|
// ServiceMonitoringCallOptions contains the retry settings for each method of ServiceMonitoringClient.
|
||||||
|
type ServiceMonitoringCallOptions struct {
|
||||||
|
CreateService []gax.CallOption
|
||||||
|
GetService []gax.CallOption
|
||||||
|
ListServices []gax.CallOption
|
||||||
|
UpdateService []gax.CallOption
|
||||||
|
DeleteService []gax.CallOption
|
||||||
|
CreateServiceLevelObjective []gax.CallOption
|
||||||
|
GetServiceLevelObjective []gax.CallOption
|
||||||
|
ListServiceLevelObjectives []gax.CallOption
|
||||||
|
UpdateServiceLevelObjective []gax.CallOption
|
||||||
|
DeleteServiceLevelObjective []gax.CallOption
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultServiceMonitoringClientOptions() []option.ClientOption {
|
||||||
|
return []option.ClientOption{
|
||||||
|
option.WithEndpoint("monitoring.googleapis.com:443"),
|
||||||
|
option.WithGRPCDialOption(grpc.WithDisableServiceConfig()),
|
||||||
|
option.WithScopes(DefaultAuthScopes()...),
|
||||||
|
option.WithGRPCDialOption(grpc.WithDefaultCallOptions(
|
||||||
|
grpc.MaxCallRecvMsgSize(math.MaxInt32))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultServiceMonitoringCallOptions() *ServiceMonitoringCallOptions {
|
||||||
|
return &ServiceMonitoringCallOptions{
|
||||||
|
CreateService: []gax.CallOption{},
|
||||||
|
GetService: []gax.CallOption{
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnCodes([]codes.Code{
|
||||||
|
codes.DeadlineExceeded,
|
||||||
|
codes.Unavailable,
|
||||||
|
}, gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 30000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
ListServices: []gax.CallOption{
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnCodes([]codes.Code{
|
||||||
|
codes.DeadlineExceeded,
|
||||||
|
codes.Unavailable,
|
||||||
|
}, gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 30000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
UpdateService: []gax.CallOption{},
|
||||||
|
DeleteService: []gax.CallOption{
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnCodes([]codes.Code{
|
||||||
|
codes.DeadlineExceeded,
|
||||||
|
codes.Unavailable,
|
||||||
|
}, gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 30000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
CreateServiceLevelObjective: []gax.CallOption{},
|
||||||
|
GetServiceLevelObjective: []gax.CallOption{
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnCodes([]codes.Code{
|
||||||
|
codes.DeadlineExceeded,
|
||||||
|
codes.Unavailable,
|
||||||
|
}, gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 30000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
ListServiceLevelObjectives: []gax.CallOption{
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnCodes([]codes.Code{
|
||||||
|
codes.DeadlineExceeded,
|
||||||
|
codes.Unavailable,
|
||||||
|
}, gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 30000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
UpdateServiceLevelObjective: []gax.CallOption{},
|
||||||
|
DeleteServiceLevelObjective: []gax.CallOption{
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnCodes([]codes.Code{
|
||||||
|
codes.DeadlineExceeded,
|
||||||
|
codes.Unavailable,
|
||||||
|
}, gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 30000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServiceMonitoringClient is a client for interacting with Cloud Monitoring API.
|
||||||
|
//
|
||||||
|
// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls.
|
||||||
|
type ServiceMonitoringClient struct {
|
||||||
|
// Connection pool of gRPC connections to the service.
|
||||||
|
connPool gtransport.ConnPool
|
||||||
|
|
||||||
|
// The gRPC API client.
|
||||||
|
serviceMonitoringClient monitoringpb.ServiceMonitoringServiceClient
|
||||||
|
|
||||||
|
// The call options for this service.
|
||||||
|
CallOptions *ServiceMonitoringCallOptions
|
||||||
|
|
||||||
|
// The x-goog-* metadata to be sent with each request.
|
||||||
|
xGoogMetadata metadata.MD
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewServiceMonitoringClient creates a new service monitoring service client.
|
||||||
|
//
|
||||||
|
// The Cloud Monitoring Service-Oriented Monitoring API has endpoints for
|
||||||
|
// managing and querying aspects of a workspace’s services. These include the
|
||||||
|
// Service's monitored resources, its Service-Level Objectives, and a taxonomy
|
||||||
|
// of categorized Health Metrics.
|
||||||
|
func NewServiceMonitoringClient(ctx context.Context, opts ...option.ClientOption) (*ServiceMonitoringClient, error) {
|
||||||
|
clientOpts := defaultServiceMonitoringClientOptions()
|
||||||
|
|
||||||
|
if newServiceMonitoringClientHook != nil {
|
||||||
|
hookOpts, err := newServiceMonitoringClientHook(ctx, clientHookParams{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
clientOpts = append(clientOpts, hookOpts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
connPool, err := gtransport.DialPool(ctx, append(clientOpts, opts...)...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
c := &ServiceMonitoringClient{
|
||||||
|
connPool: connPool,
|
||||||
|
CallOptions: defaultServiceMonitoringCallOptions(),
|
||||||
|
|
||||||
|
serviceMonitoringClient: monitoringpb.NewServiceMonitoringServiceClient(connPool),
|
||||||
|
}
|
||||||
|
c.setGoogleClientInfo()
|
||||||
|
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connection returns a connection to the API service.
|
||||||
|
//
|
||||||
|
// Deprecated.
|
||||||
|
func (c *ServiceMonitoringClient) Connection() *grpc.ClientConn {
|
||||||
|
return c.connPool.Conn()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close closes the connection to the API service. The user should invoke this when
|
||||||
|
// the client is no longer required.
|
||||||
|
func (c *ServiceMonitoringClient) Close() error {
|
||||||
|
return c.connPool.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 *ServiceMonitoringClient) setGoogleClientInfo(keyval ...string) {
|
||||||
|
kv := append([]string{"gl-go", versionGo()}, keyval...)
|
||||||
|
kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version)
|
||||||
|
c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateService create a Service.
|
||||||
|
func (c *ServiceMonitoringClient) CreateService(ctx context.Context, req *monitoringpb.CreateServiceRequest, opts ...gax.CallOption) (*monitoringpb.Service, error) {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.CreateService[0:len(c.CallOptions.CreateService):len(c.CallOptions.CreateService)], opts...)
|
||||||
|
var resp *monitoringpb.Service
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.serviceMonitoringClient.CreateService(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetService get the named Service.
|
||||||
|
func (c *ServiceMonitoringClient) GetService(ctx context.Context, req *monitoringpb.GetServiceRequest, opts ...gax.CallOption) (*monitoringpb.Service, error) {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.GetService[0:len(c.CallOptions.GetService):len(c.CallOptions.GetService)], opts...)
|
||||||
|
var resp *monitoringpb.Service
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.serviceMonitoringClient.GetService(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListServices list Services for this workspace.
|
||||||
|
func (c *ServiceMonitoringClient) ListServices(ctx context.Context, req *monitoringpb.ListServicesRequest, opts ...gax.CallOption) *ServiceIterator {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.ListServices[0:len(c.CallOptions.ListServices):len(c.CallOptions.ListServices)], opts...)
|
||||||
|
it := &ServiceIterator{}
|
||||||
|
req = proto.Clone(req).(*monitoringpb.ListServicesRequest)
|
||||||
|
it.InternalFetch = func(pageSize int, pageToken string) ([]*monitoringpb.Service, string, error) {
|
||||||
|
var resp *monitoringpb.ListServicesResponse
|
||||||
|
req.PageToken = pageToken
|
||||||
|
if pageSize > math.MaxInt32 {
|
||||||
|
req.PageSize = math.MaxInt32
|
||||||
|
} else {
|
||||||
|
req.PageSize = int32(pageSize)
|
||||||
|
}
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.serviceMonitoringClient.ListServices(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
it.Response = resp
|
||||||
|
return resp.Services, resp.NextPageToken, 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.PageSize)
|
||||||
|
it.pageInfo.Token = req.PageToken
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateService update this Service.
|
||||||
|
func (c *ServiceMonitoringClient) UpdateService(ctx context.Context, req *monitoringpb.UpdateServiceRequest, opts ...gax.CallOption) (*monitoringpb.Service, error) {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "service.name", url.QueryEscape(req.GetService().GetName())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.UpdateService[0:len(c.CallOptions.UpdateService):len(c.CallOptions.UpdateService)], opts...)
|
||||||
|
var resp *monitoringpb.Service
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.serviceMonitoringClient.UpdateService(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteService soft delete this Service.
|
||||||
|
func (c *ServiceMonitoringClient) DeleteService(ctx context.Context, req *monitoringpb.DeleteServiceRequest, opts ...gax.CallOption) error {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.DeleteService[0:len(c.CallOptions.DeleteService):len(c.CallOptions.DeleteService)], opts...)
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
_, err = c.serviceMonitoringClient.DeleteService(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateServiceLevelObjective create a ServiceLevelObjective for the given Service.
|
||||||
|
func (c *ServiceMonitoringClient) CreateServiceLevelObjective(ctx context.Context, req *monitoringpb.CreateServiceLevelObjectiveRequest, opts ...gax.CallOption) (*monitoringpb.ServiceLevelObjective, error) {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.CreateServiceLevelObjective[0:len(c.CallOptions.CreateServiceLevelObjective):len(c.CallOptions.CreateServiceLevelObjective)], opts...)
|
||||||
|
var resp *monitoringpb.ServiceLevelObjective
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.serviceMonitoringClient.CreateServiceLevelObjective(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetServiceLevelObjective get a ServiceLevelObjective by name.
|
||||||
|
func (c *ServiceMonitoringClient) GetServiceLevelObjective(ctx context.Context, req *monitoringpb.GetServiceLevelObjectiveRequest, opts ...gax.CallOption) (*monitoringpb.ServiceLevelObjective, error) {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.GetServiceLevelObjective[0:len(c.CallOptions.GetServiceLevelObjective):len(c.CallOptions.GetServiceLevelObjective)], opts...)
|
||||||
|
var resp *monitoringpb.ServiceLevelObjective
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.serviceMonitoringClient.GetServiceLevelObjective(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListServiceLevelObjectives list the ServiceLevelObjectives for the given Service.
|
||||||
|
func (c *ServiceMonitoringClient) ListServiceLevelObjectives(ctx context.Context, req *monitoringpb.ListServiceLevelObjectivesRequest, opts ...gax.CallOption) *ServiceLevelObjectiveIterator {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.ListServiceLevelObjectives[0:len(c.CallOptions.ListServiceLevelObjectives):len(c.CallOptions.ListServiceLevelObjectives)], opts...)
|
||||||
|
it := &ServiceLevelObjectiveIterator{}
|
||||||
|
req = proto.Clone(req).(*monitoringpb.ListServiceLevelObjectivesRequest)
|
||||||
|
it.InternalFetch = func(pageSize int, pageToken string) ([]*monitoringpb.ServiceLevelObjective, string, error) {
|
||||||
|
var resp *monitoringpb.ListServiceLevelObjectivesResponse
|
||||||
|
req.PageToken = pageToken
|
||||||
|
if pageSize > math.MaxInt32 {
|
||||||
|
req.PageSize = math.MaxInt32
|
||||||
|
} else {
|
||||||
|
req.PageSize = int32(pageSize)
|
||||||
|
}
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.serviceMonitoringClient.ListServiceLevelObjectives(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
it.Response = resp
|
||||||
|
return resp.ServiceLevelObjectives, resp.NextPageToken, 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.PageSize)
|
||||||
|
it.pageInfo.Token = req.PageToken
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateServiceLevelObjective update the given ServiceLevelObjective.
|
||||||
|
func (c *ServiceMonitoringClient) UpdateServiceLevelObjective(ctx context.Context, req *monitoringpb.UpdateServiceLevelObjectiveRequest, opts ...gax.CallOption) (*monitoringpb.ServiceLevelObjective, error) {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "service_level_objective.name", url.QueryEscape(req.GetServiceLevelObjective().GetName())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.UpdateServiceLevelObjective[0:len(c.CallOptions.UpdateServiceLevelObjective):len(c.CallOptions.UpdateServiceLevelObjective)], opts...)
|
||||||
|
var resp *monitoringpb.ServiceLevelObjective
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.serviceMonitoringClient.UpdateServiceLevelObjective(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteServiceLevelObjective delete the given ServiceLevelObjective.
|
||||||
|
func (c *ServiceMonitoringClient) DeleteServiceLevelObjective(ctx context.Context, req *monitoringpb.DeleteServiceLevelObjectiveRequest, opts ...gax.CallOption) error {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.DeleteServiceLevelObjective[0:len(c.CallOptions.DeleteServiceLevelObjective):len(c.CallOptions.DeleteServiceLevelObjective)], opts...)
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
_, err = c.serviceMonitoringClient.DeleteServiceLevelObjective(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServiceIterator manages a stream of *monitoringpb.Service.
|
||||||
|
type ServiceIterator struct {
|
||||||
|
items []*monitoringpb.Service
|
||||||
|
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 []*monitoringpb.Service, nextPageToken string, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
|
||||||
|
func (it *ServiceIterator) 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 *ServiceIterator) Next() (*monitoringpb.Service, error) {
|
||||||
|
var item *monitoringpb.Service
|
||||||
|
if err := it.nextFunc(); err != nil {
|
||||||
|
return item, err
|
||||||
|
}
|
||||||
|
item = it.items[0]
|
||||||
|
it.items = it.items[1:]
|
||||||
|
return item, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *ServiceIterator) bufLen() int {
|
||||||
|
return len(it.items)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *ServiceIterator) takeBuf() interface{} {
|
||||||
|
b := it.items
|
||||||
|
it.items = nil
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServiceLevelObjectiveIterator manages a stream of *monitoringpb.ServiceLevelObjective.
|
||||||
|
type ServiceLevelObjectiveIterator struct {
|
||||||
|
items []*monitoringpb.ServiceLevelObjective
|
||||||
|
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 []*monitoringpb.ServiceLevelObjective, nextPageToken string, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
|
||||||
|
func (it *ServiceLevelObjectiveIterator) 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 *ServiceLevelObjectiveIterator) Next() (*monitoringpb.ServiceLevelObjective, error) {
|
||||||
|
var item *monitoringpb.ServiceLevelObjective
|
||||||
|
if err := it.nextFunc(); err != nil {
|
||||||
|
return item, err
|
||||||
|
}
|
||||||
|
item = it.items[0]
|
||||||
|
it.items = it.items[1:]
|
||||||
|
return item, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *ServiceLevelObjectiveIterator) bufLen() int {
|
||||||
|
return len(it.items)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *ServiceLevelObjectiveIterator) takeBuf() interface{} {
|
||||||
|
b := it.items
|
||||||
|
it.items = nil
|
||||||
|
return b
|
||||||
|
}
|
||||||
+432
@@ -0,0 +1,432 @@
|
|||||||
|
// Copyright 2020 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 monitoring
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"net/url"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
gax "github.com/googleapis/gax-go/v2"
|
||||||
|
"google.golang.org/api/iterator"
|
||||||
|
"google.golang.org/api/option"
|
||||||
|
gtransport "google.golang.org/api/transport/grpc"
|
||||||
|
monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/codes"
|
||||||
|
"google.golang.org/grpc/metadata"
|
||||||
|
)
|
||||||
|
|
||||||
|
var newUptimeCheckClientHook clientHook
|
||||||
|
|
||||||
|
// UptimeCheckCallOptions contains the retry settings for each method of UptimeCheckClient.
|
||||||
|
type UptimeCheckCallOptions struct {
|
||||||
|
ListUptimeCheckConfigs []gax.CallOption
|
||||||
|
GetUptimeCheckConfig []gax.CallOption
|
||||||
|
CreateUptimeCheckConfig []gax.CallOption
|
||||||
|
UpdateUptimeCheckConfig []gax.CallOption
|
||||||
|
DeleteUptimeCheckConfig []gax.CallOption
|
||||||
|
ListUptimeCheckIps []gax.CallOption
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultUptimeCheckClientOptions() []option.ClientOption {
|
||||||
|
return []option.ClientOption{
|
||||||
|
option.WithEndpoint("monitoring.googleapis.com:443"),
|
||||||
|
option.WithGRPCDialOption(grpc.WithDisableServiceConfig()),
|
||||||
|
option.WithScopes(DefaultAuthScopes()...),
|
||||||
|
option.WithGRPCDialOption(grpc.WithDefaultCallOptions(
|
||||||
|
grpc.MaxCallRecvMsgSize(math.MaxInt32))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultUptimeCheckCallOptions() *UptimeCheckCallOptions {
|
||||||
|
return &UptimeCheckCallOptions{
|
||||||
|
ListUptimeCheckConfigs: []gax.CallOption{
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnCodes([]codes.Code{
|
||||||
|
codes.DeadlineExceeded,
|
||||||
|
codes.Unavailable,
|
||||||
|
}, gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 30000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
GetUptimeCheckConfig: []gax.CallOption{
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnCodes([]codes.Code{
|
||||||
|
codes.DeadlineExceeded,
|
||||||
|
codes.Unavailable,
|
||||||
|
}, gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 30000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
CreateUptimeCheckConfig: []gax.CallOption{},
|
||||||
|
UpdateUptimeCheckConfig: []gax.CallOption{},
|
||||||
|
DeleteUptimeCheckConfig: []gax.CallOption{
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnCodes([]codes.Code{
|
||||||
|
codes.DeadlineExceeded,
|
||||||
|
codes.Unavailable,
|
||||||
|
}, gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 30000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
ListUptimeCheckIps: []gax.CallOption{
|
||||||
|
gax.WithRetry(func() gax.Retryer {
|
||||||
|
return gax.OnCodes([]codes.Code{
|
||||||
|
codes.DeadlineExceeded,
|
||||||
|
codes.Unavailable,
|
||||||
|
}, gax.Backoff{
|
||||||
|
Initial: 100 * time.Millisecond,
|
||||||
|
Max: 30000 * time.Millisecond,
|
||||||
|
Multiplier: 1.30,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// UptimeCheckClient is a client for interacting with Cloud Monitoring API.
|
||||||
|
//
|
||||||
|
// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls.
|
||||||
|
type UptimeCheckClient struct {
|
||||||
|
// Connection pool of gRPC connections to the service.
|
||||||
|
connPool gtransport.ConnPool
|
||||||
|
|
||||||
|
// The gRPC API client.
|
||||||
|
uptimeCheckClient monitoringpb.UptimeCheckServiceClient
|
||||||
|
|
||||||
|
// The call options for this service.
|
||||||
|
CallOptions *UptimeCheckCallOptions
|
||||||
|
|
||||||
|
// The x-goog-* metadata to be sent with each request.
|
||||||
|
xGoogMetadata metadata.MD
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewUptimeCheckClient creates a new uptime check service client.
|
||||||
|
//
|
||||||
|
// The UptimeCheckService API is used to manage (list, create, delete, edit)
|
||||||
|
// Uptime check configurations in the Stackdriver Monitoring product. An Uptime
|
||||||
|
// check is a piece of configuration that determines which resources and
|
||||||
|
// services to monitor for availability. These configurations can also be
|
||||||
|
// configured interactively by navigating to the [Cloud Console]
|
||||||
|
// (http://console.cloud.google.com (at http://console.cloud.google.com)), selecting the appropriate project,
|
||||||
|
// clicking on “Monitoring” on the left-hand side to navigate to Stackdriver,
|
||||||
|
// and then clicking on “Uptime”.
|
||||||
|
func NewUptimeCheckClient(ctx context.Context, opts ...option.ClientOption) (*UptimeCheckClient, error) {
|
||||||
|
clientOpts := defaultUptimeCheckClientOptions()
|
||||||
|
|
||||||
|
if newUptimeCheckClientHook != nil {
|
||||||
|
hookOpts, err := newUptimeCheckClientHook(ctx, clientHookParams{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
clientOpts = append(clientOpts, hookOpts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
connPool, err := gtransport.DialPool(ctx, append(clientOpts, opts...)...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
c := &UptimeCheckClient{
|
||||||
|
connPool: connPool,
|
||||||
|
CallOptions: defaultUptimeCheckCallOptions(),
|
||||||
|
|
||||||
|
uptimeCheckClient: monitoringpb.NewUptimeCheckServiceClient(connPool),
|
||||||
|
}
|
||||||
|
c.setGoogleClientInfo()
|
||||||
|
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connection returns a connection to the API service.
|
||||||
|
//
|
||||||
|
// Deprecated.
|
||||||
|
func (c *UptimeCheckClient) Connection() *grpc.ClientConn {
|
||||||
|
return c.connPool.Conn()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close closes the connection to the API service. The user should invoke this when
|
||||||
|
// the client is no longer required.
|
||||||
|
func (c *UptimeCheckClient) Close() error {
|
||||||
|
return c.connPool.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 *UptimeCheckClient) setGoogleClientInfo(keyval ...string) {
|
||||||
|
kv := append([]string{"gl-go", versionGo()}, keyval...)
|
||||||
|
kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version)
|
||||||
|
c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListUptimeCheckConfigs lists the existing valid Uptime check configurations for the project
|
||||||
|
// (leaving out any invalid configurations).
|
||||||
|
func (c *UptimeCheckClient) ListUptimeCheckConfigs(ctx context.Context, req *monitoringpb.ListUptimeCheckConfigsRequest, opts ...gax.CallOption) *UptimeCheckConfigIterator {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.ListUptimeCheckConfigs[0:len(c.CallOptions.ListUptimeCheckConfigs):len(c.CallOptions.ListUptimeCheckConfigs)], opts...)
|
||||||
|
it := &UptimeCheckConfigIterator{}
|
||||||
|
req = proto.Clone(req).(*monitoringpb.ListUptimeCheckConfigsRequest)
|
||||||
|
it.InternalFetch = func(pageSize int, pageToken string) ([]*monitoringpb.UptimeCheckConfig, string, error) {
|
||||||
|
var resp *monitoringpb.ListUptimeCheckConfigsResponse
|
||||||
|
req.PageToken = pageToken
|
||||||
|
if pageSize > math.MaxInt32 {
|
||||||
|
req.PageSize = math.MaxInt32
|
||||||
|
} else {
|
||||||
|
req.PageSize = int32(pageSize)
|
||||||
|
}
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.uptimeCheckClient.ListUptimeCheckConfigs(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
it.Response = resp
|
||||||
|
return resp.UptimeCheckConfigs, resp.NextPageToken, 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.PageSize)
|
||||||
|
it.pageInfo.Token = req.PageToken
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUptimeCheckConfig gets a single Uptime check configuration.
|
||||||
|
func (c *UptimeCheckClient) GetUptimeCheckConfig(ctx context.Context, req *monitoringpb.GetUptimeCheckConfigRequest, opts ...gax.CallOption) (*monitoringpb.UptimeCheckConfig, error) {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.GetUptimeCheckConfig[0:len(c.CallOptions.GetUptimeCheckConfig):len(c.CallOptions.GetUptimeCheckConfig)], opts...)
|
||||||
|
var resp *monitoringpb.UptimeCheckConfig
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.uptimeCheckClient.GetUptimeCheckConfig(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateUptimeCheckConfig creates a new Uptime check configuration.
|
||||||
|
func (c *UptimeCheckClient) CreateUptimeCheckConfig(ctx context.Context, req *monitoringpb.CreateUptimeCheckConfigRequest, opts ...gax.CallOption) (*monitoringpb.UptimeCheckConfig, error) {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.CreateUptimeCheckConfig[0:len(c.CallOptions.CreateUptimeCheckConfig):len(c.CallOptions.CreateUptimeCheckConfig)], opts...)
|
||||||
|
var resp *monitoringpb.UptimeCheckConfig
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.uptimeCheckClient.CreateUptimeCheckConfig(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateUptimeCheckConfig updates an Uptime check configuration. You can either replace the entire
|
||||||
|
// configuration with a new one or replace only certain fields in the current
|
||||||
|
// configuration by specifying the fields to be updated via updateMask.
|
||||||
|
// Returns the updated configuration.
|
||||||
|
func (c *UptimeCheckClient) UpdateUptimeCheckConfig(ctx context.Context, req *monitoringpb.UpdateUptimeCheckConfigRequest, opts ...gax.CallOption) (*monitoringpb.UptimeCheckConfig, error) {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "uptime_check_config.name", url.QueryEscape(req.GetUptimeCheckConfig().GetName())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.UpdateUptimeCheckConfig[0:len(c.CallOptions.UpdateUptimeCheckConfig):len(c.CallOptions.UpdateUptimeCheckConfig)], opts...)
|
||||||
|
var resp *monitoringpb.UptimeCheckConfig
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.uptimeCheckClient.UpdateUptimeCheckConfig(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteUptimeCheckConfig deletes an Uptime check configuration. Note that this method will fail
|
||||||
|
// if the Uptime check configuration is referenced by an alert policy or
|
||||||
|
// other dependent configs that would be rendered invalid by the deletion.
|
||||||
|
func (c *UptimeCheckClient) DeleteUptimeCheckConfig(ctx context.Context, req *monitoringpb.DeleteUptimeCheckConfigRequest, opts ...gax.CallOption) error {
|
||||||
|
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName())))
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata, md)
|
||||||
|
opts = append(c.CallOptions.DeleteUptimeCheckConfig[0:len(c.CallOptions.DeleteUptimeCheckConfig):len(c.CallOptions.DeleteUptimeCheckConfig)], opts...)
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
_, err = c.uptimeCheckClient.DeleteUptimeCheckConfig(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListUptimeCheckIps returns the list of IP addresses that checkers run from
|
||||||
|
func (c *UptimeCheckClient) ListUptimeCheckIps(ctx context.Context, req *monitoringpb.ListUptimeCheckIpsRequest, opts ...gax.CallOption) *UptimeCheckIpIterator {
|
||||||
|
ctx = insertMetadata(ctx, c.xGoogMetadata)
|
||||||
|
opts = append(c.CallOptions.ListUptimeCheckIps[0:len(c.CallOptions.ListUptimeCheckIps):len(c.CallOptions.ListUptimeCheckIps)], opts...)
|
||||||
|
it := &UptimeCheckIpIterator{}
|
||||||
|
req = proto.Clone(req).(*monitoringpb.ListUptimeCheckIpsRequest)
|
||||||
|
it.InternalFetch = func(pageSize int, pageToken string) ([]*monitoringpb.UptimeCheckIp, string, error) {
|
||||||
|
var resp *monitoringpb.ListUptimeCheckIpsResponse
|
||||||
|
req.PageToken = pageToken
|
||||||
|
if pageSize > math.MaxInt32 {
|
||||||
|
req.PageSize = math.MaxInt32
|
||||||
|
} else {
|
||||||
|
req.PageSize = int32(pageSize)
|
||||||
|
}
|
||||||
|
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||||
|
var err error
|
||||||
|
resp, err = c.uptimeCheckClient.ListUptimeCheckIps(ctx, req, settings.GRPC...)
|
||||||
|
return err
|
||||||
|
}, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
it.Response = resp
|
||||||
|
return resp.UptimeCheckIps, resp.NextPageToken, 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.PageSize)
|
||||||
|
it.pageInfo.Token = req.PageToken
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
|
||||||
|
// UptimeCheckConfigIterator manages a stream of *monitoringpb.UptimeCheckConfig.
|
||||||
|
type UptimeCheckConfigIterator struct {
|
||||||
|
items []*monitoringpb.UptimeCheckConfig
|
||||||
|
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 []*monitoringpb.UptimeCheckConfig, nextPageToken string, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
|
||||||
|
func (it *UptimeCheckConfigIterator) 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 *UptimeCheckConfigIterator) Next() (*monitoringpb.UptimeCheckConfig, error) {
|
||||||
|
var item *monitoringpb.UptimeCheckConfig
|
||||||
|
if err := it.nextFunc(); err != nil {
|
||||||
|
return item, err
|
||||||
|
}
|
||||||
|
item = it.items[0]
|
||||||
|
it.items = it.items[1:]
|
||||||
|
return item, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *UptimeCheckConfigIterator) bufLen() int {
|
||||||
|
return len(it.items)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *UptimeCheckConfigIterator) takeBuf() interface{} {
|
||||||
|
b := it.items
|
||||||
|
it.items = nil
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// UptimeCheckIpIterator manages a stream of *monitoringpb.UptimeCheckIp.
|
||||||
|
type UptimeCheckIpIterator struct {
|
||||||
|
items []*monitoringpb.UptimeCheckIp
|
||||||
|
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 []*monitoringpb.UptimeCheckIp, nextPageToken string, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
|
||||||
|
func (it *UptimeCheckIpIterator) 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 *UptimeCheckIpIterator) Next() (*monitoringpb.UptimeCheckIp, error) {
|
||||||
|
var item *monitoringpb.UptimeCheckIp
|
||||||
|
if err := it.nextFunc(); err != nil {
|
||||||
|
return item, err
|
||||||
|
}
|
||||||
|
item = it.items[0]
|
||||||
|
it.items = it.items[1:]
|
||||||
|
return item, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *UptimeCheckIpIterator) bufLen() int {
|
||||||
|
return len(it.items)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *UptimeCheckIpIterator) takeBuf() interface{} {
|
||||||
|
b := it.items
|
||||||
|
it.items = nil
|
||||||
|
return b
|
||||||
|
}
|
||||||
+87
@@ -0,0 +1,87 @@
|
|||||||
|
# Changes
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
- Improve documentation for Writer.ChunkSize.
|
||||||
|
- Fix a bug in lifecycle to allow callers to clear lifecycle rules on a bucket.
|
||||||
|
|
||||||
|
## v1.9.0
|
||||||
|
- Add retry for transient network errors on most operations (with the exception
|
||||||
|
of writes).
|
||||||
|
- Bump dependency for google.golang.org/api to capture a change in the default
|
||||||
|
HTTP transport which will improve performance for reads under heavy load.
|
||||||
|
- Add CRC32C checksum validation option to Composer.
|
||||||
|
|
||||||
|
## v1.8.0
|
||||||
|
- Add support for V4 signed post policies.
|
||||||
|
|
||||||
|
## v1.7.0
|
||||||
|
- V4 signed URL support:
|
||||||
|
- Add support for bucket-bound domains and virtual hosted style URLs.
|
||||||
|
- Add support for query parameters in the signature.
|
||||||
|
- Fix text encoding to align with standards.
|
||||||
|
- Add the object name to query parameters for write calls.
|
||||||
|
- Fix retry behavior when reading files with Content-Encoding gzip.
|
||||||
|
- Fix response header in reader.
|
||||||
|
- New code examples:
|
||||||
|
- Error handling for `ObjectHandle` preconditions.
|
||||||
|
- Existence checks for buckets and objects.
|
||||||
|
|
||||||
|
## v1.6.0
|
||||||
|
|
||||||
|
- Updated option handling:
|
||||||
|
- Don't drop custom scopes (#1756)
|
||||||
|
- Don't drop port in provided endpoint (#1737)
|
||||||
|
|
||||||
|
## v1.5.0
|
||||||
|
|
||||||
|
- Honor WithEndpoint client option for reads as well as writes.
|
||||||
|
- Add archive storage class to docs.
|
||||||
|
- Make fixes to storage benchwrapper.
|
||||||
|
|
||||||
|
## v1.4.0
|
||||||
|
|
||||||
|
- When listing objects in a bucket, allow callers to specify which attributes
|
||||||
|
are queried. This allows for performance optimization.
|
||||||
|
|
||||||
|
## v1.3.0
|
||||||
|
|
||||||
|
- Use `storage.googleapis.com/storage/v1` by default for GCS requests
|
||||||
|
instead of `www.googleapis.com/storage/v1`.
|
||||||
|
|
||||||
|
## v1.2.1
|
||||||
|
|
||||||
|
- Fixed a bug where UniformBucketLevelAccess and BucketPolicyOnly were not
|
||||||
|
being sent in all cases.
|
||||||
|
|
||||||
|
## v1.2.0
|
||||||
|
|
||||||
|
- Add support for UniformBucketLevelAccess. This configures access checks
|
||||||
|
to use only bucket-level IAM policies.
|
||||||
|
See: https://godoc.org/cloud.google.com/go/storage#UniformBucketLevelAccess.
|
||||||
|
- Fix userAgent to use correct version.
|
||||||
|
|
||||||
|
## v1.1.2
|
||||||
|
|
||||||
|
- Fix memory leak in BucketIterator and ObjectIterator.
|
||||||
|
|
||||||
|
## v1.1.1
|
||||||
|
|
||||||
|
- Send BucketPolicyOnly even when it's disabled.
|
||||||
|
|
||||||
|
## v1.1.0
|
||||||
|
|
||||||
|
- Performance improvements for ObjectIterator and BucketIterator.
|
||||||
|
- Fix Bucket.ObjectIterator size calculation checks.
|
||||||
|
- Added HMACKeyOptions to all the methods which allows for options such as
|
||||||
|
UserProject to be set per invocation and optionally be used.
|
||||||
|
|
||||||
|
## v1.0.0
|
||||||
|
|
||||||
|
This is the first tag to carve out storage as its own module. See:
|
||||||
|
https://github.com/golang/go/wiki/Modules#is-it-possible-to-add-a-module-to-a-multi-module-repository.
|
||||||
+202
@@ -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.
|
||||||
+32
@@ -0,0 +1,32 @@
|
|||||||
|
## Cloud Storage [](https://godoc.org/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)
|
||||||
|
|
||||||
|
### Example Usage
|
||||||
|
|
||||||
|
First create a `storage.Client` to use throughout your application:
|
||||||
|
|
||||||
|
[snip]:# (storage-1)
|
||||||
|
```go
|
||||||
|
client, err := storage.NewClient(ctx)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
[snip]:# (storage-2)
|
||||||
|
```go
|
||||||
|
// Read the object1 from bucket.
|
||||||
|
rc, err := client.Bucket("bucket").Object("object1").NewReader(ctx)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer rc.Close()
|
||||||
|
body, err := ioutil.ReadAll(rc)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
```
|
||||||
+335
@@ -0,0 +1,335 @@
|
|||||||
|
// 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 storage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"cloud.google.com/go/internal/trace"
|
||||||
|
"google.golang.org/api/googleapi"
|
||||||
|
raw "google.golang.org/api/storage/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ACLRole is the level of access to grant.
|
||||||
|
type ACLRole string
|
||||||
|
|
||||||
|
const (
|
||||||
|
RoleOwner ACLRole = "OWNER"
|
||||||
|
RoleReader ACLRole = "READER"
|
||||||
|
RoleWriter ACLRole = "WRITER"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ACLEntity refers to a user or group.
|
||||||
|
// They are sometimes referred to as grantees.
|
||||||
|
//
|
||||||
|
// It could be in the form of:
|
||||||
|
// "user-<userId>", "user-<email>", "group-<groupId>", "group-<email>",
|
||||||
|
// "domain-<domain>" and "project-team-<projectId>".
|
||||||
|
//
|
||||||
|
// Or one of the predefined constants: AllUsers, AllAuthenticatedUsers.
|
||||||
|
type ACLEntity string
|
||||||
|
|
||||||
|
const (
|
||||||
|
AllUsers ACLEntity = "allUsers"
|
||||||
|
AllAuthenticatedUsers ACLEntity = "allAuthenticatedUsers"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ACLRule represents a grant for a role to an entity (user, group or team) for a
|
||||||
|
// Google Cloud Storage object or bucket.
|
||||||
|
type ACLRule struct {
|
||||||
|
Entity ACLEntity
|
||||||
|
EntityID string
|
||||||
|
Role ACLRole
|
||||||
|
Domain string
|
||||||
|
Email string
|
||||||
|
ProjectTeam *ProjectTeam
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProjectTeam is the project team associated with the entity, if any.
|
||||||
|
type ProjectTeam struct {
|
||||||
|
ProjectNumber string
|
||||||
|
Team string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ACLHandle provides operations on an access control list for a Google Cloud Storage bucket or object.
|
||||||
|
type ACLHandle struct {
|
||||||
|
c *Client
|
||||||
|
bucket string
|
||||||
|
object string
|
||||||
|
isDefault bool
|
||||||
|
userProject string // for requester-pays buckets
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete permanently deletes the ACL entry for the given entity.
|
||||||
|
func (a *ACLHandle) Delete(ctx context.Context, entity ACLEntity) (err error) {
|
||||||
|
ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.ACL.Delete")
|
||||||
|
defer func() { trace.EndSpan(ctx, err) }()
|
||||||
|
|
||||||
|
if a.object != "" {
|
||||||
|
return a.objectDelete(ctx, entity)
|
||||||
|
}
|
||||||
|
if a.isDefault {
|
||||||
|
return a.bucketDefaultDelete(ctx, entity)
|
||||||
|
}
|
||||||
|
return a.bucketDelete(ctx, entity)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set sets the role for the given entity.
|
||||||
|
func (a *ACLHandle) Set(ctx context.Context, entity ACLEntity, role ACLRole) (err error) {
|
||||||
|
ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.ACL.Set")
|
||||||
|
defer func() { trace.EndSpan(ctx, err) }()
|
||||||
|
|
||||||
|
if a.object != "" {
|
||||||
|
return a.objectSet(ctx, entity, role, false)
|
||||||
|
}
|
||||||
|
if a.isDefault {
|
||||||
|
return a.objectSet(ctx, entity, role, true)
|
||||||
|
}
|
||||||
|
return a.bucketSet(ctx, entity, role)
|
||||||
|
}
|
||||||
|
|
||||||
|
// List retrieves ACL entries.
|
||||||
|
func (a *ACLHandle) List(ctx context.Context) (rules []ACLRule, err error) {
|
||||||
|
ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.ACL.List")
|
||||||
|
defer func() { trace.EndSpan(ctx, err) }()
|
||||||
|
|
||||||
|
if a.object != "" {
|
||||||
|
return a.objectList(ctx)
|
||||||
|
}
|
||||||
|
if a.isDefault {
|
||||||
|
return a.bucketDefaultList(ctx)
|
||||||
|
}
|
||||||
|
return a.bucketList(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
a.configureCall(ctx, req)
|
||||||
|
return runWithRetry(ctx, func() error {
|
||||||
|
_, err := req.Do()
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ACLHandle) configureCall(ctx context.Context, call interface{ Header() http.Header }) {
|
||||||
|
vc := reflect.ValueOf(call)
|
||||||
|
vc.MethodByName("Context").Call([]reflect.Value{reflect.ValueOf(ctx)})
|
||||||
|
if a.userProject != "" {
|
||||||
|
vc.MethodByName("UserProject").Call([]reflect.Value{reflect.ValueOf(a.userProject)})
|
||||||
|
}
|
||||||
|
setClientHeader(call.Header())
|
||||||
|
}
|
||||||
|
|
||||||
|
func toObjectACLRules(items []*raw.ObjectAccessControl) []ACLRule {
|
||||||
|
var rs []ACLRule
|
||||||
|
for _, item := range items {
|
||||||
|
rs = append(rs, toObjectACLRule(item))
|
||||||
|
}
|
||||||
|
return rs
|
||||||
|
}
|
||||||
|
|
||||||
|
func toBucketACLRules(items []*raw.BucketAccessControl) []ACLRule {
|
||||||
|
var rs []ACLRule
|
||||||
|
for _, item := range items {
|
||||||
|
rs = append(rs, toBucketACLRule(item))
|
||||||
|
}
|
||||||
|
return rs
|
||||||
|
}
|
||||||
|
|
||||||
|
func toObjectACLRule(a *raw.ObjectAccessControl) ACLRule {
|
||||||
|
return ACLRule{
|
||||||
|
Entity: ACLEntity(a.Entity),
|
||||||
|
EntityID: a.EntityId,
|
||||||
|
Role: ACLRole(a.Role),
|
||||||
|
Domain: a.Domain,
|
||||||
|
Email: a.Email,
|
||||||
|
ProjectTeam: toObjectProjectTeam(a.ProjectTeam),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func toBucketACLRule(a *raw.BucketAccessControl) ACLRule {
|
||||||
|
return ACLRule{
|
||||||
|
Entity: ACLEntity(a.Entity),
|
||||||
|
EntityID: a.EntityId,
|
||||||
|
Role: ACLRole(a.Role),
|
||||||
|
Domain: a.Domain,
|
||||||
|
Email: a.Email,
|
||||||
|
ProjectTeam: toBucketProjectTeam(a.ProjectTeam),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func toRawObjectACL(rules []ACLRule) []*raw.ObjectAccessControl {
|
||||||
|
if len(rules) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
r := make([]*raw.ObjectAccessControl, 0, len(rules))
|
||||||
|
for _, rule := range rules {
|
||||||
|
r = append(r, rule.toRawObjectAccessControl("")) // bucket name unnecessary
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func toRawBucketACL(rules []ACLRule) []*raw.BucketAccessControl {
|
||||||
|
if len(rules) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
r := make([]*raw.BucketAccessControl, 0, len(rules))
|
||||||
|
for _, rule := range rules {
|
||||||
|
r = append(r, rule.toRawBucketAccessControl("")) // bucket name unnecessary
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r ACLRule) toRawBucketAccessControl(bucket string) *raw.BucketAccessControl {
|
||||||
|
return &raw.BucketAccessControl{
|
||||||
|
Bucket: bucket,
|
||||||
|
Entity: string(r.Entity),
|
||||||
|
Role: string(r.Role),
|
||||||
|
// The other fields are not settable.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r ACLRule) toRawObjectAccessControl(bucket string) *raw.ObjectAccessControl {
|
||||||
|
return &raw.ObjectAccessControl{
|
||||||
|
Bucket: bucket,
|
||||||
|
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
|
||||||
|
}
|
||||||
|
return &ProjectTeam{
|
||||||
|
ProjectNumber: p.ProjectNumber,
|
||||||
|
Team: p.Team,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func toObjectProjectTeam(p *raw.ObjectAccessControlProjectTeam) *ProjectTeam {
|
||||||
|
if p == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &ProjectTeam{
|
||||||
|
ProjectNumber: p.ProjectNumber,
|
||||||
|
Team: p.Team,
|
||||||
|
}
|
||||||
|
}
|
||||||
+1306
File diff suppressed because it is too large.
Load diff
+238
@@ -0,0 +1,238 @@
|
|||||||
|
// Copyright 2016 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"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"cloud.google.com/go/internal/trace"
|
||||||
|
raw "google.golang.org/api/storage/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CopierFrom creates a Copier that can copy src to dst.
|
||||||
|
// You can immediately call Run on the returned Copier, or
|
||||||
|
// you can configure it first.
|
||||||
|
//
|
||||||
|
// For Requester Pays buckets, the user project of dst is billed, unless it is empty,
|
||||||
|
// in which case the user project of src is billed.
|
||||||
|
func (dst *ObjectHandle) CopierFrom(src *ObjectHandle) *Copier {
|
||||||
|
return &Copier{dst: dst, src: src}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Copier copies a source object to a destination.
|
||||||
|
type Copier struct {
|
||||||
|
// ObjectAttrs are optional attributes to set on the destination object.
|
||||||
|
// Any attributes must be initialized before any calls on the Copier. Nil
|
||||||
|
// or zero-valued attributes are ignored.
|
||||||
|
ObjectAttrs
|
||||||
|
|
||||||
|
// RewriteToken can be set before calling Run to resume a copy
|
||||||
|
// operation. After Run returns a non-nil error, RewriteToken will
|
||||||
|
// have been updated to contain the value needed to resume the copy.
|
||||||
|
RewriteToken string
|
||||||
|
|
||||||
|
// ProgressFunc can be used to monitor the progress of a multi-RPC copy
|
||||||
|
// operation. If ProgressFunc is not nil and copying requires multiple
|
||||||
|
// calls to the underlying service (see
|
||||||
|
// https://cloud.google.com/storage/docs/json_api/v1/objects/rewrite), then
|
||||||
|
// ProgressFunc will be invoked after each call with the number of bytes of
|
||||||
|
// content copied so far and the total size in bytes of the source object.
|
||||||
|
//
|
||||||
|
// ProgressFunc is intended to make upload progress available to the
|
||||||
|
// application. For example, the implementation of ProgressFunc may update
|
||||||
|
// a progress bar in the application's UI, or log the result of
|
||||||
|
// float64(copiedBytes)/float64(totalBytes).
|
||||||
|
//
|
||||||
|
// ProgressFunc should return quickly without blocking.
|
||||||
|
ProgressFunc func(copiedBytes, totalBytes uint64)
|
||||||
|
|
||||||
|
// The Cloud KMS key, in the form projects/P/locations/L/keyRings/R/cryptoKeys/K,
|
||||||
|
// that will be used to encrypt the object. Overrides the object's KMSKeyName, if
|
||||||
|
// any.
|
||||||
|
//
|
||||||
|
// Providing both a DestinationKMSKeyName and a customer-supplied encryption key
|
||||||
|
// (via ObjectHandle.Key) on the destination object will result in an error when
|
||||||
|
// Run is called.
|
||||||
|
DestinationKMSKeyName string
|
||||||
|
|
||||||
|
dst, src *ObjectHandle
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run performs the copy.
|
||||||
|
func (c *Copier) Run(ctx context.Context) (attrs *ObjectAttrs, err error) {
|
||||||
|
ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Copier.Run")
|
||||||
|
defer func() { trace.EndSpan(ctx, err) }()
|
||||||
|
|
||||||
|
if err := c.src.validate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := c.dst.validate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if c.DestinationKMSKeyName != "" && c.dst.encryptionKey != nil {
|
||||||
|
return nil, errors.New("storage: cannot use DestinationKMSKeyName with a customer-supplied encryption key")
|
||||||
|
}
|
||||||
|
// 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("")
|
||||||
|
for {
|
||||||
|
res, err := c.callRewrite(ctx, rawObject)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if c.ProgressFunc != nil {
|
||||||
|
c.ProgressFunc(uint64(res.TotalBytesRewritten), uint64(res.ObjectSize))
|
||||||
|
}
|
||||||
|
if res.Done { // Finished successfully.
|
||||||
|
return newObject(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.
|
||||||
|
//
|
||||||
|
// The encryption key for the destination object will be used to decrypt all
|
||||||
|
// source objects and encrypt the destination object. It is an error
|
||||||
|
// to specify an encryption key for any of the source objects.
|
||||||
|
func (dst *ObjectHandle) ComposerFrom(srcs ...*ObjectHandle) *Composer {
|
||||||
|
return &Composer{dst: dst, srcs: srcs}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Composer composes source objects into a destination object.
|
||||||
|
//
|
||||||
|
// For Requester Pays buckets, the user project of dst is billed.
|
||||||
|
type Composer struct {
|
||||||
|
// ObjectAttrs are optional attributes to set on the destination object.
|
||||||
|
// Any attributes must be initialized before any calls on the Composer. Nil
|
||||||
|
// or zero-valued attributes are ignored.
|
||||||
|
ObjectAttrs
|
||||||
|
|
||||||
|
// SendCRC specifies whether to transmit a CRC32C field. It should be set
|
||||||
|
// to true in addition to setting the Composer'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 in the destination object does not match
|
||||||
|
// the checksum, the compose will be rejected.
|
||||||
|
SendCRC32C bool
|
||||||
|
|
||||||
|
dst *ObjectHandle
|
||||||
|
srcs []*ObjectHandle
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run performs the compose operation.
|
||||||
|
func (c *Composer) Run(ctx context.Context) (attrs *ObjectAttrs, err error) {
|
||||||
|
ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Composer.Run")
|
||||||
|
defer func() { trace.EndSpan(ctx, err) }()
|
||||||
|
|
||||||
|
if err := c.dst.validate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
if src.bucket != c.dst.bucket {
|
||||||
|
return nil, fmt.Errorf("storage: all source objects must be in bucket %q, found %q", c.dst.bucket, src.bucket)
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
if c.PredefinedACL != "" {
|
||||||
|
call.DestinationPredefinedAcl(c.PredefinedACL)
|
||||||
|
}
|
||||||
|
if err := setEncryptionHeaders(call.Header(), c.dst.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 err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return newObject(obj), nil
|
||||||
|
}
|
||||||
+220
@@ -0,0 +1,220 @@
|
|||||||
|
// Copyright 2016 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 provides an easy way to work with Google Cloud Storage.
|
||||||
|
Google Cloud Storage stores data in named objects, which are grouped into buckets.
|
||||||
|
|
||||||
|
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,
|
||||||
|
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:
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
client, err := storage.NewClient(ctx)
|
||||||
|
if err != nil {
|
||||||
|
// TODO: Handle error.
|
||||||
|
}
|
||||||
|
|
||||||
|
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())
|
||||||
|
|
||||||
|
Buckets
|
||||||
|
|
||||||
|
A Google Cloud Storage bucket is a collection of objects. To work with a
|
||||||
|
bucket, make a bucket handle:
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
If only a subset of object attributes is needed when listing, specifying this
|
||||||
|
subset using Query.SetAttrSelection may speed up the listing process:
|
||||||
|
|
||||||
|
query := &storage.Query{Prefix: ""}
|
||||||
|
query.SetAttrSelection([]string{"Name"})
|
||||||
|
|
||||||
|
// ... as before
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
|
To list the ACLs of a bucket or object, obtain an ACLHandle and call its List method:
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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;
|
||||||
|
the operation only executes if the conditions match. You can use conditions to
|
||||||
|
prevent race conditions in read-modify-write operations.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
if e, ok := err.(*googleapi.Error); ok {
|
||||||
|
if e.Code == 409 { ... }
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
package storage // import "cloud.google.com/go/storage"
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
module cloud.google.com/go/storage
|
||||||
|
|
||||||
|
go 1.11
|
||||||
|
|
||||||
|
require (
|
||||||
|
cloud.google.com/go v0.64.0
|
||||||
|
github.com/golang/protobuf v1.4.2
|
||||||
|
github.com/google/go-cmp v0.5.1
|
||||||
|
github.com/googleapis/gax-go/v2 v2.0.5
|
||||||
|
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
|
||||||
|
golang.org/x/tools v0.0.0-20200827163409-021d7c6f1ec3 // indirect
|
||||||
|
google.golang.org/api v0.30.0
|
||||||
|
google.golang.org/genproto v0.0.0-20200827165113-ac2560b5e952
|
||||||
|
google.golang.org/grpc v1.31.0
|
||||||
|
)
|
||||||
+500
@@ -0,0 +1,500 @@
|
|||||||
|
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 h1:AVXDdKsrtX33oR9fbCMu/+c1o8Ofjq6Ku/MInaLVg5Y=
|
||||||
|
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 h1:GGslhk/BU052LPlnI1vpp3fcbUs+hQ3E+Doti/3/vF8=
|
||||||
|
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
||||||
|
cloud.google.com/go v0.53.0 h1:MZQCQQaRwOrAcuKjiHWHrgKykt4fZyuwF2dtiG3fGW8=
|
||||||
|
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
||||||
|
cloud.google.com/go v0.54.0 h1:3ithwDMr7/3vpAMXiH+ZQnYbuIsh+OPhUPMFC9enmn0=
|
||||||
|
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
||||||
|
cloud.google.com/go v0.56.0 h1:WRz29PgAsVEyPSDHyk+0fpEkwEFyfhHn+JbksT6gIL4=
|
||||||
|
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||||
|
cloud.google.com/go v0.57.0 h1:EpMNVUorLiZIELdMZbCYX/ByTFCdoYopYAGxaGVz9ms=
|
||||||
|
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||||
|
cloud.google.com/go v0.62.0 h1:RmDygqvj27Zf3fCQjQRtLyC7KwFcHkeJitcO0OoGOcA=
|
||||||
|
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||||
|
cloud.google.com/go v0.64.0 h1:xVP3LPvMjGT4J0a55y02Gw5y/dkY/rxGz58sfK1jqIo=
|
||||||
|
cloud.google.com/go v0.64.0/go.mod h1:xfORb36jGvE+6EexW71nMEtL025s3x6xvuYUKM4JLv4=
|
||||||
|
cloud.google.com/go/bigquery v1.0.1 h1:hL+ycaJpVE9M7nLoiXb/Pn10ENE2u+oddxbD8uu0ZVU=
|
||||||
|
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||||
|
cloud.google.com/go/bigquery v1.3.0 h1:sAbMqjY1PEQKZBWfbu6Y6bsupJ9c4QdHnzg/VvYTLcE=
|
||||||
|
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||||
|
cloud.google.com/go/bigquery v1.4.0 h1:xE3CPsOgttP4ACBePh79zTKALtXwn/Edhcr16R5hMWU=
|
||||||
|
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||||
|
cloud.google.com/go/bigquery v1.5.0 h1:K2NyuHRuv15ku6eUpe0DQk5ZykPMnSOnvuVf6IHcjaE=
|
||||||
|
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||||
|
cloud.google.com/go/bigquery v1.7.0 h1:a/O/bK/vWrYGOTFtH8di4rBxMZnmkjy+Y5LxpDwo+dA=
|
||||||
|
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 h1:Kt+gOPPp2LEPWp8CSfxhsM8ik9CcyE/gYu+0r+RnZvM=
|
||||||
|
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||||
|
cloud.google.com/go/datastore v1.1.0 h1:/May9ojXjRkPBNVrq+oWLqmWCkr4OU5uRY29bu0mRyQ=
|
||||||
|
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||||
|
cloud.google.com/go/pubsub v1.0.1 h1:W9tAK3E57P75u0XLLR82LZyw8VpAnhmyTOxW9qzmyj8=
|
||||||
|
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||||
|
cloud.google.com/go/pubsub v1.1.0 h1:9/vpR43S4aJaROxqQHQ3nH9lfyKKV0dC3vOmnw8ebQQ=
|
||||||
|
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||||
|
cloud.google.com/go/pubsub v1.2.0 h1:Lpy6hKgdcl7a3WGSfJIFmxmcdjSpP6OmBEfcOv1Y680=
|
||||||
|
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||||
|
cloud.google.com/go/pubsub v1.3.1 h1:ukjixP1wl0LpnZ6LWtZJ0mX5tBmjp1f8Sqer8Z2OMUU=
|
||||||
|
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
|
||||||
|
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||||
|
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||||
|
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||||
|
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||||
|
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||||
|
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||||
|
github.com/BurntSushi/toml v0.3.1 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/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
|
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||||
|
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||||
|
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||||
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
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/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
|
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||||
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
|
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7 h1:5ZkaAPbicIKTF2I64qf5Fh8Aa83Q/dnOafMYV0OMwjA=
|
||||||
|
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
|
||||||
|
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||||
|
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||||
|
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||||
|
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||||
|
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||||
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||||
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
|
||||||
|
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||||
|
github.com/golang/protobuf v1.3.4 h1:87PNWwrRvUSnqS4dlcBU/ftvOIBep4sYuBLlh6rX2wk=
|
||||||
|
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||||
|
github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls=
|
||||||
|
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 h1:oOuy+ugB+P/kBdUnG5QaMXSIyJ1q38wWSojYCb3z5VQ=
|
||||||
|
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||||
|
github.com/golang/protobuf v1.4.1 h1:ZFgWrT+bLgsYPirOnRfKLYJLvssAegOj/hgyMFdJZe0=
|
||||||
|
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||||
|
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
|
||||||
|
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
|
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
|
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
|
||||||
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
|
||||||
|
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 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
|
||||||
|
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k=
|
||||||
|
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
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 h1:pMen7vLs8nvgEYhywH3KDWJIJTeEr2ULsVWHWYHQyBs=
|
||||||
|
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||||
|
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
|
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
|
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
|
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
|
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
|
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
|
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
|
github.com/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/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
|
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
|
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024 h1:rBMNdlhTLzJjJSDIjNEXX1Pz3Hmwmz91v+zycvx9PJc=
|
||||||
|
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/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||||
|
go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4=
|
||||||
|
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||||
|
go.opencensus.io v0.22.2 h1:75k/FF0Q2YM8QYo07VPddOLBslDt1MZOdEslOHvmzAs=
|
||||||
|
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
|
go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8=
|
||||||
|
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
|
go.opencensus.io v0.22.4 h1:LYy1Hy3MJdrCdMwwzxA/dRok4ejH+RwNGbuoD9fCjto=
|
||||||
|
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
|
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/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 h1:Agxu5KLo8o7Bb634SVDnhIfpTvxmzUwhbYAzBvXt6h4=
|
||||||
|
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 h1:zQpM52jfKHG6II1ISZY1ZcpygvuSFZpLwfluuF89XOg=
|
||||||
|
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||||
|
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a h1:7Wlg8L54In96HTWOaI4sreLJ6qfyGuvSau5el3fK41Y=
|
||||||
|
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||||
|
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd h1:zkO/Lhoka23X63N9OSzpSeROEUQ5ODw47tM3YWjygbs=
|
||||||
|
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||||
|
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y=
|
||||||
|
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 h1:8R1esu+8QioDxo4E4mX6bFztO+dMTM49DNAaWfO5OeY=
|
||||||
|
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 h1:J5lckAjkw6qYlOZNj90mLYNTEKDvWeuc1yieZ8qUzUE=
|
||||||
|
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||||
|
golang.org/x/lint v0.0.0-20200130185559-910be7a94367 h1:0IiAsCRByjO2QjX7ZPkw5oU9x+n1YqRL802rjC0c3Aw=
|
||||||
|
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 h1:WG0RUwxtNT4qqaXX3DPA8zHFNm/D9xaBpxzHt1WcA/E=
|
||||||
|
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 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
|
||||||
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
|
||||||
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
|
||||||
|
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 h1:F+8P+gmewFQYRk6JoLQLwjBCTu3mcIURZfNkVweuRKA=
|
||||||
|
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 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI=
|
||||||
|
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8=
|
||||||
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0=
|
||||||
|
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k=
|
||||||
|
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
|
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5 h1:WQ8q63x+f/zpC8Ac1s9wLElVoHhm32p6tudrU72n1QA=
|
||||||
|
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 h1:eDrdRpKgkcCqKZQwyZRyeFZgfqt37SL7Kv3tok06cKE=
|
||||||
|
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
|
golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4=
|
||||||
|
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
|
golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
|
||||||
|
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
|
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc h1:zK/HqS5bZxDptfPJNq8v7vJfXtkU7r9TLIoSr1bXaP4=
|
||||||
|
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
|
||||||
|
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 h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
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 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
|
||||||
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03iWnKLEWinaScsxF2Vm2o=
|
||||||
|
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/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0 h1:HyfiK1WMnHj5FXFXatD+Qs1A/xC2Run6RzeW1SyHxpc=
|
||||||
|
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 h1:gZpLHxUX5BdYLA08Lj4YCJNN/jk7KtquiArPoeX0WvA=
|
||||||
|
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82 h1:ywK/j/KkyTHcdyYSZNXGjMwgmDSfjglYZ3vStQ/gSCU=
|
||||||
|
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 h1:LfCXLvNmTYH9kEmVgqbnsWfruoXZIrh4YBgqVHtDvw0=
|
||||||
|
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4 h1:sfkvUWPNGwSV+8/fNqctR5lS2AqCSqYwXdrjCxp/dXo=
|
||||||
|
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
|
||||||
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So=
|
||||||
|
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
|
||||||
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d h1:nc5K6ox/4lTFbMVSL9WRR81ixkcwXThoiF6yf+R9scA=
|
||||||
|
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e h1:hq86ru83GdWTlfQFZGO4nZJTU4Bs2wfHl8oFHRaXsfc=
|
||||||
|
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 h1:rITEj+UZHYC927n8GT97eC3zrpzXdb/voyeOuVKS46o=
|
||||||
|
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642 h1:B6caxRw+hozq68X2MY7jEpZh/cr4/aHLv9xU8Kkadrw=
|
||||||
|
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||||
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
|
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.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 h1:On1qIo75ByTwFJ4/W2bIqHcwJ9XAqtSWUs8GwRrIhtc=
|
||||||
|
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200117161641-43d50277825c h1:2EA2K0k9bcvvEDlqD8xdlOhCOqq+O/p9Voqi4x9W1YU=
|
||||||
|
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a h1:7YaEqUc1tUg0yDwvdX+3U5bwrBg7u3FFAZ5D8gUs4/c=
|
||||||
|
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 h1:KW20qMcLRWuIgjdCpHFJbVZA7zsDKtFXPNcm7/eI5ZA=
|
||||||
|
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 h1:DFtSed2q3HtNuVazwVDZ4nSRS/JrZEig0gz2BY4VNrg=
|
||||||
|
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 h1:7M9AXzLrJWWGdDYtBblPHBTnHtaN6KKQ98OYb35mLlY=
|
||||||
|
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb h1:iKlO7ROJc6SttHKlxzwGytRtBUqX4VARrNTgP2YLX5M=
|
||||||
|
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||||
|
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d h1:3K34ovZAOnVaUPxanr0j4ghTZTPTA0CnXvjCl+5lZqk=
|
||||||
|
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||||
|
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4 h1:kDtqNkeBrZb8B+atrj50B5XLHpzXXqcCdZPP/ApQ5NY=
|
||||||
|
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 h1:lzLdP95xJmMpwQ6LUHwrc5V7js93hTiY7gkznu0BgmY=
|
||||||
|
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 h1:szSOL78iTCl0LF1AMjhSWJj8tIM0KixlUUnBtYXsmd8=
|
||||||
|
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||||
|
golang.org/x/tools v0.0.0-20200817023811-d00afeaade8f h1:33yHANSyO/TeglgY9rBhUpX43wtonTXoFOsMRtNB6qE=
|
||||||
|
golang.org/x/tools v0.0.0-20200817023811-d00afeaade8f/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||||
|
golang.org/x/tools v0.0.0-20200827163409-021d7c6f1ec3 h1:OjYQxZBKJFs+sJbHkvSGIKNMkZXDJQ9JsMpebGhkafI=
|
||||||
|
golang.org/x/tools v0.0.0-20200827163409-021d7c6f1ec3/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||||
|
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||||
|
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||||
|
google.golang.org/api v0.9.0 h1:jbyannxz0XFD3zdjgrSUsaJbgpH4eTrkdhRChkHPfO8=
|
||||||
|
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 h1:yzlyyDW/J0w8yNFJIhiAJy4kq74S+1DOLdawELNxFMA=
|
||||||
|
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||||
|
google.golang.org/api v0.17.0 h1:0q95w+VuFtv4PAx4PZVQdBMmYbaCHbnfKaEiDIcVyag=
|
||||||
|
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 h1:GwFK8+l5/gdsOYKz5p6M4UK+QT8OvmHWZPJCnf+5DjA=
|
||||||
|
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||||
|
google.golang.org/api v0.20.0 h1:jz2KixHX7EcCPiQrySzPdnYT7DbINAypCqKZ1Z7GM40=
|
||||||
|
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||||
|
google.golang.org/api v0.22.0 h1:J1Pl9P2lnmYFSJvgs70DKELqHNh8CNWXPbud4njEE2s=
|
||||||
|
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||||
|
google.golang.org/api v0.24.0 h1:cG03eaksBzhfSIk7JRGctfp3lanklcOM/mTGvow7BbQ=
|
||||||
|
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||||
|
google.golang.org/api v0.28.0 h1:jMF5hhVfMkTZwHW1SDpKq5CkgWLXOb31Foaca9Zr3oM=
|
||||||
|
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||||
|
google.golang.org/api v0.29.0 h1:BaiDisFir8O4IJxvAabCGGkQ6yCJegNQqSVoYUNAnbk=
|
||||||
|
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||||
|
google.golang.org/api v0.30.0 h1:yfrXXP61wVuLb0vBcG6qaOoIoqYEzOQS8jum51jkv2w=
|
||||||
|
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||||
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I=
|
||||||
|
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||||
|
google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
|
||||||
|
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
|
google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc=
|
||||||
|
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51 h1:Ex1mq5jaJof+kRnYi3SlYJ8KKa9Ao3NHyIT5XJ1gF6U=
|
||||||
|
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 h1:pRj9OXZbwNtbtZtOB4dLwfK4u+EVRMvP+e9zKkg2grM=
|
||||||
|
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150 h1:VPpdpQkGvFicX9yo4G5oxZPi9ALBnEOZblPSa/Wa2m4=
|
||||||
|
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90 h1:7THRSvPuzF1bql5kyFzX0JM0vpGhwuhskgJrJsbZ80Y=
|
||||||
|
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
|
||||||
|
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce h1:1mbrb1tUU+Zmt5C94IGKADBTJZjZXAd+BubWi7r9EiI=
|
||||||
|
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 h1:Vo0fD5w0fUKriWlZLyrim2GXbumyN0D6euW79T9PgEE=
|
||||||
|
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto v0.0.0-20200305110556-506484158171 h1:xes2Q2k+d/+YNXVw0FpZkIDJiaux4OVrRKXRAzH6A0U=
|
||||||
|
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672 h1:jiDSspVssiikoRPFHT6pYrL+CL6/yIc3b9AuHO/4xik=
|
||||||
|
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940 h1:MRHtG0U6SnaUb+s+LhNE1qt1FQ1wlhqr5E4usBKC0uA=
|
||||||
|
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84 h1:pSLkPbrjnPyLDYUO2VM9mDLqo2V6CFBY84lFSZAfoi4=
|
||||||
|
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 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
|
||||||
|
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 h1:Lq4llNryJoaVFRmvrIwC/ZHH7tNt4tUYIu8+se2aayY=
|
||||||
|
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20200815001618-f69a88009b70 h1:wboULUXGF3c5qdUnKp+6gLAccE6PRpa/czkYvQ4UXv8=
|
||||||
|
google.golang.org/genproto v0.0.0-20200815001618-f69a88009b70/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20200827165113-ac2560b5e952 h1:y857ZwFJ60XFsJ00vOc7ouVMLOZp7C+7h03pESkILFY=
|
||||||
|
google.golang.org/genproto v0.0.0-20200827165113-ac2560b5e952/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
|
google.golang.org/grpc v1.21.1 h1:j6XxA85m/6txkUCHvzlV5f+HBNl/1r5cZ2A/3IEFOO8=
|
||||||
|
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 h1:2dTRdpdFEEhJYQD8EMLB61nnrzSCTbG38PhqdhvOltg=
|
||||||
|
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
|
google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg=
|
||||||
|
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
|
google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk=
|
||||||
|
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
|
google.golang.org/grpc v1.28.0 h1:bO/TA4OxCOummhSf10siHuG7vJOiwh7SpRpFZDkOgl4=
|
||||||
|
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||||
|
google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4=
|
||||||
|
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||||
|
google.golang.org/grpc v1.30.0 h1:M5a8xTlYTxwMn5ZFkwhRabsygDY5G8TYLyQDBxJNAxE=
|
||||||
|
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
|
google.golang.org/grpc v1.31.0 h1:T7P4R73V3SSDPhH7WW7ATbfViLtmamH0DKrP3f9AuDI=
|
||||||
|
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
|
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 h1:qdOKuR/EIArgaWNjetjgTzgVTAZ+S/WXVrq9HW9zimw=
|
||||||
|
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||||
|
google.golang.org/protobuf v1.22.0 h1:cJv5/xdbk1NnMPR1VP9+HU6gupuG9MLBoH1r6RHZ2MY=
|
||||||
|
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
|
||||||
|
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc h1:TnonUr8u3himcMY0vSh23jFOXA+cnucl1gB6EQTReBI=
|
||||||
|
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA=
|
||||||
|
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||||
|
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
|
||||||
|
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
||||||
|
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||||
|
honnef.co/go/tools v0.0.1-2020.1.3 h1:sXmLre5bzIR6ypkjXCDI3jHPssRhc8KD/Ome589sc3U=
|
||||||
|
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||||
|
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||||
|
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||||
|
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||||
|
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||||
+48
@@ -0,0 +1,48 @@
|
|||||||
|
// 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
|
||||||
|
}
|
||||||
|
}
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
// This file, and the cloud.google.com/go import, won't actually become part of
|
||||||
|
// the resultant binary.
|
||||||
|
// +build modhack
|
||||||
|
|
||||||
|
package storage
|
||||||
|
|
||||||
|
// 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"
|
||||||
+441
@@ -0,0 +1,441 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
package storage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"google.golang.org/api/iterator"
|
||||||
|
raw "google.golang.org/api/storage/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HMACState is the state of the HMAC key.
|
||||||
|
//
|
||||||
|
// This type is EXPERIMENTAL and subject to change or removal without notice.
|
||||||
|
type HMACState string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Active is the status for an active key that can be used to sign
|
||||||
|
// requests.
|
||||||
|
Active HMACState = "ACTIVE"
|
||||||
|
|
||||||
|
// Inactive is the status for an inactive key thus requests signed by
|
||||||
|
// this key will be denied.
|
||||||
|
Inactive HMACState = "INACTIVE"
|
||||||
|
|
||||||
|
// Deleted is the status for a key that is deleted.
|
||||||
|
// Once in this state the key cannot key cannot be recovered
|
||||||
|
// and does not count towards key limits. Deleted keys will be cleaned
|
||||||
|
// up later.
|
||||||
|
Deleted HMACState = "DELETED"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HMACKey is the representation of a Google Cloud Storage HMAC key.
|
||||||
|
//
|
||||||
|
// HMAC keys are used to authenticate signed access to objects. To enable HMAC key
|
||||||
|
// authentication, please visit https://cloud.google.com/storage/docs/migrating.
|
||||||
|
//
|
||||||
|
// This type is EXPERIMENTAL and subject to change or removal without notice.
|
||||||
|
type HMACKey struct {
|
||||||
|
// The HMAC's secret key.
|
||||||
|
Secret string
|
||||||
|
|
||||||
|
// AccessID is the ID of the HMAC key.
|
||||||
|
AccessID string
|
||||||
|
|
||||||
|
// Etag is the HTTP/1.1 Entity tag.
|
||||||
|
Etag string
|
||||||
|
|
||||||
|
// ID is the ID of the HMAC key, including the ProjectID and AccessID.
|
||||||
|
ID string
|
||||||
|
|
||||||
|
// ProjectID is the ID of the project that owns the
|
||||||
|
// service account to which the key authenticates.
|
||||||
|
ProjectID string
|
||||||
|
|
||||||
|
// ServiceAccountEmail is the email address
|
||||||
|
// of the key's associated service account.
|
||||||
|
ServiceAccountEmail string
|
||||||
|
|
||||||
|
// CreatedTime is the creation time of the HMAC key.
|
||||||
|
CreatedTime time.Time
|
||||||
|
|
||||||
|
// UpdatedTime is the last modification time of the HMAC key metadata.
|
||||||
|
UpdatedTime time.Time
|
||||||
|
|
||||||
|
// State is the state of the HMAC key.
|
||||||
|
// It can be one of StateActive, StateInactive or StateDeleted.
|
||||||
|
State HMACState
|
||||||
|
}
|
||||||
|
|
||||||
|
// HMACKeyHandle helps provide access and management for HMAC keys.
|
||||||
|
//
|
||||||
|
// This type is EXPERIMENTAL and subject to change or removal without notice.
|
||||||
|
type HMACKeyHandle struct {
|
||||||
|
projectID string
|
||||||
|
accessID string
|
||||||
|
|
||||||
|
raw *raw.ProjectsHmacKeysService
|
||||||
|
}
|
||||||
|
|
||||||
|
// HMACKeyHandle creates a handle that will be used for HMACKey operations.
|
||||||
|
//
|
||||||
|
// This method is EXPERIMENTAL and subject to change or removal without notice.
|
||||||
|
func (c *Client) HMACKeyHandle(projectID, accessID string) *HMACKeyHandle {
|
||||||
|
return &HMACKeyHandle{
|
||||||
|
projectID: projectID,
|
||||||
|
accessID: accessID,
|
||||||
|
raw: raw.NewProjectsHmacKeysService(c.raw),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get invokes an RPC to retrieve the HMAC key referenced by the
|
||||||
|
// HMACKeyHandle's accessID.
|
||||||
|
//
|
||||||
|
// Options such as UserProjectForHMACKeys can be used to set the
|
||||||
|
// userProject to be billed against for operations.
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
hkPb := &raw.HmacKey{
|
||||||
|
Metadata: metadata,
|
||||||
|
}
|
||||||
|
return pbHmacKeyToHMACKey(hkPb, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete invokes an RPC to delete the key referenced by accessID, on Google Cloud Storage.
|
||||||
|
// Only inactive HMAC keys can be deleted.
|
||||||
|
// After deletion, a key cannot be used to authenticate requests.
|
||||||
|
//
|
||||||
|
// 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()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func pbHmacKeyToHMACKey(pb *raw.HmacKey, updatedTimeCanBeNil bool) (*HMACKey, error) {
|
||||||
|
pbmd := pb.Metadata
|
||||||
|
if pbmd == nil {
|
||||||
|
return nil, errors.New("field Metadata cannot be nil")
|
||||||
|
}
|
||||||
|
createdTime, err := time.Parse(time.RFC3339, pbmd.TimeCreated)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("field CreatedTime: %v", err)
|
||||||
|
}
|
||||||
|
updatedTime, err := time.Parse(time.RFC3339, pbmd.Updated)
|
||||||
|
if err != nil && !updatedTimeCanBeNil {
|
||||||
|
return nil, fmt.Errorf("field UpdatedTime: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
hmk := &HMACKey{
|
||||||
|
AccessID: pbmd.AccessId,
|
||||||
|
Secret: pb.Secret,
|
||||||
|
Etag: pbmd.Etag,
|
||||||
|
ID: pbmd.Id,
|
||||||
|
State: HMACState(pbmd.State),
|
||||||
|
ProjectID: pbmd.ProjectId,
|
||||||
|
CreatedTime: createdTime,
|
||||||
|
UpdatedTime: updatedTime,
|
||||||
|
|
||||||
|
ServiceAccountEmail: pbmd.ServiceAccountEmail,
|
||||||
|
}
|
||||||
|
|
||||||
|
return hmk, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateHMACKey invokes an RPC for Google Cloud Storage to create a new HMACKey.
|
||||||
|
//
|
||||||
|
// This method is EXPERIMENTAL and subject to change or removal without notice.
|
||||||
|
func (c *Client) CreateHMACKey(ctx context.Context, projectID, serviceAccountEmail string, opts ...HMACKeyOption) (*HMACKey, error) {
|
||||||
|
if projectID == "" {
|
||||||
|
return nil, errors.New("storage: expecting a non-blank projectID")
|
||||||
|
}
|
||||||
|
if serviceAccountEmail == "" {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HMACKeyAttrsToUpdate defines the attributes of an HMACKey that will be updated.
|
||||||
|
//
|
||||||
|
// This type is EXPERIMENTAL and subject to change or removal without notice.
|
||||||
|
type HMACKeyAttrsToUpdate struct {
|
||||||
|
// State is required and must be either StateActive or StateInactive.
|
||||||
|
State HMACState
|
||||||
|
|
||||||
|
// Etag is an optional field and it is the HTTP/1.1 Entity tag.
|
||||||
|
Etag string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update mutates the HMACKey referred to by accessID.
|
||||||
|
//
|
||||||
|
// This method is EXPERIMENTAL and subject to change or removal without notice.
|
||||||
|
func (h *HMACKeyHandle) Update(ctx context.Context, au HMACKeyAttrsToUpdate, opts ...HMACKeyOption) (*HMACKey, error) {
|
||||||
|
if au.State != Active && au.State != Inactive {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// An HMACKeysIterator is an iterator over HMACKeys.
|
||||||
|
//
|
||||||
|
// Note: This iterator is not safe for concurrent operations without explicit synchronization.
|
||||||
|
//
|
||||||
|
// This type is EXPERIMENTAL and subject to change or removal without notice.
|
||||||
|
type HMACKeysIterator struct {
|
||||||
|
ctx context.Context
|
||||||
|
raw *raw.ProjectsHmacKeysService
|
||||||
|
projectID string
|
||||||
|
hmacKeys []*HMACKey
|
||||||
|
pageInfo *iterator.PageInfo
|
||||||
|
nextFunc func() error
|
||||||
|
index int
|
||||||
|
desc hmacKeyDesc
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListHMACKeys returns an iterator for listing HMACKeys.
|
||||||
|
//
|
||||||
|
// Note: This iterator is not safe for concurrent operations without explicit synchronization.
|
||||||
|
//
|
||||||
|
// 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,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt.withHMACKeyDesc(&it.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
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next returns the next result. Its second return value is iterator.Done if
|
||||||
|
// there are no more results. Once Next returns iterator.Done, all subsequent
|
||||||
|
// calls will return iterator.Done.
|
||||||
|
//
|
||||||
|
// Note: This iterator is not safe for concurrent operations without explicit synchronization.
|
||||||
|
//
|
||||||
|
// This method is EXPERIMENTAL and subject to change or removal without notice.
|
||||||
|
func (it *HMACKeysIterator) Next() (*HMACKey, error) {
|
||||||
|
if err := it.nextFunc(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
key := it.hmacKeys[it.index]
|
||||||
|
it.index++
|
||||||
|
|
||||||
|
return key, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
|
||||||
|
//
|
||||||
|
// Note: This iterator is not safe for concurrent operations without explicit synchronization.
|
||||||
|
//
|
||||||
|
// This method is EXPERIMENTAL and subject to change or removal without notice.
|
||||||
|
func (it *HMACKeysIterator) PageInfo() *iterator.PageInfo { return it.pageInfo }
|
||||||
|
|
||||||
|
func (it *HMACKeysIterator) fetch(pageSize int, pageToken string) (token string, err error) {
|
||||||
|
call := it.raw.List(it.projectID)
|
||||||
|
setClientHeader(call.Header())
|
||||||
|
if pageToken != "" {
|
||||||
|
call = call.PageToken(pageToken)
|
||||||
|
}
|
||||||
|
if it.desc.showDeletedKeys {
|
||||||
|
call = call.ShowDeletedKeys(true)
|
||||||
|
}
|
||||||
|
if it.desc.userProjectID != "" {
|
||||||
|
call = call.UserProject(it.desc.userProjectID)
|
||||||
|
}
|
||||||
|
if it.desc.forServiceAccountEmail != "" {
|
||||||
|
call = call.ServiceAccountEmail(it.desc.forServiceAccountEmail)
|
||||||
|
}
|
||||||
|
if pageSize > 0 {
|
||||||
|
call = call.MaxResults(int64(pageSize))
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := it.ctx
|
||||||
|
var resp *raw.HmacKeysMetadata
|
||||||
|
err = runWithRetry(it.ctx, func() error {
|
||||||
|
resp, err = call.Context(ctx).Do()
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, metadata := range resp.Items {
|
||||||
|
hkPb := &raw.HmacKey{
|
||||||
|
Metadata: metadata,
|
||||||
|
}
|
||||||
|
hkey, err := pbHmacKeyToHMACKey(hkPb, true)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
it.hmacKeys = append(it.hmacKeys, hkey)
|
||||||
|
}
|
||||||
|
return resp.NextPageToken, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type hmacKeyDesc struct {
|
||||||
|
forServiceAccountEmail string
|
||||||
|
showDeletedKeys bool
|
||||||
|
userProjectID string
|
||||||
|
}
|
||||||
|
|
||||||
|
// HMACKeyOption configures the behavior of HMACKey related methods and actions.
|
||||||
|
//
|
||||||
|
// This interface is EXPERIMENTAL and subject to change or removal without notice.
|
||||||
|
type HMACKeyOption interface {
|
||||||
|
withHMACKeyDesc(*hmacKeyDesc)
|
||||||
|
}
|
||||||
|
|
||||||
|
type hmacKeyDescFunc func(*hmacKeyDesc)
|
||||||
|
|
||||||
|
func (hkdf hmacKeyDescFunc) withHMACKeyDesc(hkd *hmacKeyDesc) {
|
||||||
|
hkdf(hkd)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ForHMACKeyServiceAccountEmail returns HMAC Keys that are
|
||||||
|
// associated with the email address of a service account in the project.
|
||||||
|
//
|
||||||
|
// Only one service account email can be used as a filter, so if multiple
|
||||||
|
// of these options are applied, the last email to be set will be used.
|
||||||
|
//
|
||||||
|
// This option is EXPERIMENTAL and subject to change or removal without notice.
|
||||||
|
func ForHMACKeyServiceAccountEmail(serviceAccountEmail string) HMACKeyOption {
|
||||||
|
return hmacKeyDescFunc(func(hkd *hmacKeyDesc) {
|
||||||
|
hkd.forServiceAccountEmail = serviceAccountEmail
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ShowDeletedHMACKeys will also list keys whose state is "DELETED".
|
||||||
|
//
|
||||||
|
// This option is EXPERIMENTAL and subject to change or removal without notice.
|
||||||
|
func ShowDeletedHMACKeys() HMACKeyOption {
|
||||||
|
return hmacKeyDescFunc(func(hkd *hmacKeyDesc) {
|
||||||
|
hkd.showDeletedKeys = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserProjectForHMACKeys will bill the request against userProjectID
|
||||||
|
// if userProjectID is non-empty.
|
||||||
|
//
|
||||||
|
// Note: This is a noop right now and only provided for API compatibility.
|
||||||
|
//
|
||||||
|
// This option is EXPERIMENTAL and subject to change or removal without notice.
|
||||||
|
func UserProjectForHMACKeys(userProjectID string) HMACKeyOption {
|
||||||
|
return hmacKeyDescFunc(func(hkd *hmacKeyDesc) {
|
||||||
|
hkd.userProjectID = userProjectID
|
||||||
|
})
|
||||||
|
}
|
||||||
+162
@@ -0,0 +1,162 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
package storage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"cloud.google.com/go/iam"
|
||||||
|
"cloud.google.com/go/internal/trace"
|
||||||
|
raw "google.golang.org/api/storage/v1"
|
||||||
|
iampb "google.golang.org/genproto/googleapis/iam/v1"
|
||||||
|
"google.golang.org/genproto/googleapis/type/expr"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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,
|
||||||
|
}, b.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// iamClient implements the iam.client interface.
|
||||||
|
type iamClient struct {
|
||||||
|
raw *raw.Service
|
||||||
|
userProject string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *iamClient) Get(ctx context.Context, resource string) (p *iampb.Policy, err error) {
|
||||||
|
return c.GetWithVersion(ctx, resource, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *iamClient) GetWithVersion(ctx context.Context, resource string, requestedPolicyVersion int32) (p *iampb.Policy, err error) {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
func iamToStoragePolicy(ip *iampb.Policy) *raw.Policy {
|
||||||
|
return &raw.Policy{
|
||||||
|
Bindings: iamToStorageBindings(ip.Bindings),
|
||||||
|
Etag: string(ip.Etag),
|
||||||
|
Version: int64(ip.Version),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func iamToStorageBindings(ibs []*iampb.Binding) []*raw.PolicyBindings {
|
||||||
|
var rbs []*raw.PolicyBindings
|
||||||
|
for _, ib := range ibs {
|
||||||
|
rbs = append(rbs, &raw.PolicyBindings{
|
||||||
|
Role: ib.Role,
|
||||||
|
Members: ib.Members,
|
||||||
|
Condition: iamToStorageCondition(ib.Condition),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return rbs
|
||||||
|
}
|
||||||
|
|
||||||
|
func iamToStorageCondition(exprpb *expr.Expr) *raw.Expr {
|
||||||
|
if exprpb == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &raw.Expr{
|
||||||
|
Expression: exprpb.Expression,
|
||||||
|
Description: exprpb.Description,
|
||||||
|
Location: exprpb.Location,
|
||||||
|
Title: exprpb.Title,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func iamFromStoragePolicy(rp *raw.Policy) *iampb.Policy {
|
||||||
|
return &iampb.Policy{
|
||||||
|
Bindings: iamFromStorageBindings(rp.Bindings),
|
||||||
|
Etag: []byte(rp.Etag),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func iamFromStorageBindings(rbs []*raw.PolicyBindings) []*iampb.Binding {
|
||||||
|
var ibs []*iampb.Binding
|
||||||
|
for _, rb := range rbs {
|
||||||
|
ibs = append(ibs, &iampb.Binding{
|
||||||
|
Role: rb.Role,
|
||||||
|
Members: rb.Members,
|
||||||
|
Condition: iamFromStorageCondition(rb.Condition),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return ibs
|
||||||
|
}
|
||||||
|
|
||||||
|
func iamFromStorageCondition(rawexpr *raw.Expr) *expr.Expr {
|
||||||
|
if rawexpr == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &expr.Expr{
|
||||||
|
Expression: rawexpr.Expression,
|
||||||
|
Description: rawexpr.Description,
|
||||||
|
Location: rawexpr.Location,
|
||||||
|
Title: rawexpr.Title,
|
||||||
|
}
|
||||||
|
}
|
||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
// 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 storage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"cloud.google.com/go/internal"
|
||||||
|
gax "github.com/googleapis/gax-go/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
err = call()
|
||||||
|
if err == nil {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
if shouldRetry(err) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return true, err
|
||||||
|
})
|
||||||
|
}
|
||||||
+42
@@ -0,0 +1,42 @@
|
|||||||
|
// 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
|
||||||
|
}
|
||||||
|
}
|
||||||
+188
@@ -0,0 +1,188 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
package storage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
|
"cloud.google.com/go/internal/trace"
|
||||||
|
raw "google.golang.org/api/storage/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Notification describes how to send Cloud PubSub messages when certain
|
||||||
|
// events occur in a bucket.
|
||||||
|
type Notification struct {
|
||||||
|
//The ID of the notification.
|
||||||
|
ID string
|
||||||
|
|
||||||
|
// The ID of the topic to which this subscription publishes.
|
||||||
|
TopicID string
|
||||||
|
|
||||||
|
// The ID of the project to which the topic belongs.
|
||||||
|
TopicProjectID string
|
||||||
|
|
||||||
|
// Only send notifications about listed event types. If empty, send notifications
|
||||||
|
// for all event types.
|
||||||
|
// See https://cloud.google.com/storage/docs/pubsub-notifications#events.
|
||||||
|
EventTypes []string
|
||||||
|
|
||||||
|
// If present, only apply this notification configuration to object names that
|
||||||
|
// begin with this prefix.
|
||||||
|
ObjectNamePrefix string
|
||||||
|
|
||||||
|
// An optional list of additional attributes to attach to each Cloud PubSub
|
||||||
|
// message published for this notification subscription.
|
||||||
|
CustomAttributes map[string]string
|
||||||
|
|
||||||
|
// The contents of the message payload.
|
||||||
|
// See https://cloud.google.com/storage/docs/pubsub-notifications#payload.
|
||||||
|
PayloadFormat string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Values for Notification.PayloadFormat.
|
||||||
|
const (
|
||||||
|
// Send no payload with notification messages.
|
||||||
|
NoPayload = "NONE"
|
||||||
|
|
||||||
|
// Send object metadata as JSON with notification messages.
|
||||||
|
JSONPayload = "JSON_API_V1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Values for Notification.EventTypes.
|
||||||
|
const (
|
||||||
|
// Event that occurs when an object is successfully created.
|
||||||
|
ObjectFinalizeEvent = "OBJECT_FINALIZE"
|
||||||
|
|
||||||
|
// Event that occurs when the metadata of an existing object changes.
|
||||||
|
ObjectMetadataUpdateEvent = "OBJECT_METADATA_UPDATE"
|
||||||
|
|
||||||
|
// Event that occurs when an object is permanently deleted.
|
||||||
|
ObjectDeleteEvent = "OBJECT_DELETE"
|
||||||
|
|
||||||
|
// Event that occurs when the live version of an object becomes an
|
||||||
|
// archived version.
|
||||||
|
ObjectArchiveEvent = "OBJECT_ARCHIVE"
|
||||||
|
)
|
||||||
|
|
||||||
|
func toNotification(rn *raw.Notification) *Notification {
|
||||||
|
n := &Notification{
|
||||||
|
ID: rn.Id,
|
||||||
|
EventTypes: rn.EventTypes,
|
||||||
|
ObjectNamePrefix: rn.ObjectNamePrefix,
|
||||||
|
CustomAttributes: rn.CustomAttributes,
|
||||||
|
PayloadFormat: rn.PayloadFormat,
|
||||||
|
}
|
||||||
|
n.TopicProjectID, n.TopicID = parseNotificationTopic(rn.Topic)
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
var topicRE = regexp.MustCompile("^//pubsub.googleapis.com/projects/([^/]+)/topics/([^/]+)")
|
||||||
|
|
||||||
|
// parseNotificationTopic extracts the project and topic IDs from from the full
|
||||||
|
// resource name returned by the service. If the name is malformed, it returns
|
||||||
|
// "?" for both IDs.
|
||||||
|
func parseNotificationTopic(nt string) (projectID, topicID string) {
|
||||||
|
matches := topicRE.FindStringSubmatch(nt)
|
||||||
|
if matches == nil {
|
||||||
|
return "?", "?"
|
||||||
|
}
|
||||||
|
return matches[1], matches[2]
|
||||||
|
}
|
||||||
|
|
||||||
|
func toRawNotification(n *Notification) *raw.Notification {
|
||||||
|
return &raw.Notification{
|
||||||
|
Id: 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: string(n.PayloadFormat),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddNotification adds a notification to b. You must set n's TopicProjectID, TopicID
|
||||||
|
// and PayloadFormat, and must not set its ID. The other fields are all optional. The
|
||||||
|
// returned Notification's ID can be used to refer to it.
|
||||||
|
func (b *BucketHandle) AddNotification(ctx context.Context, n *Notification) (ret *Notification, err error) {
|
||||||
|
ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.AddNotification")
|
||||||
|
defer func() { trace.EndSpan(ctx, err) }()
|
||||||
|
|
||||||
|
if n.ID != "" {
|
||||||
|
return nil, errors.New("storage: AddNotification: ID must not be set")
|
||||||
|
}
|
||||||
|
if n.TopicProjectID == "" {
|
||||||
|
return nil, errors.New("storage: AddNotification: missing TopicProjectID")
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notifications returns all the Notifications configured for this bucket, as a map
|
||||||
|
// indexed by notification ID.
|
||||||
|
func (b *BucketHandle) Notifications(ctx context.Context) (n map[string]*Notification, err error) {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
func notificationsToMap(rns []*raw.Notification) map[string]*Notification {
|
||||||
|
m := map[string]*Notification{}
|
||||||
|
for _, rn := range rns {
|
||||||
|
m[rn.Id] = toNotification(rn)
|
||||||
|
}
|
||||||
|
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()
|
||||||
|
}
|
||||||
+377
@@ -0,0 +1,377 @@
|
|||||||
|
// Copyright 2020 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 (
|
||||||
|
"crypto"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PostPolicyV4Options are used to construct a signed post policy.
|
||||||
|
// Please see https://cloud.google.com/storage/docs/xml-api/post-object
|
||||||
|
// for reference about the fields.
|
||||||
|
type PostPolicyV4Options struct {
|
||||||
|
// GoogleAccessID represents the authorizer of the signed URL generation.
|
||||||
|
// It is typically the Google service account client email address from
|
||||||
|
// the Google Developers Console in the form of "xxx@developer.gserviceaccount.com".
|
||||||
|
// Required.
|
||||||
|
GoogleAccessID string
|
||||||
|
|
||||||
|
// PrivateKey is the Google service account private key. It is obtainable
|
||||||
|
// from the Google Developers Console.
|
||||||
|
// At https://console.developers.google.com/project/<your-project-id>/apiui/credential,
|
||||||
|
// create a service account client ID or reuse one of your existing service account
|
||||||
|
// credentials. Click on the "Generate new P12 key" to generate and download
|
||||||
|
// a new private key. Once you download the P12 file, use the following command
|
||||||
|
// to convert it into a PEM file.
|
||||||
|
//
|
||||||
|
// $ openssl pkcs12 -in key.p12 -passin pass:notasecret -out key.pem -nodes
|
||||||
|
//
|
||||||
|
// Provide the contents of the PEM file as a byte slice.
|
||||||
|
// Exactly one of PrivateKey or SignBytes must be non-nil.
|
||||||
|
PrivateKey []byte
|
||||||
|
|
||||||
|
// SignBytes 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.
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// Exactly one of PrivateKey or SignBytes must be non-nil.
|
||||||
|
SignBytes func(hashBytes []byte) (signature []byte, err error)
|
||||||
|
|
||||||
|
// Expires is the expiration time on the signed URL.
|
||||||
|
// It must be a time in the future.
|
||||||
|
// Required.
|
||||||
|
Expires time.Time
|
||||||
|
|
||||||
|
// Style provides options for the type of URL to use. Options are
|
||||||
|
// PathStyle (default), BucketBoundHostname, and VirtualHostedStyle. See
|
||||||
|
// https://cloud.google.com/storage/docs/request-endpoints for details.
|
||||||
|
// Optional.
|
||||||
|
Style URLStyle
|
||||||
|
|
||||||
|
// Insecure when set indicates that the generated URL's scheme
|
||||||
|
// will use "http" instead of "https" (default).
|
||||||
|
// Optional.
|
||||||
|
Insecure bool
|
||||||
|
|
||||||
|
// Fields specifies the attributes of a PostPolicyV4 request.
|
||||||
|
// When Fields is non-nil, its attributes must match those that will
|
||||||
|
// passed into field Conditions.
|
||||||
|
// Optional.
|
||||||
|
Fields *PolicyV4Fields
|
||||||
|
|
||||||
|
// The conditions that the uploaded file will be expected to conform to.
|
||||||
|
// When used, the failure of an upload to satisfy a condition will result in
|
||||||
|
// a 4XX status code, back with the message describing the problem.
|
||||||
|
// Optional.
|
||||||
|
Conditions []PostPolicyV4Condition
|
||||||
|
}
|
||||||
|
|
||||||
|
// PolicyV4Fields describes the attributes for a PostPolicyV4 request.
|
||||||
|
type PolicyV4Fields struct {
|
||||||
|
// ACL specifies the access control permissions for the object.
|
||||||
|
// Optional.
|
||||||
|
ACL string
|
||||||
|
// CacheControl specifies the caching directives for the object.
|
||||||
|
// Optional.
|
||||||
|
CacheControl string
|
||||||
|
// ContentType specifies the media type of the object.
|
||||||
|
// Optional.
|
||||||
|
ContentType string
|
||||||
|
// ContentDisposition specifies how the file will be served back to requesters.
|
||||||
|
// Optional.
|
||||||
|
ContentDisposition string
|
||||||
|
// ContentEncoding specifies the decompressive transcoding that the object.
|
||||||
|
// This field is complementary to ContentType in that the file could be
|
||||||
|
// compressed but ContentType specifies the file's original media type.
|
||||||
|
// Optional.
|
||||||
|
ContentEncoding string
|
||||||
|
// Metadata specifies custom metadata for the object.
|
||||||
|
// If any key doesn't begin with "x-goog-meta-", an error will be returned.
|
||||||
|
// Optional.
|
||||||
|
Metadata map[string]string
|
||||||
|
// StatusCodeOnSuccess when set, specifies the status code that Cloud Storage
|
||||||
|
// will serve back on successful upload of the object.
|
||||||
|
// Optional.
|
||||||
|
StatusCodeOnSuccess int
|
||||||
|
// RedirectToURLOnSuccess when set, specifies the URL that Cloud Storage
|
||||||
|
// will serve back on successful upload of the object.
|
||||||
|
// Optional.
|
||||||
|
RedirectToURLOnSuccess string
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostPolicyV4 describes the URL and respective form fields for a generated PostPolicyV4 request.
|
||||||
|
type PostPolicyV4 struct {
|
||||||
|
// URL is the generated URL that the file upload will be made to.
|
||||||
|
URL string
|
||||||
|
// Fields specifies the generated key-values that the file uploader
|
||||||
|
// must include in their multipart upload form.
|
||||||
|
Fields map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostPolicyV4Condition describes the constraints that the subsequent
|
||||||
|
// object upload's multipart form fields will be expected to conform to.
|
||||||
|
type PostPolicyV4Condition interface {
|
||||||
|
isEmpty() bool
|
||||||
|
json.Marshaler
|
||||||
|
}
|
||||||
|
|
||||||
|
type startsWith struct {
|
||||||
|
key, value string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sw *startsWith) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal([]string{"starts-with", sw.key, sw.value})
|
||||||
|
}
|
||||||
|
func (sw *startsWith) isEmpty() bool {
|
||||||
|
return sw.value == ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConditionStartsWith checks that an attributes starts with value.
|
||||||
|
// An empty value will cause this condition to be ignored.
|
||||||
|
func ConditionStartsWith(key, value string) PostPolicyV4Condition {
|
||||||
|
return &startsWith{key, value}
|
||||||
|
}
|
||||||
|
|
||||||
|
type contentLengthRangeCondition struct {
|
||||||
|
start, end uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (clr *contentLengthRangeCondition) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal([]interface{}{"content-length-range", clr.start, clr.end})
|
||||||
|
}
|
||||||
|
func (clr *contentLengthRangeCondition) isEmpty() bool {
|
||||||
|
return clr.start == 0 && clr.end == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type singleValueCondition struct {
|
||||||
|
name, value string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (svc *singleValueCondition) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(map[string]string{svc.name: svc.value})
|
||||||
|
}
|
||||||
|
func (svc *singleValueCondition) isEmpty() bool {
|
||||||
|
return svc.value == ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConditionContentLengthRange constraints the limits that the
|
||||||
|
// multipart upload's range header will be expected to be within.
|
||||||
|
func ConditionContentLengthRange(start, end uint64) PostPolicyV4Condition {
|
||||||
|
return &contentLengthRangeCondition{start, end}
|
||||||
|
}
|
||||||
|
|
||||||
|
func conditionRedirectToURLOnSuccess(redirectURL string) PostPolicyV4Condition {
|
||||||
|
return &singleValueCondition{"success_action_redirect", redirectURL}
|
||||||
|
}
|
||||||
|
|
||||||
|
func conditionStatusCodeOnSuccess(statusCode int) PostPolicyV4Condition {
|
||||||
|
svc := &singleValueCondition{name: "success_action_status"}
|
||||||
|
if statusCode > 0 {
|
||||||
|
svc.value = fmt.Sprintf("%d", statusCode)
|
||||||
|
}
|
||||||
|
return svc
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
func GenerateSignedPostPolicyV4(bucket, object string, opts *PostPolicyV4Options) (*PostPolicyV4, error) {
|
||||||
|
if bucket == "" {
|
||||||
|
return nil, errors.New("storage: bucket must be non-empty")
|
||||||
|
}
|
||||||
|
if object == "" {
|
||||||
|
return nil, errors.New("storage: object must be non-empty")
|
||||||
|
}
|
||||||
|
now := utcNow()
|
||||||
|
if err := validatePostPolicyV4Options(opts, now); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var signingFn func(hashedBytes []byte) ([]byte, error)
|
||||||
|
switch {
|
||||||
|
case opts.SignBytes != nil:
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, errors.New("storage: exactly one of PrivateKey or SignedBytes must be set")
|
||||||
|
}
|
||||||
|
|
||||||
|
var descFields PolicyV4Fields
|
||||||
|
if opts.Fields != nil {
|
||||||
|
descFields = *opts.Fields
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := validateMetadata(descFields.Metadata); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the policy.
|
||||||
|
conds := make([]PostPolicyV4Condition, len(opts.Conditions))
|
||||||
|
copy(conds, opts.Conditions)
|
||||||
|
conds = append(conds,
|
||||||
|
conditionRedirectToURLOnSuccess(descFields.RedirectToURLOnSuccess),
|
||||||
|
conditionStatusCodeOnSuccess(descFields.StatusCodeOnSuccess),
|
||||||
|
&singleValueCondition{"acl", descFields.ACL},
|
||||||
|
&singleValueCondition{"cache-control", descFields.CacheControl},
|
||||||
|
)
|
||||||
|
|
||||||
|
YYYYMMDD := now.Format(yearMonthDay)
|
||||||
|
policyFields := map[string]string{
|
||||||
|
"key": object,
|
||||||
|
"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,
|
||||||
|
}
|
||||||
|
for key, value := range descFields.Metadata {
|
||||||
|
conds = append(conds, &singleValueCondition{key, value})
|
||||||
|
policyFields[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// Following from the order expected by the conformance test cases,
|
||||||
|
// hence manually inserting these fields in a specific order.
|
||||||
|
conds = append(conds,
|
||||||
|
&singleValueCondition{"bucket", bucket},
|
||||||
|
&singleValueCondition{"key", object},
|
||||||
|
&singleValueCondition{"x-goog-date", now.Format(iso8601)},
|
||||||
|
&singleValueCondition{
|
||||||
|
name: "x-goog-credential",
|
||||||
|
value: opts.GoogleAccessID + "/" + YYYYMMDD + "/auto/storage/goog4_request",
|
||||||
|
},
|
||||||
|
&singleValueCondition{"x-goog-algorithm", "GOOG4-RSA-SHA256"},
|
||||||
|
)
|
||||||
|
|
||||||
|
nonEmptyConds := make([]PostPolicyV4Condition, 0, len(opts.Conditions))
|
||||||
|
for _, cond := range conds {
|
||||||
|
if cond == nil || !cond.isEmpty() {
|
||||||
|
nonEmptyConds = append(nonEmptyConds, cond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
condsAsJSON, err := json.Marshal(map[string]interface{}{
|
||||||
|
"conditions": nonEmptyConds,
|
||||||
|
"expiration": opts.Expires.Format(time.RFC3339),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("storage: PostPolicyV4 JSON serialization failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
b64Policy := base64.StdEncoding.EncodeToString(condsAsJSON)
|
||||||
|
shaSum := sha256.Sum256([]byte(b64Policy))
|
||||||
|
signature, err := signingFn(shaSum[:])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
policyFields["policy"] = b64Policy
|
||||||
|
policyFields["x-goog-signature"] = fmt.Sprintf("%x", signature)
|
||||||
|
|
||||||
|
// Construct the URL.
|
||||||
|
scheme := "https"
|
||||||
|
if opts.Insecure {
|
||||||
|
scheme = "http"
|
||||||
|
}
|
||||||
|
path := opts.Style.path(bucket, "") + "/"
|
||||||
|
u := &url.URL{
|
||||||
|
Path: path,
|
||||||
|
RawPath: pathEncodeV4(path),
|
||||||
|
Host: opts.Style.host(bucket),
|
||||||
|
Scheme: scheme,
|
||||||
|
}
|
||||||
|
|
||||||
|
if descFields.StatusCodeOnSuccess > 0 {
|
||||||
|
policyFields["success_action_status"] = fmt.Sprintf("%d", descFields.StatusCodeOnSuccess)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear out fields with blanks values.
|
||||||
|
for key, value := range policyFields {
|
||||||
|
if value == "" {
|
||||||
|
delete(policyFields, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pp4 := &PostPolicyV4{
|
||||||
|
Fields: policyFields,
|
||||||
|
URL: u.String(),
|
||||||
|
}
|
||||||
|
return pp4, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// * if Style is not set, it'll use PathStyle
|
||||||
|
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 opts.Expires.Before(now) {
|
||||||
|
return errors.New("storage: expecting Expires to be in the future")
|
||||||
|
}
|
||||||
|
if opts.Style == nil {
|
||||||
|
opts.Style = PathStyle()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// validateMetadata ensures that all keys passed in have a prefix of "x-goog-meta-",
|
||||||
|
// otherwise it will return an error.
|
||||||
|
func validateMetadata(hdrs map[string]string) (err error) {
|
||||||
|
if len(hdrs) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
badKeys := make([]string, 0, len(hdrs))
|
||||||
|
for key := range hdrs {
|
||||||
|
if !strings.HasPrefix(key, "x-goog-meta-") {
|
||||||
|
badKeys = append(badKeys, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(badKeys) != 0 {
|
||||||
|
err = errors.New("storage: expected metadata to begin with x-goog-meta-, got " + strings.Join(badKeys, ", "))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
+435
@@ -0,0 +1,435 @@
|
|||||||
|
// Copyright 2016 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"
|
||||||
|
"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)
|
||||||
|
|
||||||
|
// ReaderObjectAttrs are attributes about the object being read. These are populated
|
||||||
|
// during the New call. This struct only holds a subset of object attributes: to
|
||||||
|
// get the full set of attributes, use ObjectHandle.Attrs.
|
||||||
|
//
|
||||||
|
// Each field is read-only.
|
||||||
|
type ReaderObjectAttrs struct {
|
||||||
|
// Size is the length of the object's content.
|
||||||
|
Size int64
|
||||||
|
|
||||||
|
// StartOffset is the byte offset within the object
|
||||||
|
// from which reading begins.
|
||||||
|
// This value is only non-zero for range requests.
|
||||||
|
StartOffset int64
|
||||||
|
|
||||||
|
// ContentType is the MIME type of the object's content.
|
||||||
|
ContentType string
|
||||||
|
|
||||||
|
// ContentEncoding is the encoding of the object's content.
|
||||||
|
ContentEncoding string
|
||||||
|
|
||||||
|
// CacheControl specifies whether and for how long browser and Internet
|
||||||
|
// caches are allowed to cache your objects.
|
||||||
|
CacheControl string
|
||||||
|
|
||||||
|
// LastModified is the time that the object was last modified.
|
||||||
|
LastModified time.Time
|
||||||
|
|
||||||
|
// Generation is the generation number of the object's content.
|
||||||
|
Generation int64
|
||||||
|
|
||||||
|
// Metageneration is the version of the metadata for this object at
|
||||||
|
// this generation. This field is 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.
|
||||||
|
Metageneration int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewReader creates a new Reader to read the contents of the
|
||||||
|
// object.
|
||||||
|
// ErrObjectNotExist will be returned if the object is not found.
|
||||||
|
//
|
||||||
|
// The caller must call Close on the returned Reader when done reading.
|
||||||
|
func (o *ObjectHandle) NewReader(ctx context.Context) (*Reader, error) {
|
||||||
|
return o.NewRangeReader(ctx, 0, -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRangeReader reads part of an object, reading at most length bytes
|
||||||
|
// starting at the given offset. If length is negative, the object is read
|
||||||
|
// until the end. If offset is negative, the object is read abs(offset) bytes
|
||||||
|
// from the end, and length must also be negative to indicate all remaining
|
||||||
|
// bytes will be read.
|
||||||
|
//
|
||||||
|
// If the object's metadata property "Content-Encoding" is set to "gzip" or satisfies
|
||||||
|
// decompressive transcoding per https://cloud.google.com/storage/docs/transcoding
|
||||||
|
// that file will be served back whole, regardless of the requested range as
|
||||||
|
// Google Cloud Storage dictates.
|
||||||
|
func (o *ObjectHandle) NewRangeReader(ctx context.Context, offset, length int64) (r *Reader, err error) {
|
||||||
|
ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Object.NewRangeReader")
|
||||||
|
defer func() { trace.EndSpan(ctx, err) }()
|
||||||
|
|
||||||
|
if err := o.validate(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if offset < 0 && length >= 0 {
|
||||||
|
return nil, fmt.Errorf("storage: invalid offset %d < 0 requires negative length", offset)
|
||||||
|
}
|
||||||
|
if o.conds != nil {
|
||||||
|
if err := o.conds.validate("NewRangeReader"); err != nil {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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: gen,
|
||||||
|
Metageneration: metaGen,
|
||||||
|
}
|
||||||
|
return &Reader{
|
||||||
|
Attrs: attrs,
|
||||||
|
body: body,
|
||||||
|
size: size,
|
||||||
|
remain: remain,
|
||||||
|
wantCRC: crc,
|
||||||
|
checkCRC: checkCRC,
|
||||||
|
reopen: reopen,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
func decompressiveTranscoding(res *http.Response) bool {
|
||||||
|
// Decompressive Transcoding.
|
||||||
|
return res.Header.Get("Content-Encoding") == "gzip" ||
|
||||||
|
res.Header.Get("X-Goog-Stored-Content-Encoding") == "gzip"
|
||||||
|
}
|
||||||
|
|
||||||
|
func uncompressedByServer(res *http.Response) bool {
|
||||||
|
// If the data is stored as gzip but is not encoded as gzip, then it
|
||||||
|
// was uncompressed by the server.
|
||||||
|
return res.Header.Get("X-Goog-Stored-Content-Encoding") == "gzip" &&
|
||||||
|
res.Header.Get("Content-Encoding") != "gzip"
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseCRC32c(res *http.Response) (uint32, bool) {
|
||||||
|
const prefix = "crc32c="
|
||||||
|
for _, spec := range res.Header["X-Goog-Hash"] {
|
||||||
|
if strings.HasPrefix(spec, prefix) {
|
||||||
|
c, err := decodeUint32(spec[len(prefix):])
|
||||||
|
if err == nil {
|
||||||
|
return c, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
var emptyBody = ioutil.NopCloser(strings.NewReader(""))
|
||||||
|
|
||||||
|
// Reader reads a Cloud Storage object.
|
||||||
|
// It implements io.Reader.
|
||||||
|
//
|
||||||
|
// Typically, a Reader computes the CRC of the downloaded content and compares it to
|
||||||
|
// the stored CRC, returning an error from Read if there is a mismatch. This integrity check
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close closes the Reader. It must be called when done reading.
|
||||||
|
func (r *Reader) Close() error {
|
||||||
|
return r.body.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Reader) Read(p []byte) (int, error) {
|
||||||
|
n, err := r.readWithRetry(p)
|
||||||
|
if r.remain != -1 {
|
||||||
|
r.remain -= int64(n)
|
||||||
|
}
|
||||||
|
if r.checkCRC {
|
||||||
|
r.gotCRC = crc32.Update(r.gotCRC, crc32cTable, p[:n])
|
||||||
|
// Check CRC here. It would be natural to check it in Close, but
|
||||||
|
// everybody defers Close on the assumption that it doesn't return
|
||||||
|
// anything worth looking at.
|
||||||
|
if err == io.EOF {
|
||||||
|
if r.gotCRC != r.wantCRC {
|
||||||
|
return n, fmt.Errorf("storage: bad CRC on read: got %d, want %d",
|
||||||
|
r.gotCRC, r.wantCRC)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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.
|
||||||
|
//
|
||||||
|
// Deprecated: use Reader.Attrs.Size.
|
||||||
|
func (r *Reader) Size() int64 {
|
||||||
|
return r.Attrs.Size
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remain returns the number of bytes left to read, or -1 if unknown.
|
||||||
|
func (r *Reader) Remain() int64 {
|
||||||
|
return r.remain
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContentType returns the content type of the object.
|
||||||
|
//
|
||||||
|
// Deprecated: use Reader.Attrs.ContentType.
|
||||||
|
func (r *Reader) ContentType() string {
|
||||||
|
return r.Attrs.ContentType
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContentEncoding returns the content encoding of the object.
|
||||||
|
//
|
||||||
|
// Deprecated: use Reader.Attrs.ContentEncoding.
|
||||||
|
func (r *Reader) ContentEncoding() string {
|
||||||
|
return r.Attrs.ContentEncoding
|
||||||
|
}
|
||||||
|
|
||||||
|
// CacheControl returns the cache control of the object.
|
||||||
|
//
|
||||||
|
// Deprecated: use Reader.Attrs.CacheControl.
|
||||||
|
func (r *Reader) CacheControl() string {
|
||||||
|
return r.Attrs.CacheControl
|
||||||
|
}
|
||||||
|
|
||||||
|
// LastModified returns the value of the Last-Modified header.
|
||||||
|
//
|
||||||
|
// Deprecated: use Reader.Attrs.LastModified.
|
||||||
|
func (r *Reader) LastModified() (time.Time, error) {
|
||||||
|
return r.Attrs.LastModified, nil
|
||||||
|
}
|
||||||
+1641
File diff suppressed because it is too large.
Load diff
+30067
File diff suppressed because it is too large.
Load diff
+268
@@ -0,0 +1,268 @@
|
|||||||
|
// 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 storage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"sync"
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"google.golang.org/api/googleapi"
|
||||||
|
raw "google.golang.org/api/storage/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Writer writes a Cloud Storage object.
|
||||||
|
type Writer struct {
|
||||||
|
// ObjectAttrs are optional attributes to set on the object. Any attributes
|
||||||
|
// must be initialized before the first Write call. Nil or zero-valued
|
||||||
|
// attributes are ignored.
|
||||||
|
ObjectAttrs
|
||||||
|
|
||||||
|
// SendCRC 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.
|
||||||
|
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.
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// ChunkSize must be set before the first Write call.
|
||||||
|
ChunkSize int
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// https://cloud.google.com/storage/docs/json_api/v1/how-tos/resumable-upload),
|
||||||
|
// then ProgressFunc will be invoked after each call with the number of bytes of
|
||||||
|
// content copied so far.
|
||||||
|
//
|
||||||
|
// ProgressFunc should return quickly without blocking.
|
||||||
|
ProgressFunc func(int64)
|
||||||
|
|
||||||
|
ctx context.Context
|
||||||
|
o *ObjectHandle
|
||||||
|
|
||||||
|
opened bool
|
||||||
|
pw *io.PipeWriter
|
||||||
|
|
||||||
|
donec chan struct{} // closed after err and obj are set.
|
||||||
|
obj *ObjectAttrs
|
||||||
|
|
||||||
|
mu sync.Mutex
|
||||||
|
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
|
||||||
|
// error even though the write failed (or will fail). Always
|
||||||
|
// use the error returned from Writer.Close to determine if
|
||||||
|
// the upload was successful.
|
||||||
|
//
|
||||||
|
// Writes will be retried on transient errors from the server, unless
|
||||||
|
// Writer.ChunkSize has been set to zero.
|
||||||
|
func (w *Writer) Write(p []byte) (n int, err error) {
|
||||||
|
w.mu.Lock()
|
||||||
|
werr := w.err
|
||||||
|
w.mu.Unlock()
|
||||||
|
if werr != nil {
|
||||||
|
return 0, werr
|
||||||
|
}
|
||||||
|
if !w.opened {
|
||||||
|
if err := w.open(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
n, err = w.pw.Write(p)
|
||||||
|
if err != nil {
|
||||||
|
w.mu.Lock()
|
||||||
|
werr := w.err
|
||||||
|
w.mu.Unlock()
|
||||||
|
// 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 {
|
||||||
|
return n, werr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close completes the write operation and flushes any buffered data.
|
||||||
|
// If Close doesn't return an error, metadata about the written object
|
||||||
|
// can be retrieved by calling Attrs.
|
||||||
|
func (w *Writer) Close() error {
|
||||||
|
if !w.opened {
|
||||||
|
if err := w.open(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Closing either the read or write causes the entire pipe to close.
|
||||||
|
if err := w.pw.Close(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
<-w.donec
|
||||||
|
w.mu.Lock()
|
||||||
|
defer w.mu.Unlock()
|
||||||
|
return w.err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
func (w *Writer) monitorCancel() {
|
||||||
|
select {
|
||||||
|
case <-w.ctx.Done():
|
||||||
|
w.mu.Lock()
|
||||||
|
werr := w.ctx.Err()
|
||||||
|
w.err = werr
|
||||||
|
w.mu.Unlock()
|
||||||
|
|
||||||
|
// Closing either the read or write causes the entire pipe to close.
|
||||||
|
w.CloseWithError(werr)
|
||||||
|
case <-w.donec:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CloseWithError aborts the write operation with the provided error.
|
||||||
|
// CloseWithError always returns nil.
|
||||||
|
//
|
||||||
|
// Deprecated: cancel the context passed to NewWriter instead.
|
||||||
|
func (w *Writer) CloseWithError(err error) error {
|
||||||
|
if !w.opened {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return w.pw.CloseWithError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attrs returns metadata about a successfully-written object.
|
||||||
|
// It's only valid to call it after Close returns nil.
|
||||||
|
func (w *Writer) Attrs() *ObjectAttrs {
|
||||||
|
return w.obj
|
||||||
|
}
|
||||||
+230
@@ -0,0 +1,230 @@
|
|||||||
|
# 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
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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 TranslateTextWithAbstractClient(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 := TranslateTextWithAbstractClient(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).
|
||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
// +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"
|
||||||
|
)
|
||||||
+202
@@ -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 2020 Microsoft Corporation
|
||||||
|
|
||||||
|
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.
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
Microsoft Azure-SDK-for-Go
|
||||||
|
Copyright 2014-2017 Microsoft
|
||||||
|
|
||||||
|
This product includes software developed at
|
||||||
|
the Microsoft Corporation (https://www.microsoft.com).
|
||||||
Generated
Vendored
+7265
File diff suppressed because it is too large.
Load diff
Generated
Vendored
+3375
File diff suppressed because it is too large.
Load diff
Generated
Vendored
+30
@@ -0,0 +1,30 @@
|
|||||||
|
package keyvault
|
||||||
|
|
||||||
|
import "github.com/Azure/azure-sdk-for-go/version"
|
||||||
|
|
||||||
|
// Copyright (c) Microsoft and contributors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
//
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// Code generated by Microsoft (R) AutoRest Code Generator.
|
||||||
|
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||||
|
|
||||||
|
// UserAgent returns the UserAgent string to use when sending http.Requests.
|
||||||
|
func UserAgent() string {
|
||||||
|
return "Azure-SDK-For-Go/" + version.Number + " keyvault/7.0"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Version returns the semantic version (see http://semver.org) of the client.
|
||||||
|
func Version() string {
|
||||||
|
return version.Number
|
||||||
|
}
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
package version
|
||||||
|
|
||||||
|
// Copyright (c) Microsoft and contributors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
//
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// Code generated by Microsoft (R) AutoRest Code Generator.
|
||||||
|
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||||
|
|
||||||
|
// Number contains the semantic version of this SDK.
|
||||||
|
const Number = "v46.4.0"
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2015 Microsoft Corporation
|
||||||
|
|
||||||
|
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.
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
# go-ansiterm
|
||||||
|
|
||||||
|
This is a cross platform Ansi Terminal Emulation library. It reads a stream of Ansi characters and produces the appropriate function calls. The results of the function calls are platform dependent.
|
||||||
|
|
||||||
|
For example the parser might receive "ESC, [, A" as a stream of three characters. This is the code for Cursor Up (http://www.vt100.net/docs/vt510-rm/CUU). The parser then calls the cursor up function (CUU()) on an event handler. The event handler determines what platform specific work must be done to cause the cursor to move up one position.
|
||||||
|
|
||||||
|
The parser (parser.go) is a partial implementation of this state machine (http://vt100.net/emu/vt500_parser.png). There are also two event handler implementations, one for tests (test_event_handler.go) to validate that the expected events are being produced and called, the other is a Windows implementation (winterm/win_event_handler.go).
|
||||||
|
|
||||||
|
See parser_test.go for examples exercising the state machine and generating appropriate function calls.
|
||||||
|
|
||||||
|
-----
|
||||||
|
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||||
+188
@@ -0,0 +1,188 @@
|
|||||||
|
package ansiterm
|
||||||
|
|
||||||
|
const LogEnv = "DEBUG_TERMINAL"
|
||||||
|
|
||||||
|
// ANSI constants
|
||||||
|
// References:
|
||||||
|
// -- http://www.ecma-international.org/publications/standards/Ecma-048.htm
|
||||||
|
// -- http://man7.org/linux/man-pages/man4/console_codes.4.html
|
||||||
|
// -- http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html
|
||||||
|
// -- http://en.wikipedia.org/wiki/ANSI_escape_code
|
||||||
|
// -- http://vt100.net/emu/dec_ansi_parser
|
||||||
|
// -- http://vt100.net/emu/vt500_parser.svg
|
||||||
|
// -- http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
|
||||||
|
// -- http://www.inwap.com/pdp10/ansicode.txt
|
||||||
|
const (
|
||||||
|
// ECMA-48 Set Graphics Rendition
|
||||||
|
// Note:
|
||||||
|
// -- Constants leading with an underscore (e.g., _ANSI_xxx) are unsupported or reserved
|
||||||
|
// -- Fonts could possibly be supported via SetCurrentConsoleFontEx
|
||||||
|
// -- Windows does not expose the per-window cursor (i.e., caret) blink times
|
||||||
|
ANSI_SGR_RESET = 0
|
||||||
|
ANSI_SGR_BOLD = 1
|
||||||
|
ANSI_SGR_DIM = 2
|
||||||
|
_ANSI_SGR_ITALIC = 3
|
||||||
|
ANSI_SGR_UNDERLINE = 4
|
||||||
|
_ANSI_SGR_BLINKSLOW = 5
|
||||||
|
_ANSI_SGR_BLINKFAST = 6
|
||||||
|
ANSI_SGR_REVERSE = 7
|
||||||
|
_ANSI_SGR_INVISIBLE = 8
|
||||||
|
_ANSI_SGR_LINETHROUGH = 9
|
||||||
|
_ANSI_SGR_FONT_00 = 10
|
||||||
|
_ANSI_SGR_FONT_01 = 11
|
||||||
|
_ANSI_SGR_FONT_02 = 12
|
||||||
|
_ANSI_SGR_FONT_03 = 13
|
||||||
|
_ANSI_SGR_FONT_04 = 14
|
||||||
|
_ANSI_SGR_FONT_05 = 15
|
||||||
|
_ANSI_SGR_FONT_06 = 16
|
||||||
|
_ANSI_SGR_FONT_07 = 17
|
||||||
|
_ANSI_SGR_FONT_08 = 18
|
||||||
|
_ANSI_SGR_FONT_09 = 19
|
||||||
|
_ANSI_SGR_FONT_10 = 20
|
||||||
|
_ANSI_SGR_DOUBLEUNDERLINE = 21
|
||||||
|
ANSI_SGR_BOLD_DIM_OFF = 22
|
||||||
|
_ANSI_SGR_ITALIC_OFF = 23
|
||||||
|
ANSI_SGR_UNDERLINE_OFF = 24
|
||||||
|
_ANSI_SGR_BLINK_OFF = 25
|
||||||
|
_ANSI_SGR_RESERVED_00 = 26
|
||||||
|
ANSI_SGR_REVERSE_OFF = 27
|
||||||
|
_ANSI_SGR_INVISIBLE_OFF = 28
|
||||||
|
_ANSI_SGR_LINETHROUGH_OFF = 29
|
||||||
|
ANSI_SGR_FOREGROUND_BLACK = 30
|
||||||
|
ANSI_SGR_FOREGROUND_RED = 31
|
||||||
|
ANSI_SGR_FOREGROUND_GREEN = 32
|
||||||
|
ANSI_SGR_FOREGROUND_YELLOW = 33
|
||||||
|
ANSI_SGR_FOREGROUND_BLUE = 34
|
||||||
|
ANSI_SGR_FOREGROUND_MAGENTA = 35
|
||||||
|
ANSI_SGR_FOREGROUND_CYAN = 36
|
||||||
|
ANSI_SGR_FOREGROUND_WHITE = 37
|
||||||
|
_ANSI_SGR_RESERVED_01 = 38
|
||||||
|
ANSI_SGR_FOREGROUND_DEFAULT = 39
|
||||||
|
ANSI_SGR_BACKGROUND_BLACK = 40
|
||||||
|
ANSI_SGR_BACKGROUND_RED = 41
|
||||||
|
ANSI_SGR_BACKGROUND_GREEN = 42
|
||||||
|
ANSI_SGR_BACKGROUND_YELLOW = 43
|
||||||
|
ANSI_SGR_BACKGROUND_BLUE = 44
|
||||||
|
ANSI_SGR_BACKGROUND_MAGENTA = 45
|
||||||
|
ANSI_SGR_BACKGROUND_CYAN = 46
|
||||||
|
ANSI_SGR_BACKGROUND_WHITE = 47
|
||||||
|
_ANSI_SGR_RESERVED_02 = 48
|
||||||
|
ANSI_SGR_BACKGROUND_DEFAULT = 49
|
||||||
|
// 50 - 65: Unsupported
|
||||||
|
|
||||||
|
ANSI_MAX_CMD_LENGTH = 4096
|
||||||
|
|
||||||
|
MAX_INPUT_EVENTS = 128
|
||||||
|
DEFAULT_WIDTH = 80
|
||||||
|
DEFAULT_HEIGHT = 24
|
||||||
|
|
||||||
|
ANSI_BEL = 0x07
|
||||||
|
ANSI_BACKSPACE = 0x08
|
||||||
|
ANSI_TAB = 0x09
|
||||||
|
ANSI_LINE_FEED = 0x0A
|
||||||
|
ANSI_VERTICAL_TAB = 0x0B
|
||||||
|
ANSI_FORM_FEED = 0x0C
|
||||||
|
ANSI_CARRIAGE_RETURN = 0x0D
|
||||||
|
ANSI_ESCAPE_PRIMARY = 0x1B
|
||||||
|
ANSI_ESCAPE_SECONDARY = 0x5B
|
||||||
|
ANSI_OSC_STRING_ENTRY = 0x5D
|
||||||
|
ANSI_COMMAND_FIRST = 0x40
|
||||||
|
ANSI_COMMAND_LAST = 0x7E
|
||||||
|
DCS_ENTRY = 0x90
|
||||||
|
CSI_ENTRY = 0x9B
|
||||||
|
OSC_STRING = 0x9D
|
||||||
|
ANSI_PARAMETER_SEP = ";"
|
||||||
|
ANSI_CMD_G0 = '('
|
||||||
|
ANSI_CMD_G1 = ')'
|
||||||
|
ANSI_CMD_G2 = '*'
|
||||||
|
ANSI_CMD_G3 = '+'
|
||||||
|
ANSI_CMD_DECPNM = '>'
|
||||||
|
ANSI_CMD_DECPAM = '='
|
||||||
|
ANSI_CMD_OSC = ']'
|
||||||
|
ANSI_CMD_STR_TERM = '\\'
|
||||||
|
|
||||||
|
KEY_CONTROL_PARAM_2 = ";2"
|
||||||
|
KEY_CONTROL_PARAM_3 = ";3"
|
||||||
|
KEY_CONTROL_PARAM_4 = ";4"
|
||||||
|
KEY_CONTROL_PARAM_5 = ";5"
|
||||||
|
KEY_CONTROL_PARAM_6 = ";6"
|
||||||
|
KEY_CONTROL_PARAM_7 = ";7"
|
||||||
|
KEY_CONTROL_PARAM_8 = ";8"
|
||||||
|
KEY_ESC_CSI = "\x1B["
|
||||||
|
KEY_ESC_N = "\x1BN"
|
||||||
|
KEY_ESC_O = "\x1BO"
|
||||||
|
|
||||||
|
FILL_CHARACTER = ' '
|
||||||
|
)
|
||||||
|
|
||||||
|
func getByteRange(start byte, end byte) []byte {
|
||||||
|
bytes := make([]byte, 0, 32)
|
||||||
|
for i := start; i <= end; i++ {
|
||||||
|
bytes = append(bytes, byte(i))
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
var toGroundBytes = getToGroundBytes()
|
||||||
|
var executors = getExecuteBytes()
|
||||||
|
|
||||||
|
// SPACE 20+A0 hex Always and everywhere a blank space
|
||||||
|
// Intermediate 20-2F hex !"#$%&'()*+,-./
|
||||||
|
var intermeds = getByteRange(0x20, 0x2F)
|
||||||
|
|
||||||
|
// Parameters 30-3F hex 0123456789:;<=>?
|
||||||
|
// CSI Parameters 30-39, 3B hex 0123456789;
|
||||||
|
var csiParams = getByteRange(0x30, 0x3F)
|
||||||
|
|
||||||
|
var csiCollectables = append(getByteRange(0x30, 0x39), getByteRange(0x3B, 0x3F)...)
|
||||||
|
|
||||||
|
// Uppercase 40-5F hex @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
|
||||||
|
var upperCase = getByteRange(0x40, 0x5F)
|
||||||
|
|
||||||
|
// Lowercase 60-7E hex `abcdefghijlkmnopqrstuvwxyz{|}~
|
||||||
|
var lowerCase = getByteRange(0x60, 0x7E)
|
||||||
|
|
||||||
|
// Alphabetics 40-7E hex (all of upper and lower case)
|
||||||
|
var alphabetics = append(upperCase, lowerCase...)
|
||||||
|
|
||||||
|
var printables = getByteRange(0x20, 0x7F)
|
||||||
|
|
||||||
|
var escapeIntermediateToGroundBytes = getByteRange(0x30, 0x7E)
|
||||||
|
var escapeToGroundBytes = getEscapeToGroundBytes()
|
||||||
|
|
||||||
|
// See http://www.vt100.net/emu/vt500_parser.png for description of the complex
|
||||||
|
// byte ranges below
|
||||||
|
|
||||||
|
func getEscapeToGroundBytes() []byte {
|
||||||
|
escapeToGroundBytes := getByteRange(0x30, 0x4F)
|
||||||
|
escapeToGroundBytes = append(escapeToGroundBytes, getByteRange(0x51, 0x57)...)
|
||||||
|
escapeToGroundBytes = append(escapeToGroundBytes, 0x59)
|
||||||
|
escapeToGroundBytes = append(escapeToGroundBytes, 0x5A)
|
||||||
|
escapeToGroundBytes = append(escapeToGroundBytes, 0x5C)
|
||||||
|
escapeToGroundBytes = append(escapeToGroundBytes, getByteRange(0x60, 0x7E)...)
|
||||||
|
return escapeToGroundBytes
|
||||||
|
}
|
||||||
|
|
||||||
|
func getExecuteBytes() []byte {
|
||||||
|
executeBytes := getByteRange(0x00, 0x17)
|
||||||
|
executeBytes = append(executeBytes, 0x19)
|
||||||
|
executeBytes = append(executeBytes, getByteRange(0x1C, 0x1F)...)
|
||||||
|
return executeBytes
|
||||||
|
}
|
||||||
|
|
||||||
|
func getToGroundBytes() []byte {
|
||||||
|
groundBytes := []byte{0x18}
|
||||||
|
groundBytes = append(groundBytes, 0x1A)
|
||||||
|
groundBytes = append(groundBytes, getByteRange(0x80, 0x8F)...)
|
||||||
|
groundBytes = append(groundBytes, getByteRange(0x91, 0x97)...)
|
||||||
|
groundBytes = append(groundBytes, 0x99)
|
||||||
|
groundBytes = append(groundBytes, 0x9A)
|
||||||
|
groundBytes = append(groundBytes, 0x9C)
|
||||||
|
return groundBytes
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete 7F hex Always and everywhere ignored
|
||||||
|
// C1 Control 80-9F hex 32 additional control characters
|
||||||
|
// G1 Displayable A1-FE hex 94 additional displayable characters
|
||||||
|
// Special A0+FF hex Same as SPACE and DELETE
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
package ansiterm
|
||||||
|
|
||||||
|
type ansiContext struct {
|
||||||
|
currentChar byte
|
||||||
|
paramBuffer []byte
|
||||||
|
interBuffer []byte
|
||||||
|
}
|
||||||
+49
@@ -0,0 +1,49 @@
|
|||||||
|
package ansiterm
|
||||||
|
|
||||||
|
type csiEntryState struct {
|
||||||
|
baseState
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csiState csiEntryState) Handle(b byte) (s state, e error) {
|
||||||
|
csiState.parser.logf("CsiEntry::Handle %#x", b)
|
||||||
|
|
||||||
|
nextState, err := csiState.baseState.Handle(b)
|
||||||
|
if nextState != nil || err != nil {
|
||||||
|
return nextState, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case sliceContains(alphabetics, b):
|
||||||
|
return csiState.parser.ground, nil
|
||||||
|
case sliceContains(csiCollectables, b):
|
||||||
|
return csiState.parser.csiParam, nil
|
||||||
|
case sliceContains(executors, b):
|
||||||
|
return csiState, csiState.parser.execute()
|
||||||
|
}
|
||||||
|
|
||||||
|
return csiState, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csiState csiEntryState) Transition(s state) error {
|
||||||
|
csiState.parser.logf("CsiEntry::Transition %s --> %s", csiState.Name(), s.Name())
|
||||||
|
csiState.baseState.Transition(s)
|
||||||
|
|
||||||
|
switch s {
|
||||||
|
case csiState.parser.ground:
|
||||||
|
return csiState.parser.csiDispatch()
|
||||||
|
case csiState.parser.csiParam:
|
||||||
|
switch {
|
||||||
|
case sliceContains(csiParams, csiState.parser.context.currentChar):
|
||||||
|
csiState.parser.collectParam()
|
||||||
|
case sliceContains(intermeds, csiState.parser.context.currentChar):
|
||||||
|
csiState.parser.collectInter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csiState csiEntryState) Enter() error {
|
||||||
|
csiState.parser.clear()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
package ansiterm
|
||||||
|
|
||||||
|
type csiParamState struct {
|
||||||
|
baseState
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csiState csiParamState) Handle(b byte) (s state, e error) {
|
||||||
|
csiState.parser.logf("CsiParam::Handle %#x", b)
|
||||||
|
|
||||||
|
nextState, err := csiState.baseState.Handle(b)
|
||||||
|
if nextState != nil || err != nil {
|
||||||
|
return nextState, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case sliceContains(alphabetics, b):
|
||||||
|
return csiState.parser.ground, nil
|
||||||
|
case sliceContains(csiCollectables, b):
|
||||||
|
csiState.parser.collectParam()
|
||||||
|
return csiState, nil
|
||||||
|
case sliceContains(executors, b):
|
||||||
|
return csiState, csiState.parser.execute()
|
||||||
|
}
|
||||||
|
|
||||||
|
return csiState, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csiState csiParamState) Transition(s state) error {
|
||||||
|
csiState.parser.logf("CsiParam::Transition %s --> %s", csiState.Name(), s.Name())
|
||||||
|
csiState.baseState.Transition(s)
|
||||||
|
|
||||||
|
switch s {
|
||||||
|
case csiState.parser.ground:
|
||||||
|
return csiState.parser.csiDispatch()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
+36
@@ -0,0 +1,36 @@
|
|||||||
|
package ansiterm
|
||||||
|
|
||||||
|
type escapeIntermediateState struct {
|
||||||
|
baseState
|
||||||
|
}
|
||||||
|
|
||||||
|
func (escState escapeIntermediateState) Handle(b byte) (s state, e error) {
|
||||||
|
escState.parser.logf("escapeIntermediateState::Handle %#x", b)
|
||||||
|
nextState, err := escState.baseState.Handle(b)
|
||||||
|
if nextState != nil || err != nil {
|
||||||
|
return nextState, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case sliceContains(intermeds, b):
|
||||||
|
return escState, escState.parser.collectInter()
|
||||||
|
case sliceContains(executors, b):
|
||||||
|
return escState, escState.parser.execute()
|
||||||
|
case sliceContains(escapeIntermediateToGroundBytes, b):
|
||||||
|
return escState.parser.ground, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return escState, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (escState escapeIntermediateState) Transition(s state) error {
|
||||||
|
escState.parser.logf("escapeIntermediateState::Transition %s --> %s", escState.Name(), s.Name())
|
||||||
|
escState.baseState.Transition(s)
|
||||||
|
|
||||||
|
switch s {
|
||||||
|
case escState.parser.ground:
|
||||||
|
return escState.parser.escDispatch()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
+47
@@ -0,0 +1,47 @@
|
|||||||
|
package ansiterm
|
||||||
|
|
||||||
|
type escapeState struct {
|
||||||
|
baseState
|
||||||
|
}
|
||||||
|
|
||||||
|
func (escState escapeState) Handle(b byte) (s state, e error) {
|
||||||
|
escState.parser.logf("escapeState::Handle %#x", b)
|
||||||
|
nextState, err := escState.baseState.Handle(b)
|
||||||
|
if nextState != nil || err != nil {
|
||||||
|
return nextState, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case b == ANSI_ESCAPE_SECONDARY:
|
||||||
|
return escState.parser.csiEntry, nil
|
||||||
|
case b == ANSI_OSC_STRING_ENTRY:
|
||||||
|
return escState.parser.oscString, nil
|
||||||
|
case sliceContains(executors, b):
|
||||||
|
return escState, escState.parser.execute()
|
||||||
|
case sliceContains(escapeToGroundBytes, b):
|
||||||
|
return escState.parser.ground, nil
|
||||||
|
case sliceContains(intermeds, b):
|
||||||
|
return escState.parser.escapeIntermediate, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return escState, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (escState escapeState) Transition(s state) error {
|
||||||
|
escState.parser.logf("Escape::Transition %s --> %s", escState.Name(), s.Name())
|
||||||
|
escState.baseState.Transition(s)
|
||||||
|
|
||||||
|
switch s {
|
||||||
|
case escState.parser.ground:
|
||||||
|
return escState.parser.escDispatch()
|
||||||
|
case escState.parser.escapeIntermediate:
|
||||||
|
return escState.parser.collectInter()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (escState escapeState) Enter() error {
|
||||||
|
escState.parser.clear()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
+90
@@ -0,0 +1,90 @@
|
|||||||
|
package ansiterm
|
||||||
|
|
||||||
|
type AnsiEventHandler interface {
|
||||||
|
// Print
|
||||||
|
Print(b byte) error
|
||||||
|
|
||||||
|
// Execute C0 commands
|
||||||
|
Execute(b byte) error
|
||||||
|
|
||||||
|
// CUrsor Up
|
||||||
|
CUU(int) error
|
||||||
|
|
||||||
|
// CUrsor Down
|
||||||
|
CUD(int) error
|
||||||
|
|
||||||
|
// CUrsor Forward
|
||||||
|
CUF(int) error
|
||||||
|
|
||||||
|
// CUrsor Backward
|
||||||
|
CUB(int) error
|
||||||
|
|
||||||
|
// Cursor to Next Line
|
||||||
|
CNL(int) error
|
||||||
|
|
||||||
|
// Cursor to Previous Line
|
||||||
|
CPL(int) error
|
||||||
|
|
||||||
|
// Cursor Horizontal position Absolute
|
||||||
|
CHA(int) error
|
||||||
|
|
||||||
|
// Vertical line Position Absolute
|
||||||
|
VPA(int) error
|
||||||
|
|
||||||
|
// CUrsor Position
|
||||||
|
CUP(int, int) error
|
||||||
|
|
||||||
|
// Horizontal and Vertical Position (depends on PUM)
|
||||||
|
HVP(int, int) error
|
||||||
|
|
||||||
|
// Text Cursor Enable Mode
|
||||||
|
DECTCEM(bool) error
|
||||||
|
|
||||||
|
// Origin Mode
|
||||||
|
DECOM(bool) error
|
||||||
|
|
||||||
|
// 132 Column Mode
|
||||||
|
DECCOLM(bool) error
|
||||||
|
|
||||||
|
// Erase in Display
|
||||||
|
ED(int) error
|
||||||
|
|
||||||
|
// Erase in Line
|
||||||
|
EL(int) error
|
||||||
|
|
||||||
|
// Insert Line
|
||||||
|
IL(int) error
|
||||||
|
|
||||||
|
// Delete Line
|
||||||
|
DL(int) error
|
||||||
|
|
||||||
|
// Insert Character
|
||||||
|
ICH(int) error
|
||||||
|
|
||||||
|
// Delete Character
|
||||||
|
DCH(int) error
|
||||||
|
|
||||||
|
// Set Graphics Rendition
|
||||||
|
SGR([]int) error
|
||||||
|
|
||||||
|
// Pan Down
|
||||||
|
SU(int) error
|
||||||
|
|
||||||
|
// Pan Up
|
||||||
|
SD(int) error
|
||||||
|
|
||||||
|
// Device Attributes
|
||||||
|
DA([]string) error
|
||||||
|
|
||||||
|
// Set Top and Bottom Margins
|
||||||
|
DECSTBM(int, int) error
|
||||||
|
|
||||||
|
// Index
|
||||||
|
IND() error
|
||||||
|
|
||||||
|
// Reverse Index
|
||||||
|
RI() error
|
||||||
|
|
||||||
|
// Flush updates from previous commands
|
||||||
|
Flush() error
|
||||||
|
}
|
||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
package ansiterm
|
||||||
|
|
||||||
|
type groundState struct {
|
||||||
|
baseState
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gs groundState) Handle(b byte) (s state, e error) {
|
||||||
|
gs.parser.context.currentChar = b
|
||||||
|
|
||||||
|
nextState, err := gs.baseState.Handle(b)
|
||||||
|
if nextState != nil || err != nil {
|
||||||
|
return nextState, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case sliceContains(printables, b):
|
||||||
|
return gs, gs.parser.print()
|
||||||
|
|
||||||
|
case sliceContains(executors, b):
|
||||||
|
return gs, gs.parser.execute()
|
||||||
|
}
|
||||||
|
|
||||||
|
return gs, nil
|
||||||
|
}
|
||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
package ansiterm
|
||||||
|
|
||||||
|
type oscStringState struct {
|
||||||
|
baseState
|
||||||
|
}
|
||||||
|
|
||||||
|
func (oscState oscStringState) Handle(b byte) (s state, e error) {
|
||||||
|
oscState.parser.logf("OscString::Handle %#x", b)
|
||||||
|
nextState, err := oscState.baseState.Handle(b)
|
||||||
|
if nextState != nil || err != nil {
|
||||||
|
return nextState, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case isOscStringTerminator(b):
|
||||||
|
return oscState.parser.ground, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return oscState, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// See below for OSC string terminators for linux
|
||||||
|
// http://man7.org/linux/man-pages/man4/console_codes.4.html
|
||||||
|
func isOscStringTerminator(b byte) bool {
|
||||||
|
|
||||||
|
if b == ANSI_BEL || b == 0x5C {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
+151
@@ -0,0 +1,151 @@
|
|||||||
|
package ansiterm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AnsiParser struct {
|
||||||
|
currState state
|
||||||
|
eventHandler AnsiEventHandler
|
||||||
|
context *ansiContext
|
||||||
|
csiEntry state
|
||||||
|
csiParam state
|
||||||
|
dcsEntry state
|
||||||
|
escape state
|
||||||
|
escapeIntermediate state
|
||||||
|
error state
|
||||||
|
ground state
|
||||||
|
oscString state
|
||||||
|
stateMap []state
|
||||||
|
|
||||||
|
logf func(string, ...interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
type Option func(*AnsiParser)
|
||||||
|
|
||||||
|
func WithLogf(f func(string, ...interface{})) Option {
|
||||||
|
return func(ap *AnsiParser) {
|
||||||
|
ap.logf = f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateParser(initialState string, evtHandler AnsiEventHandler, opts ...Option) *AnsiParser {
|
||||||
|
ap := &AnsiParser{
|
||||||
|
eventHandler: evtHandler,
|
||||||
|
context: &ansiContext{},
|
||||||
|
}
|
||||||
|
for _, o := range opts {
|
||||||
|
o(ap)
|
||||||
|
}
|
||||||
|
|
||||||
|
if isDebugEnv := os.Getenv(LogEnv); isDebugEnv == "1" {
|
||||||
|
logFile, _ := os.Create("ansiParser.log")
|
||||||
|
logger := log.New(logFile, "", log.LstdFlags)
|
||||||
|
if ap.logf != nil {
|
||||||
|
l := ap.logf
|
||||||
|
ap.logf = func(s string, v ...interface{}) {
|
||||||
|
l(s, v...)
|
||||||
|
logger.Printf(s, v...)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ap.logf = logger.Printf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ap.logf == nil {
|
||||||
|
ap.logf = func(string, ...interface{}) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
ap.csiEntry = csiEntryState{baseState{name: "CsiEntry", parser: ap}}
|
||||||
|
ap.csiParam = csiParamState{baseState{name: "CsiParam", parser: ap}}
|
||||||
|
ap.dcsEntry = dcsEntryState{baseState{name: "DcsEntry", parser: ap}}
|
||||||
|
ap.escape = escapeState{baseState{name: "Escape", parser: ap}}
|
||||||
|
ap.escapeIntermediate = escapeIntermediateState{baseState{name: "EscapeIntermediate", parser: ap}}
|
||||||
|
ap.error = errorState{baseState{name: "Error", parser: ap}}
|
||||||
|
ap.ground = groundState{baseState{name: "Ground", parser: ap}}
|
||||||
|
ap.oscString = oscStringState{baseState{name: "OscString", parser: ap}}
|
||||||
|
|
||||||
|
ap.stateMap = []state{
|
||||||
|
ap.csiEntry,
|
||||||
|
ap.csiParam,
|
||||||
|
ap.dcsEntry,
|
||||||
|
ap.escape,
|
||||||
|
ap.escapeIntermediate,
|
||||||
|
ap.error,
|
||||||
|
ap.ground,
|
||||||
|
ap.oscString,
|
||||||
|
}
|
||||||
|
|
||||||
|
ap.currState = getState(initialState, ap.stateMap)
|
||||||
|
|
||||||
|
ap.logf("CreateParser: parser %p", ap)
|
||||||
|
return ap
|
||||||
|
}
|
||||||
|
|
||||||
|
func getState(name string, states []state) state {
|
||||||
|
for _, el := range states {
|
||||||
|
if el.Name() == name {
|
||||||
|
return el
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AnsiParser) Parse(bytes []byte) (int, error) {
|
||||||
|
for i, b := range bytes {
|
||||||
|
if err := ap.handle(b); err != nil {
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return len(bytes), ap.eventHandler.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AnsiParser) handle(b byte) error {
|
||||||
|
ap.context.currentChar = b
|
||||||
|
newState, err := ap.currState.Handle(b)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if newState == nil {
|
||||||
|
ap.logf("WARNING: newState is nil")
|
||||||
|
return errors.New("New state of 'nil' is invalid.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if newState != ap.currState {
|
||||||
|
if err := ap.changeState(newState); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AnsiParser) changeState(newState state) error {
|
||||||
|
ap.logf("ChangeState %s --> %s", ap.currState.Name(), newState.Name())
|
||||||
|
|
||||||
|
// Exit old state
|
||||||
|
if err := ap.currState.Exit(); err != nil {
|
||||||
|
ap.logf("Exit state '%s' failed with : '%v'", ap.currState.Name(), err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform transition action
|
||||||
|
if err := ap.currState.Transition(newState); err != nil {
|
||||||
|
ap.logf("Transition from '%s' to '%s' failed with: '%v'", ap.currState.Name(), newState.Name, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enter new state
|
||||||
|
if err := newState.Enter(); err != nil {
|
||||||
|
ap.logf("Enter state '%s' failed with: '%v'", newState.Name(), err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ap.currState = newState
|
||||||
|
return nil
|
||||||
|
}
|
||||||
+99
@@ -0,0 +1,99 @@
|
|||||||
|
package ansiterm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func parseParams(bytes []byte) ([]string, error) {
|
||||||
|
paramBuff := make([]byte, 0, 0)
|
||||||
|
params := []string{}
|
||||||
|
|
||||||
|
for _, v := range bytes {
|
||||||
|
if v == ';' {
|
||||||
|
if len(paramBuff) > 0 {
|
||||||
|
// Completed parameter, append it to the list
|
||||||
|
s := string(paramBuff)
|
||||||
|
params = append(params, s)
|
||||||
|
paramBuff = make([]byte, 0, 0)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
paramBuff = append(paramBuff, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Last parameter may not be terminated with ';'
|
||||||
|
if len(paramBuff) > 0 {
|
||||||
|
s := string(paramBuff)
|
||||||
|
params = append(params, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
return params, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseCmd(context ansiContext) (string, error) {
|
||||||
|
return string(context.currentChar), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getInt(params []string, dflt int) int {
|
||||||
|
i := getInts(params, 1, dflt)[0]
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
func getInts(params []string, minCount int, dflt int) []int {
|
||||||
|
ints := []int{}
|
||||||
|
|
||||||
|
for _, v := range params {
|
||||||
|
i, _ := strconv.Atoi(v)
|
||||||
|
// Zero is mapped to the default value in VT100.
|
||||||
|
if i == 0 {
|
||||||
|
i = dflt
|
||||||
|
}
|
||||||
|
ints = append(ints, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(ints) < minCount {
|
||||||
|
remaining := minCount - len(ints)
|
||||||
|
for i := 0; i < remaining; i++ {
|
||||||
|
ints = append(ints, dflt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ints
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AnsiParser) modeDispatch(param string, set bool) error {
|
||||||
|
switch param {
|
||||||
|
case "?3":
|
||||||
|
return ap.eventHandler.DECCOLM(set)
|
||||||
|
case "?6":
|
||||||
|
return ap.eventHandler.DECOM(set)
|
||||||
|
case "?25":
|
||||||
|
return ap.eventHandler.DECTCEM(set)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AnsiParser) hDispatch(params []string) error {
|
||||||
|
if len(params) == 1 {
|
||||||
|
return ap.modeDispatch(params[0], true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AnsiParser) lDispatch(params []string) error {
|
||||||
|
if len(params) == 1 {
|
||||||
|
return ap.modeDispatch(params[0], false)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getEraseParam(params []string) int {
|
||||||
|
param := getInt(params, 0)
|
||||||
|
if param < 0 || 3 < param {
|
||||||
|
param = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return param
|
||||||
|
}
|
||||||
+119
@@ -0,0 +1,119 @@
|
|||||||
|
package ansiterm
|
||||||
|
|
||||||
|
func (ap *AnsiParser) collectParam() error {
|
||||||
|
currChar := ap.context.currentChar
|
||||||
|
ap.logf("collectParam %#x", currChar)
|
||||||
|
ap.context.paramBuffer = append(ap.context.paramBuffer, currChar)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AnsiParser) collectInter() error {
|
||||||
|
currChar := ap.context.currentChar
|
||||||
|
ap.logf("collectInter %#x", currChar)
|
||||||
|
ap.context.paramBuffer = append(ap.context.interBuffer, currChar)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AnsiParser) escDispatch() error {
|
||||||
|
cmd, _ := parseCmd(*ap.context)
|
||||||
|
intermeds := ap.context.interBuffer
|
||||||
|
ap.logf("escDispatch currentChar: %#x", ap.context.currentChar)
|
||||||
|
ap.logf("escDispatch: %v(%v)", cmd, intermeds)
|
||||||
|
|
||||||
|
switch cmd {
|
||||||
|
case "D": // IND
|
||||||
|
return ap.eventHandler.IND()
|
||||||
|
case "E": // NEL, equivalent to CRLF
|
||||||
|
err := ap.eventHandler.Execute(ANSI_CARRIAGE_RETURN)
|
||||||
|
if err == nil {
|
||||||
|
err = ap.eventHandler.Execute(ANSI_LINE_FEED)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
case "M": // RI
|
||||||
|
return ap.eventHandler.RI()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AnsiParser) csiDispatch() error {
|
||||||
|
cmd, _ := parseCmd(*ap.context)
|
||||||
|
params, _ := parseParams(ap.context.paramBuffer)
|
||||||
|
ap.logf("Parsed params: %v with length: %d", params, len(params))
|
||||||
|
|
||||||
|
ap.logf("csiDispatch: %v(%v)", cmd, params)
|
||||||
|
|
||||||
|
switch cmd {
|
||||||
|
case "@":
|
||||||
|
return ap.eventHandler.ICH(getInt(params, 1))
|
||||||
|
case "A":
|
||||||
|
return ap.eventHandler.CUU(getInt(params, 1))
|
||||||
|
case "B":
|
||||||
|
return ap.eventHandler.CUD(getInt(params, 1))
|
||||||
|
case "C":
|
||||||
|
return ap.eventHandler.CUF(getInt(params, 1))
|
||||||
|
case "D":
|
||||||
|
return ap.eventHandler.CUB(getInt(params, 1))
|
||||||
|
case "E":
|
||||||
|
return ap.eventHandler.CNL(getInt(params, 1))
|
||||||
|
case "F":
|
||||||
|
return ap.eventHandler.CPL(getInt(params, 1))
|
||||||
|
case "G":
|
||||||
|
return ap.eventHandler.CHA(getInt(params, 1))
|
||||||
|
case "H":
|
||||||
|
ints := getInts(params, 2, 1)
|
||||||
|
x, y := ints[0], ints[1]
|
||||||
|
return ap.eventHandler.CUP(x, y)
|
||||||
|
case "J":
|
||||||
|
param := getEraseParam(params)
|
||||||
|
return ap.eventHandler.ED(param)
|
||||||
|
case "K":
|
||||||
|
param := getEraseParam(params)
|
||||||
|
return ap.eventHandler.EL(param)
|
||||||
|
case "L":
|
||||||
|
return ap.eventHandler.IL(getInt(params, 1))
|
||||||
|
case "M":
|
||||||
|
return ap.eventHandler.DL(getInt(params, 1))
|
||||||
|
case "P":
|
||||||
|
return ap.eventHandler.DCH(getInt(params, 1))
|
||||||
|
case "S":
|
||||||
|
return ap.eventHandler.SU(getInt(params, 1))
|
||||||
|
case "T":
|
||||||
|
return ap.eventHandler.SD(getInt(params, 1))
|
||||||
|
case "c":
|
||||||
|
return ap.eventHandler.DA(params)
|
||||||
|
case "d":
|
||||||
|
return ap.eventHandler.VPA(getInt(params, 1))
|
||||||
|
case "f":
|
||||||
|
ints := getInts(params, 2, 1)
|
||||||
|
x, y := ints[0], ints[1]
|
||||||
|
return ap.eventHandler.HVP(x, y)
|
||||||
|
case "h":
|
||||||
|
return ap.hDispatch(params)
|
||||||
|
case "l":
|
||||||
|
return ap.lDispatch(params)
|
||||||
|
case "m":
|
||||||
|
return ap.eventHandler.SGR(getInts(params, 1, 0))
|
||||||
|
case "r":
|
||||||
|
ints := getInts(params, 2, 1)
|
||||||
|
top, bottom := ints[0], ints[1]
|
||||||
|
return ap.eventHandler.DECSTBM(top, bottom)
|
||||||
|
default:
|
||||||
|
ap.logf("ERROR: Unsupported CSI command: '%s', with full context: %v", cmd, ap.context)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AnsiParser) print() error {
|
||||||
|
return ap.eventHandler.Print(ap.context.currentChar)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AnsiParser) clear() error {
|
||||||
|
ap.context = &ansiContext{}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AnsiParser) execute() error {
|
||||||
|
return ap.eventHandler.Execute(ap.context.currentChar)
|
||||||
|
}
|
||||||
+71
@@ -0,0 +1,71 @@
|
|||||||
|
package ansiterm
|
||||||
|
|
||||||
|
type stateID int
|
||||||
|
|
||||||
|
type state interface {
|
||||||
|
Enter() error
|
||||||
|
Exit() error
|
||||||
|
Handle(byte) (state, error)
|
||||||
|
Name() string
|
||||||
|
Transition(state) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type baseState struct {
|
||||||
|
name string
|
||||||
|
parser *AnsiParser
|
||||||
|
}
|
||||||
|
|
||||||
|
func (base baseState) Enter() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (base baseState) Exit() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (base baseState) Handle(b byte) (s state, e error) {
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case b == CSI_ENTRY:
|
||||||
|
return base.parser.csiEntry, nil
|
||||||
|
case b == DCS_ENTRY:
|
||||||
|
return base.parser.dcsEntry, nil
|
||||||
|
case b == ANSI_ESCAPE_PRIMARY:
|
||||||
|
return base.parser.escape, nil
|
||||||
|
case b == OSC_STRING:
|
||||||
|
return base.parser.oscString, nil
|
||||||
|
case sliceContains(toGroundBytes, b):
|
||||||
|
return base.parser.ground, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (base baseState) Name() string {
|
||||||
|
return base.name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (base baseState) Transition(s state) error {
|
||||||
|
if s == base.parser.ground {
|
||||||
|
execBytes := []byte{0x18}
|
||||||
|
execBytes = append(execBytes, 0x1A)
|
||||||
|
execBytes = append(execBytes, getByteRange(0x80, 0x8F)...)
|
||||||
|
execBytes = append(execBytes, getByteRange(0x91, 0x97)...)
|
||||||
|
execBytes = append(execBytes, 0x99)
|
||||||
|
execBytes = append(execBytes, 0x9A)
|
||||||
|
|
||||||
|
if sliceContains(execBytes, base.parser.context.currentChar) {
|
||||||
|
return base.parser.execute()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type dcsEntryState struct {
|
||||||
|
baseState
|
||||||
|
}
|
||||||
|
|
||||||
|
type errorState struct {
|
||||||
|
baseState
|
||||||
|
}
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
package ansiterm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func sliceContains(bytes []byte, b byte) bool {
|
||||||
|
for _, v := range bytes {
|
||||||
|
if v == b {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertBytesToInteger(bytes []byte) int {
|
||||||
|
s := string(bytes)
|
||||||
|
i, _ := strconv.Atoi(s)
|
||||||
|
return i
|
||||||
|
}
|
||||||
+182
@@ -0,0 +1,182 @@
|
|||||||
|
// +build windows
|
||||||
|
|
||||||
|
package winterm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/Azure/go-ansiterm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Windows keyboard constants
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx.
|
||||||
|
const (
|
||||||
|
VK_PRIOR = 0x21 // PAGE UP key
|
||||||
|
VK_NEXT = 0x22 // PAGE DOWN key
|
||||||
|
VK_END = 0x23 // END key
|
||||||
|
VK_HOME = 0x24 // HOME key
|
||||||
|
VK_LEFT = 0x25 // LEFT ARROW key
|
||||||
|
VK_UP = 0x26 // UP ARROW key
|
||||||
|
VK_RIGHT = 0x27 // RIGHT ARROW key
|
||||||
|
VK_DOWN = 0x28 // DOWN ARROW key
|
||||||
|
VK_SELECT = 0x29 // SELECT key
|
||||||
|
VK_PRINT = 0x2A // PRINT key
|
||||||
|
VK_EXECUTE = 0x2B // EXECUTE key
|
||||||
|
VK_SNAPSHOT = 0x2C // PRINT SCREEN key
|
||||||
|
VK_INSERT = 0x2D // INS key
|
||||||
|
VK_DELETE = 0x2E // DEL key
|
||||||
|
VK_HELP = 0x2F // HELP key
|
||||||
|
VK_F1 = 0x70 // F1 key
|
||||||
|
VK_F2 = 0x71 // F2 key
|
||||||
|
VK_F3 = 0x72 // F3 key
|
||||||
|
VK_F4 = 0x73 // F4 key
|
||||||
|
VK_F5 = 0x74 // F5 key
|
||||||
|
VK_F6 = 0x75 // F6 key
|
||||||
|
VK_F7 = 0x76 // F7 key
|
||||||
|
VK_F8 = 0x77 // F8 key
|
||||||
|
VK_F9 = 0x78 // F9 key
|
||||||
|
VK_F10 = 0x79 // F10 key
|
||||||
|
VK_F11 = 0x7A // F11 key
|
||||||
|
VK_F12 = 0x7B // F12 key
|
||||||
|
|
||||||
|
RIGHT_ALT_PRESSED = 0x0001
|
||||||
|
LEFT_ALT_PRESSED = 0x0002
|
||||||
|
RIGHT_CTRL_PRESSED = 0x0004
|
||||||
|
LEFT_CTRL_PRESSED = 0x0008
|
||||||
|
SHIFT_PRESSED = 0x0010
|
||||||
|
NUMLOCK_ON = 0x0020
|
||||||
|
SCROLLLOCK_ON = 0x0040
|
||||||
|
CAPSLOCK_ON = 0x0080
|
||||||
|
ENHANCED_KEY = 0x0100
|
||||||
|
)
|
||||||
|
|
||||||
|
type ansiCommand struct {
|
||||||
|
CommandBytes []byte
|
||||||
|
Command string
|
||||||
|
Parameters []string
|
||||||
|
IsSpecial bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func newAnsiCommand(command []byte) *ansiCommand {
|
||||||
|
|
||||||
|
if isCharacterSelectionCmdChar(command[1]) {
|
||||||
|
// Is Character Set Selection commands
|
||||||
|
return &ansiCommand{
|
||||||
|
CommandBytes: command,
|
||||||
|
Command: string(command),
|
||||||
|
IsSpecial: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// last char is command character
|
||||||
|
lastCharIndex := len(command) - 1
|
||||||
|
|
||||||
|
ac := &ansiCommand{
|
||||||
|
CommandBytes: command,
|
||||||
|
Command: string(command[lastCharIndex]),
|
||||||
|
IsSpecial: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
// more than a single escape
|
||||||
|
if lastCharIndex != 0 {
|
||||||
|
start := 1
|
||||||
|
// skip if double char escape sequence
|
||||||
|
if command[0] == ansiterm.ANSI_ESCAPE_PRIMARY && command[1] == ansiterm.ANSI_ESCAPE_SECONDARY {
|
||||||
|
start++
|
||||||
|
}
|
||||||
|
// convert this to GetNextParam method
|
||||||
|
ac.Parameters = strings.Split(string(command[start:lastCharIndex]), ansiterm.ANSI_PARAMETER_SEP)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ac
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *ansiCommand) paramAsSHORT(index int, defaultValue int16) int16 {
|
||||||
|
if index < 0 || index >= len(ac.Parameters) {
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
param, err := strconv.ParseInt(ac.Parameters[index], 10, 16)
|
||||||
|
if err != nil {
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
return int16(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *ansiCommand) String() string {
|
||||||
|
return fmt.Sprintf("0x%v \"%v\" (\"%v\")",
|
||||||
|
bytesToHex(ac.CommandBytes),
|
||||||
|
ac.Command,
|
||||||
|
strings.Join(ac.Parameters, "\",\""))
|
||||||
|
}
|
||||||
|
|
||||||
|
// isAnsiCommandChar returns true if the passed byte falls within the range of ANSI commands.
|
||||||
|
// See http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html.
|
||||||
|
func isAnsiCommandChar(b byte) bool {
|
||||||
|
switch {
|
||||||
|
case ansiterm.ANSI_COMMAND_FIRST <= b && b <= ansiterm.ANSI_COMMAND_LAST && b != ansiterm.ANSI_ESCAPE_SECONDARY:
|
||||||
|
return true
|
||||||
|
case b == ansiterm.ANSI_CMD_G1 || b == ansiterm.ANSI_CMD_OSC || b == ansiterm.ANSI_CMD_DECPAM || b == ansiterm.ANSI_CMD_DECPNM:
|
||||||
|
// non-CSI escape sequence terminator
|
||||||
|
return true
|
||||||
|
case b == ansiterm.ANSI_CMD_STR_TERM || b == ansiterm.ANSI_BEL:
|
||||||
|
// String escape sequence terminator
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func isXtermOscSequence(command []byte, current byte) bool {
|
||||||
|
return (len(command) >= 2 && command[0] == ansiterm.ANSI_ESCAPE_PRIMARY && command[1] == ansiterm.ANSI_CMD_OSC && current != ansiterm.ANSI_BEL)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isCharacterSelectionCmdChar(b byte) bool {
|
||||||
|
return (b == ansiterm.ANSI_CMD_G0 || b == ansiterm.ANSI_CMD_G1 || b == ansiterm.ANSI_CMD_G2 || b == ansiterm.ANSI_CMD_G3)
|
||||||
|
}
|
||||||
|
|
||||||
|
// bytesToHex converts a slice of bytes to a human-readable string.
|
||||||
|
func bytesToHex(b []byte) string {
|
||||||
|
hex := make([]string, len(b))
|
||||||
|
for i, ch := range b {
|
||||||
|
hex[i] = fmt.Sprintf("%X", ch)
|
||||||
|
}
|
||||||
|
return strings.Join(hex, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensureInRange adjusts the passed value, if necessary, to ensure it is within
|
||||||
|
// the passed min / max range.
|
||||||
|
func ensureInRange(n int16, min int16, max int16) int16 {
|
||||||
|
if n < min {
|
||||||
|
return min
|
||||||
|
} else if n > max {
|
||||||
|
return max
|
||||||
|
} else {
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetStdFile(nFile int) (*os.File, uintptr) {
|
||||||
|
var file *os.File
|
||||||
|
switch nFile {
|
||||||
|
case syscall.STD_INPUT_HANDLE:
|
||||||
|
file = os.Stdin
|
||||||
|
case syscall.STD_OUTPUT_HANDLE:
|
||||||
|
file = os.Stdout
|
||||||
|
case syscall.STD_ERROR_HANDLE:
|
||||||
|
file = os.Stderr
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf("Invalid standard handle identifier: %v", nFile))
|
||||||
|
}
|
||||||
|
|
||||||
|
fd, err := syscall.GetStdHandle(nFile)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Errorf("Invalid standard handle identifier: %v -- %v", nFile, err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return file, uintptr(fd)
|
||||||
|
}
|
||||||
+327
@@ -0,0 +1,327 @@
|
|||||||
|
// +build windows
|
||||||
|
|
||||||
|
package winterm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
//===========================================================================================================
|
||||||
|
// IMPORTANT NOTE:
|
||||||
|
//
|
||||||
|
// The methods below make extensive use of the "unsafe" package to obtain the required pointers.
|
||||||
|
// Beginning in Go 1.3, the garbage collector may release local variables (e.g., incoming arguments, stack
|
||||||
|
// variables) the pointers reference *before* the API completes.
|
||||||
|
//
|
||||||
|
// As a result, in those cases, the code must hint that the variables remain in active by invoking the
|
||||||
|
// dummy method "use" (see below). Newer versions of Go are planned to change the mechanism to no longer
|
||||||
|
// require unsafe pointers.
|
||||||
|
//
|
||||||
|
// If you add or modify methods, ENSURE protection of local variables through the "use" builtin to inform
|
||||||
|
// the garbage collector the variables remain in use if:
|
||||||
|
//
|
||||||
|
// -- The value is not a pointer (e.g., int32, struct)
|
||||||
|
// -- The value is not referenced by the method after passing the pointer to Windows
|
||||||
|
//
|
||||||
|
// See http://golang.org/doc/go1.3.
|
||||||
|
//===========================================================================================================
|
||||||
|
|
||||||
|
var (
|
||||||
|
kernel32DLL = syscall.NewLazyDLL("kernel32.dll")
|
||||||
|
|
||||||
|
getConsoleCursorInfoProc = kernel32DLL.NewProc("GetConsoleCursorInfo")
|
||||||
|
setConsoleCursorInfoProc = kernel32DLL.NewProc("SetConsoleCursorInfo")
|
||||||
|
setConsoleCursorPositionProc = kernel32DLL.NewProc("SetConsoleCursorPosition")
|
||||||
|
setConsoleModeProc = kernel32DLL.NewProc("SetConsoleMode")
|
||||||
|
getConsoleScreenBufferInfoProc = kernel32DLL.NewProc("GetConsoleScreenBufferInfo")
|
||||||
|
setConsoleScreenBufferSizeProc = kernel32DLL.NewProc("SetConsoleScreenBufferSize")
|
||||||
|
scrollConsoleScreenBufferProc = kernel32DLL.NewProc("ScrollConsoleScreenBufferA")
|
||||||
|
setConsoleTextAttributeProc = kernel32DLL.NewProc("SetConsoleTextAttribute")
|
||||||
|
setConsoleWindowInfoProc = kernel32DLL.NewProc("SetConsoleWindowInfo")
|
||||||
|
writeConsoleOutputProc = kernel32DLL.NewProc("WriteConsoleOutputW")
|
||||||
|
readConsoleInputProc = kernel32DLL.NewProc("ReadConsoleInputW")
|
||||||
|
waitForSingleObjectProc = kernel32DLL.NewProc("WaitForSingleObject")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Windows Console constants
|
||||||
|
const (
|
||||||
|
// Console modes
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx.
|
||||||
|
ENABLE_PROCESSED_INPUT = 0x0001
|
||||||
|
ENABLE_LINE_INPUT = 0x0002
|
||||||
|
ENABLE_ECHO_INPUT = 0x0004
|
||||||
|
ENABLE_WINDOW_INPUT = 0x0008
|
||||||
|
ENABLE_MOUSE_INPUT = 0x0010
|
||||||
|
ENABLE_INSERT_MODE = 0x0020
|
||||||
|
ENABLE_QUICK_EDIT_MODE = 0x0040
|
||||||
|
ENABLE_EXTENDED_FLAGS = 0x0080
|
||||||
|
ENABLE_AUTO_POSITION = 0x0100
|
||||||
|
ENABLE_VIRTUAL_TERMINAL_INPUT = 0x0200
|
||||||
|
|
||||||
|
ENABLE_PROCESSED_OUTPUT = 0x0001
|
||||||
|
ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002
|
||||||
|
ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004
|
||||||
|
DISABLE_NEWLINE_AUTO_RETURN = 0x0008
|
||||||
|
ENABLE_LVB_GRID_WORLDWIDE = 0x0010
|
||||||
|
|
||||||
|
// Character attributes
|
||||||
|
// Note:
|
||||||
|
// -- The attributes are combined to produce various colors (e.g., Blue + Green will create Cyan).
|
||||||
|
// Clearing all foreground or background colors results in black; setting all creates white.
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682088(v=vs.85).aspx#_win32_character_attributes.
|
||||||
|
FOREGROUND_BLUE uint16 = 0x0001
|
||||||
|
FOREGROUND_GREEN uint16 = 0x0002
|
||||||
|
FOREGROUND_RED uint16 = 0x0004
|
||||||
|
FOREGROUND_INTENSITY uint16 = 0x0008
|
||||||
|
FOREGROUND_MASK uint16 = 0x000F
|
||||||
|
|
||||||
|
BACKGROUND_BLUE uint16 = 0x0010
|
||||||
|
BACKGROUND_GREEN uint16 = 0x0020
|
||||||
|
BACKGROUND_RED uint16 = 0x0040
|
||||||
|
BACKGROUND_INTENSITY uint16 = 0x0080
|
||||||
|
BACKGROUND_MASK uint16 = 0x00F0
|
||||||
|
|
||||||
|
COMMON_LVB_MASK uint16 = 0xFF00
|
||||||
|
COMMON_LVB_REVERSE_VIDEO uint16 = 0x4000
|
||||||
|
COMMON_LVB_UNDERSCORE uint16 = 0x8000
|
||||||
|
|
||||||
|
// Input event types
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx.
|
||||||
|
KEY_EVENT = 0x0001
|
||||||
|
MOUSE_EVENT = 0x0002
|
||||||
|
WINDOW_BUFFER_SIZE_EVENT = 0x0004
|
||||||
|
MENU_EVENT = 0x0008
|
||||||
|
FOCUS_EVENT = 0x0010
|
||||||
|
|
||||||
|
// WaitForSingleObject return codes
|
||||||
|
WAIT_ABANDONED = 0x00000080
|
||||||
|
WAIT_FAILED = 0xFFFFFFFF
|
||||||
|
WAIT_SIGNALED = 0x0000000
|
||||||
|
WAIT_TIMEOUT = 0x00000102
|
||||||
|
|
||||||
|
// WaitForSingleObject wait duration
|
||||||
|
WAIT_INFINITE = 0xFFFFFFFF
|
||||||
|
WAIT_ONE_SECOND = 1000
|
||||||
|
WAIT_HALF_SECOND = 500
|
||||||
|
WAIT_QUARTER_SECOND = 250
|
||||||
|
)
|
||||||
|
|
||||||
|
// Windows API Console types
|
||||||
|
// -- See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682101(v=vs.85).aspx for Console specific types (e.g., COORD)
|
||||||
|
// -- See https://msdn.microsoft.com/en-us/library/aa296569(v=vs.60).aspx for comments on alignment
|
||||||
|
type (
|
||||||
|
CHAR_INFO struct {
|
||||||
|
UnicodeChar uint16
|
||||||
|
Attributes uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
CONSOLE_CURSOR_INFO struct {
|
||||||
|
Size uint32
|
||||||
|
Visible int32
|
||||||
|
}
|
||||||
|
|
||||||
|
CONSOLE_SCREEN_BUFFER_INFO struct {
|
||||||
|
Size COORD
|
||||||
|
CursorPosition COORD
|
||||||
|
Attributes uint16
|
||||||
|
Window SMALL_RECT
|
||||||
|
MaximumWindowSize COORD
|
||||||
|
}
|
||||||
|
|
||||||
|
COORD struct {
|
||||||
|
X int16
|
||||||
|
Y int16
|
||||||
|
}
|
||||||
|
|
||||||
|
SMALL_RECT struct {
|
||||||
|
Left int16
|
||||||
|
Top int16
|
||||||
|
Right int16
|
||||||
|
Bottom int16
|
||||||
|
}
|
||||||
|
|
||||||
|
// INPUT_RECORD is a C/C++ union of which KEY_EVENT_RECORD is one case, it is also the largest
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx.
|
||||||
|
INPUT_RECORD struct {
|
||||||
|
EventType uint16
|
||||||
|
KeyEvent KEY_EVENT_RECORD
|
||||||
|
}
|
||||||
|
|
||||||
|
KEY_EVENT_RECORD struct {
|
||||||
|
KeyDown int32
|
||||||
|
RepeatCount uint16
|
||||||
|
VirtualKeyCode uint16
|
||||||
|
VirtualScanCode uint16
|
||||||
|
UnicodeChar uint16
|
||||||
|
ControlKeyState uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
WINDOW_BUFFER_SIZE struct {
|
||||||
|
Size COORD
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// boolToBOOL converts a Go bool into a Windows int32.
|
||||||
|
func boolToBOOL(f bool) int32 {
|
||||||
|
if f {
|
||||||
|
return int32(1)
|
||||||
|
} else {
|
||||||
|
return int32(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetConsoleCursorInfo retrieves information about the size and visiblity of the console cursor.
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683163(v=vs.85).aspx.
|
||||||
|
func GetConsoleCursorInfo(handle uintptr, cursorInfo *CONSOLE_CURSOR_INFO) error {
|
||||||
|
r1, r2, err := getConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0)
|
||||||
|
return checkError(r1, r2, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetConsoleCursorInfo sets the size and visiblity of the console cursor.
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686019(v=vs.85).aspx.
|
||||||
|
func SetConsoleCursorInfo(handle uintptr, cursorInfo *CONSOLE_CURSOR_INFO) error {
|
||||||
|
r1, r2, err := setConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0)
|
||||||
|
return checkError(r1, r2, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetConsoleCursorPosition location of the console cursor.
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686025(v=vs.85).aspx.
|
||||||
|
func SetConsoleCursorPosition(handle uintptr, coord COORD) error {
|
||||||
|
r1, r2, err := setConsoleCursorPositionProc.Call(handle, coordToPointer(coord))
|
||||||
|
use(coord)
|
||||||
|
return checkError(r1, r2, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetConsoleMode gets the console mode for given file descriptor
|
||||||
|
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683167(v=vs.85).aspx.
|
||||||
|
func GetConsoleMode(handle uintptr) (mode uint32, err error) {
|
||||||
|
err = syscall.GetConsoleMode(syscall.Handle(handle), &mode)
|
||||||
|
return mode, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetConsoleMode sets the console mode for given file descriptor
|
||||||
|
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx.
|
||||||
|
func SetConsoleMode(handle uintptr, mode uint32) error {
|
||||||
|
r1, r2, err := setConsoleModeProc.Call(handle, uintptr(mode), 0)
|
||||||
|
use(mode)
|
||||||
|
return checkError(r1, r2, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetConsoleScreenBufferInfo retrieves information about the specified console screen buffer.
|
||||||
|
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683171(v=vs.85).aspx.
|
||||||
|
func GetConsoleScreenBufferInfo(handle uintptr) (*CONSOLE_SCREEN_BUFFER_INFO, error) {
|
||||||
|
info := CONSOLE_SCREEN_BUFFER_INFO{}
|
||||||
|
err := checkError(getConsoleScreenBufferInfoProc.Call(handle, uintptr(unsafe.Pointer(&info)), 0))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &info, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ScrollConsoleScreenBuffer(handle uintptr, scrollRect SMALL_RECT, clipRect SMALL_RECT, destOrigin COORD, char CHAR_INFO) error {
|
||||||
|
r1, r2, err := scrollConsoleScreenBufferProc.Call(handle, uintptr(unsafe.Pointer(&scrollRect)), uintptr(unsafe.Pointer(&clipRect)), coordToPointer(destOrigin), uintptr(unsafe.Pointer(&char)))
|
||||||
|
use(scrollRect)
|
||||||
|
use(clipRect)
|
||||||
|
use(destOrigin)
|
||||||
|
use(char)
|
||||||
|
return checkError(r1, r2, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetConsoleScreenBufferSize sets the size of the console screen buffer.
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686044(v=vs.85).aspx.
|
||||||
|
func SetConsoleScreenBufferSize(handle uintptr, coord COORD) error {
|
||||||
|
r1, r2, err := setConsoleScreenBufferSizeProc.Call(handle, coordToPointer(coord))
|
||||||
|
use(coord)
|
||||||
|
return checkError(r1, r2, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetConsoleTextAttribute sets the attributes of characters written to the
|
||||||
|
// console screen buffer by the WriteFile or WriteConsole function.
|
||||||
|
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686047(v=vs.85).aspx.
|
||||||
|
func SetConsoleTextAttribute(handle uintptr, attribute uint16) error {
|
||||||
|
r1, r2, err := setConsoleTextAttributeProc.Call(handle, uintptr(attribute), 0)
|
||||||
|
use(attribute)
|
||||||
|
return checkError(r1, r2, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetConsoleWindowInfo sets the size and position of the console screen buffer's window.
|
||||||
|
// Note that the size and location must be within and no larger than the backing console screen buffer.
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686125(v=vs.85).aspx.
|
||||||
|
func SetConsoleWindowInfo(handle uintptr, isAbsolute bool, rect SMALL_RECT) error {
|
||||||
|
r1, r2, err := setConsoleWindowInfoProc.Call(handle, uintptr(boolToBOOL(isAbsolute)), uintptr(unsafe.Pointer(&rect)))
|
||||||
|
use(isAbsolute)
|
||||||
|
use(rect)
|
||||||
|
return checkError(r1, r2, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteConsoleOutput writes the CHAR_INFOs from the provided buffer to the active console buffer.
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687404(v=vs.85).aspx.
|
||||||
|
func WriteConsoleOutput(handle uintptr, buffer []CHAR_INFO, bufferSize COORD, bufferCoord COORD, writeRegion *SMALL_RECT) error {
|
||||||
|
r1, r2, err := writeConsoleOutputProc.Call(handle, uintptr(unsafe.Pointer(&buffer[0])), coordToPointer(bufferSize), coordToPointer(bufferCoord), uintptr(unsafe.Pointer(writeRegion)))
|
||||||
|
use(buffer)
|
||||||
|
use(bufferSize)
|
||||||
|
use(bufferCoord)
|
||||||
|
return checkError(r1, r2, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadConsoleInput reads (and removes) data from the console input buffer.
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms684961(v=vs.85).aspx.
|
||||||
|
func ReadConsoleInput(handle uintptr, buffer []INPUT_RECORD, count *uint32) error {
|
||||||
|
r1, r2, err := readConsoleInputProc.Call(handle, uintptr(unsafe.Pointer(&buffer[0])), uintptr(len(buffer)), uintptr(unsafe.Pointer(count)))
|
||||||
|
use(buffer)
|
||||||
|
return checkError(r1, r2, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WaitForSingleObject waits for the passed handle to be signaled.
|
||||||
|
// It returns true if the handle was signaled; false otherwise.
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687032(v=vs.85).aspx.
|
||||||
|
func WaitForSingleObject(handle uintptr, msWait uint32) (bool, error) {
|
||||||
|
r1, _, err := waitForSingleObjectProc.Call(handle, uintptr(uint32(msWait)))
|
||||||
|
switch r1 {
|
||||||
|
case WAIT_ABANDONED, WAIT_TIMEOUT:
|
||||||
|
return false, nil
|
||||||
|
case WAIT_SIGNALED:
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
use(msWait)
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// String helpers
|
||||||
|
func (info CONSOLE_SCREEN_BUFFER_INFO) String() string {
|
||||||
|
return fmt.Sprintf("Size(%v) Cursor(%v) Window(%v) Max(%v)", info.Size, info.CursorPosition, info.Window, info.MaximumWindowSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (coord COORD) String() string {
|
||||||
|
return fmt.Sprintf("%v,%v", coord.X, coord.Y)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rect SMALL_RECT) String() string {
|
||||||
|
return fmt.Sprintf("(%v,%v),(%v,%v)", rect.Left, rect.Top, rect.Right, rect.Bottom)
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkError evaluates the results of a Windows API call and returns the error if it failed.
|
||||||
|
func checkError(r1, r2 uintptr, err error) error {
|
||||||
|
// Windows APIs return non-zero to indicate success
|
||||||
|
if r1 != 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the error if provided, otherwise default to EINVAL
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return syscall.EINVAL
|
||||||
|
}
|
||||||
|
|
||||||
|
// coordToPointer converts a COORD into a uintptr (by fooling the type system).
|
||||||
|
func coordToPointer(c COORD) uintptr {
|
||||||
|
// Note: This code assumes the two SHORTs are correctly laid out; the "cast" to uint32 is just to get a pointer to pass.
|
||||||
|
return uintptr(*((*uint32)(unsafe.Pointer(&c))))
|
||||||
|
}
|
||||||
|
|
||||||
|
// use is a no-op, but the compiler cannot see that it is.
|
||||||
|
// Calling use(p) ensures that p is kept live until that point.
|
||||||
|
func use(p interface{}) {}
|
||||||
+100
@@ -0,0 +1,100 @@
|
|||||||
|
// +build windows
|
||||||
|
|
||||||
|
package winterm
|
||||||
|
|
||||||
|
import "github.com/Azure/go-ansiterm"
|
||||||
|
|
||||||
|
const (
|
||||||
|
FOREGROUND_COLOR_MASK = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
|
||||||
|
BACKGROUND_COLOR_MASK = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
|
||||||
|
)
|
||||||
|
|
||||||
|
// collectAnsiIntoWindowsAttributes modifies the passed Windows text mode flags to reflect the
|
||||||
|
// request represented by the passed ANSI mode.
|
||||||
|
func collectAnsiIntoWindowsAttributes(windowsMode uint16, inverted bool, baseMode uint16, ansiMode int16) (uint16, bool) {
|
||||||
|
switch ansiMode {
|
||||||
|
|
||||||
|
// Mode styles
|
||||||
|
case ansiterm.ANSI_SGR_BOLD:
|
||||||
|
windowsMode = windowsMode | FOREGROUND_INTENSITY
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_DIM, ansiterm.ANSI_SGR_BOLD_DIM_OFF:
|
||||||
|
windowsMode &^= FOREGROUND_INTENSITY
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_UNDERLINE:
|
||||||
|
windowsMode = windowsMode | COMMON_LVB_UNDERSCORE
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_REVERSE:
|
||||||
|
inverted = true
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_REVERSE_OFF:
|
||||||
|
inverted = false
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_UNDERLINE_OFF:
|
||||||
|
windowsMode &^= COMMON_LVB_UNDERSCORE
|
||||||
|
|
||||||
|
// Foreground colors
|
||||||
|
case ansiterm.ANSI_SGR_FOREGROUND_DEFAULT:
|
||||||
|
windowsMode = (windowsMode &^ FOREGROUND_MASK) | (baseMode & FOREGROUND_MASK)
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_FOREGROUND_BLACK:
|
||||||
|
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK)
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_FOREGROUND_RED:
|
||||||
|
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_FOREGROUND_GREEN:
|
||||||
|
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_GREEN
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_FOREGROUND_YELLOW:
|
||||||
|
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_GREEN
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_FOREGROUND_BLUE:
|
||||||
|
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_BLUE
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_FOREGROUND_MAGENTA:
|
||||||
|
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_BLUE
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_FOREGROUND_CYAN:
|
||||||
|
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_GREEN | FOREGROUND_BLUE
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_FOREGROUND_WHITE:
|
||||||
|
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
|
||||||
|
|
||||||
|
// Background colors
|
||||||
|
case ansiterm.ANSI_SGR_BACKGROUND_DEFAULT:
|
||||||
|
// Black with no intensity
|
||||||
|
windowsMode = (windowsMode &^ BACKGROUND_MASK) | (baseMode & BACKGROUND_MASK)
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_BACKGROUND_BLACK:
|
||||||
|
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK)
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_BACKGROUND_RED:
|
||||||
|
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_BACKGROUND_GREEN:
|
||||||
|
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_GREEN
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_BACKGROUND_YELLOW:
|
||||||
|
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_GREEN
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_BACKGROUND_BLUE:
|
||||||
|
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_BLUE
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_BACKGROUND_MAGENTA:
|
||||||
|
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_BLUE
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_BACKGROUND_CYAN:
|
||||||
|
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_GREEN | BACKGROUND_BLUE
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_BACKGROUND_WHITE:
|
||||||
|
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
|
||||||
|
}
|
||||||
|
|
||||||
|
return windowsMode, inverted
|
||||||
|
}
|
||||||
|
|
||||||
|
// invertAttributes inverts the foreground and background colors of a Windows attributes value
|
||||||
|
func invertAttributes(windowsMode uint16) uint16 {
|
||||||
|
return (COMMON_LVB_MASK & windowsMode) | ((FOREGROUND_MASK & windowsMode) << 4) | ((BACKGROUND_MASK & windowsMode) >> 4)
|
||||||
|
}
|
||||||
+101
@@ -0,0 +1,101 @@
|
|||||||
|
// +build windows
|
||||||
|
|
||||||
|
package winterm
|
||||||
|
|
||||||
|
const (
|
||||||
|
horizontal = iota
|
||||||
|
vertical
|
||||||
|
)
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) getCursorWindow(info *CONSOLE_SCREEN_BUFFER_INFO) SMALL_RECT {
|
||||||
|
if h.originMode {
|
||||||
|
sr := h.effectiveSr(info.Window)
|
||||||
|
return SMALL_RECT{
|
||||||
|
Top: sr.top,
|
||||||
|
Bottom: sr.bottom,
|
||||||
|
Left: 0,
|
||||||
|
Right: info.Size.X - 1,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return SMALL_RECT{
|
||||||
|
Top: info.Window.Top,
|
||||||
|
Bottom: info.Window.Bottom,
|
||||||
|
Left: 0,
|
||||||
|
Right: info.Size.X - 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// setCursorPosition sets the cursor to the specified position, bounded to the screen size
|
||||||
|
func (h *windowsAnsiEventHandler) setCursorPosition(position COORD, window SMALL_RECT) error {
|
||||||
|
position.X = ensureInRange(position.X, window.Left, window.Right)
|
||||||
|
position.Y = ensureInRange(position.Y, window.Top, window.Bottom)
|
||||||
|
err := SetConsoleCursorPosition(h.fd, position)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("Cursor position set: (%d, %d)", position.X, position.Y)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) moveCursorVertical(param int) error {
|
||||||
|
return h.moveCursor(vertical, param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) moveCursorHorizontal(param int) error {
|
||||||
|
return h.moveCursor(horizontal, param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) moveCursor(moveMode int, param int) error {
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
position := info.CursorPosition
|
||||||
|
switch moveMode {
|
||||||
|
case horizontal:
|
||||||
|
position.X += int16(param)
|
||||||
|
case vertical:
|
||||||
|
position.Y += int16(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) moveCursorLine(param int) error {
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
position := info.CursorPosition
|
||||||
|
position.X = 0
|
||||||
|
position.Y += int16(param)
|
||||||
|
|
||||||
|
if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) moveCursorColumn(param int) error {
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
position := info.CursorPosition
|
||||||
|
position.X = int16(param) - 1
|
||||||
|
|
||||||
|
if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
+84
@@ -0,0 +1,84 @@
|
|||||||
|
// +build windows
|
||||||
|
|
||||||
|
package winterm
|
||||||
|
|
||||||
|
import "github.com/Azure/go-ansiterm"
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) clearRange(attributes uint16, fromCoord COORD, toCoord COORD) error {
|
||||||
|
// Ignore an invalid (negative area) request
|
||||||
|
if toCoord.Y < fromCoord.Y {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
var coordStart = COORD{}
|
||||||
|
var coordEnd = COORD{}
|
||||||
|
|
||||||
|
xCurrent, yCurrent := fromCoord.X, fromCoord.Y
|
||||||
|
xEnd, yEnd := toCoord.X, toCoord.Y
|
||||||
|
|
||||||
|
// Clear any partial initial line
|
||||||
|
if xCurrent > 0 {
|
||||||
|
coordStart.X, coordStart.Y = xCurrent, yCurrent
|
||||||
|
coordEnd.X, coordEnd.Y = xEnd, yCurrent
|
||||||
|
|
||||||
|
err = h.clearRect(attributes, coordStart, coordEnd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
xCurrent = 0
|
||||||
|
yCurrent += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear intervening rectangular section
|
||||||
|
if yCurrent < yEnd {
|
||||||
|
coordStart.X, coordStart.Y = xCurrent, yCurrent
|
||||||
|
coordEnd.X, coordEnd.Y = xEnd, yEnd-1
|
||||||
|
|
||||||
|
err = h.clearRect(attributes, coordStart, coordEnd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
xCurrent = 0
|
||||||
|
yCurrent = yEnd
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear remaining partial ending line
|
||||||
|
coordStart.X, coordStart.Y = xCurrent, yCurrent
|
||||||
|
coordEnd.X, coordEnd.Y = xEnd, yEnd
|
||||||
|
|
||||||
|
err = h.clearRect(attributes, coordStart, coordEnd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) clearRect(attributes uint16, fromCoord COORD, toCoord COORD) error {
|
||||||
|
region := SMALL_RECT{Top: fromCoord.Y, Left: fromCoord.X, Bottom: toCoord.Y, Right: toCoord.X}
|
||||||
|
width := toCoord.X - fromCoord.X + 1
|
||||||
|
height := toCoord.Y - fromCoord.Y + 1
|
||||||
|
size := uint32(width) * uint32(height)
|
||||||
|
|
||||||
|
if size <= 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer := make([]CHAR_INFO, size)
|
||||||
|
|
||||||
|
char := CHAR_INFO{ansiterm.FILL_CHARACTER, attributes}
|
||||||
|
for i := 0; i < int(size); i++ {
|
||||||
|
buffer[i] = char
|
||||||
|
}
|
||||||
|
|
||||||
|
err := WriteConsoleOutput(h.fd, buffer, COORD{X: width, Y: height}, COORD{X: 0, Y: 0}, ®ion)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
+118
@@ -0,0 +1,118 @@
|
|||||||
|
// +build windows
|
||||||
|
|
||||||
|
package winterm
|
||||||
|
|
||||||
|
// effectiveSr gets the current effective scroll region in buffer coordinates
|
||||||
|
func (h *windowsAnsiEventHandler) effectiveSr(window SMALL_RECT) scrollRegion {
|
||||||
|
top := addInRange(window.Top, h.sr.top, window.Top, window.Bottom)
|
||||||
|
bottom := addInRange(window.Top, h.sr.bottom, window.Top, window.Bottom)
|
||||||
|
if top >= bottom {
|
||||||
|
top = window.Top
|
||||||
|
bottom = window.Bottom
|
||||||
|
}
|
||||||
|
return scrollRegion{top: top, bottom: bottom}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) scrollUp(param int) error {
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
sr := h.effectiveSr(info.Window)
|
||||||
|
return h.scroll(param, sr, info)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) scrollDown(param int) error {
|
||||||
|
return h.scrollUp(-param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) deleteLines(param int) error {
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
start := info.CursorPosition.Y
|
||||||
|
sr := h.effectiveSr(info.Window)
|
||||||
|
// Lines cannot be inserted or deleted outside the scrolling region.
|
||||||
|
if start >= sr.top && start <= sr.bottom {
|
||||||
|
sr.top = start
|
||||||
|
return h.scroll(param, sr, info)
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) insertLines(param int) error {
|
||||||
|
return h.deleteLines(-param)
|
||||||
|
}
|
||||||
|
|
||||||
|
// scroll scrolls the provided scroll region by param lines. The scroll region is in buffer coordinates.
|
||||||
|
func (h *windowsAnsiEventHandler) scroll(param int, sr scrollRegion, info *CONSOLE_SCREEN_BUFFER_INFO) error {
|
||||||
|
h.logf("scroll: scrollTop: %d, scrollBottom: %d", sr.top, sr.bottom)
|
||||||
|
h.logf("scroll: windowTop: %d, windowBottom: %d", info.Window.Top, info.Window.Bottom)
|
||||||
|
|
||||||
|
// Copy from and clip to the scroll region (full buffer width)
|
||||||
|
scrollRect := SMALL_RECT{
|
||||||
|
Top: sr.top,
|
||||||
|
Bottom: sr.bottom,
|
||||||
|
Left: 0,
|
||||||
|
Right: info.Size.X - 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Origin to which area should be copied
|
||||||
|
destOrigin := COORD{
|
||||||
|
X: 0,
|
||||||
|
Y: sr.top - int16(param),
|
||||||
|
}
|
||||||
|
|
||||||
|
char := CHAR_INFO{
|
||||||
|
UnicodeChar: ' ',
|
||||||
|
Attributes: h.attributes,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) deleteCharacters(param int) error {
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return h.scrollLine(param, info.CursorPosition, info)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) insertCharacters(param int) error {
|
||||||
|
return h.deleteCharacters(-param)
|
||||||
|
}
|
||||||
|
|
||||||
|
// scrollLine scrolls a line horizontally starting at the provided position by a number of columns.
|
||||||
|
func (h *windowsAnsiEventHandler) scrollLine(columns int, position COORD, info *CONSOLE_SCREEN_BUFFER_INFO) error {
|
||||||
|
// Copy from and clip to the scroll region (full buffer width)
|
||||||
|
scrollRect := SMALL_RECT{
|
||||||
|
Top: position.Y,
|
||||||
|
Bottom: position.Y,
|
||||||
|
Left: position.X,
|
||||||
|
Right: info.Size.X - 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Origin to which area should be copied
|
||||||
|
destOrigin := COORD{
|
||||||
|
X: position.X - int16(columns),
|
||||||
|
Y: position.Y,
|
||||||
|
}
|
||||||
|
|
||||||
|
char := CHAR_INFO{
|
||||||
|
UnicodeChar: ' ',
|
||||||
|
Attributes: h.attributes,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
// +build windows
|
||||||
|
|
||||||
|
package winterm
|
||||||
|
|
||||||
|
// AddInRange increments a value by the passed quantity while ensuring the values
|
||||||
|
// always remain within the supplied min / max range.
|
||||||
|
func addInRange(n int16, increment int16, min int16, max int16) int16 {
|
||||||
|
return ensureInRange(n+increment, min, max)
|
||||||
|
}
|
||||||
+743
@@ -0,0 +1,743 @@
|
|||||||
|
// +build windows
|
||||||
|
|
||||||
|
package winterm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/Azure/go-ansiterm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type windowsAnsiEventHandler struct {
|
||||||
|
fd uintptr
|
||||||
|
file *os.File
|
||||||
|
infoReset *CONSOLE_SCREEN_BUFFER_INFO
|
||||||
|
sr scrollRegion
|
||||||
|
buffer bytes.Buffer
|
||||||
|
attributes uint16
|
||||||
|
inverted bool
|
||||||
|
wrapNext bool
|
||||||
|
drewMarginByte bool
|
||||||
|
originMode bool
|
||||||
|
marginByte byte
|
||||||
|
curInfo *CONSOLE_SCREEN_BUFFER_INFO
|
||||||
|
curPos COORD
|
||||||
|
logf func(string, ...interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
type Option func(*windowsAnsiEventHandler)
|
||||||
|
|
||||||
|
func WithLogf(f func(string, ...interface{})) Option {
|
||||||
|
return func(w *windowsAnsiEventHandler) {
|
||||||
|
w.logf = f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateWinEventHandler(fd uintptr, file *os.File, opts ...Option) ansiterm.AnsiEventHandler {
|
||||||
|
infoReset, err := GetConsoleScreenBufferInfo(fd)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
h := &windowsAnsiEventHandler{
|
||||||
|
fd: fd,
|
||||||
|
file: file,
|
||||||
|
infoReset: infoReset,
|
||||||
|
attributes: infoReset.Attributes,
|
||||||
|
}
|
||||||
|
for _, o := range opts {
|
||||||
|
o(h)
|
||||||
|
}
|
||||||
|
|
||||||
|
if isDebugEnv := os.Getenv(ansiterm.LogEnv); isDebugEnv == "1" {
|
||||||
|
logFile, _ := os.Create("winEventHandler.log")
|
||||||
|
logger := log.New(logFile, "", log.LstdFlags)
|
||||||
|
if h.logf != nil {
|
||||||
|
l := h.logf
|
||||||
|
h.logf = func(s string, v ...interface{}) {
|
||||||
|
l(s, v...)
|
||||||
|
logger.Printf(s, v...)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
h.logf = logger.Printf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if h.logf == nil {
|
||||||
|
h.logf = func(string, ...interface{}) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
type scrollRegion struct {
|
||||||
|
top int16
|
||||||
|
bottom int16
|
||||||
|
}
|
||||||
|
|
||||||
|
// simulateLF simulates a LF or CR+LF by scrolling if necessary to handle the
|
||||||
|
// current cursor position and scroll region settings, in which case it returns
|
||||||
|
// true. If no special handling is necessary, then it does nothing and returns
|
||||||
|
// false.
|
||||||
|
//
|
||||||
|
// In the false case, the caller should ensure that a carriage return
|
||||||
|
// and line feed are inserted or that the text is otherwise wrapped.
|
||||||
|
func (h *windowsAnsiEventHandler) simulateLF(includeCR bool) (bool, error) {
|
||||||
|
if h.wrapNext {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
h.clearWrap()
|
||||||
|
}
|
||||||
|
pos, info, err := h.getCurrentInfo()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
sr := h.effectiveSr(info.Window)
|
||||||
|
if pos.Y == sr.bottom {
|
||||||
|
// Scrolling is necessary. Let Windows automatically scroll if the scrolling region
|
||||||
|
// is the full window.
|
||||||
|
if sr.top == info.Window.Top && sr.bottom == info.Window.Bottom {
|
||||||
|
if includeCR {
|
||||||
|
pos.X = 0
|
||||||
|
h.updatePos(pos)
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// A custom scroll region is active. Scroll the window manually to simulate
|
||||||
|
// the LF.
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
h.logf("Simulating LF inside scroll region")
|
||||||
|
if err := h.scrollUp(1); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if includeCR {
|
||||||
|
pos.X = 0
|
||||||
|
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
|
||||||
|
} else if pos.Y < info.Window.Bottom {
|
||||||
|
// Let Windows handle the LF.
|
||||||
|
pos.Y++
|
||||||
|
if includeCR {
|
||||||
|
pos.X = 0
|
||||||
|
}
|
||||||
|
h.updatePos(pos)
|
||||||
|
return false, nil
|
||||||
|
} else {
|
||||||
|
// The cursor is at the bottom of the screen but outside the scroll
|
||||||
|
// region. Skip the LF.
|
||||||
|
h.logf("Simulating LF outside scroll region")
|
||||||
|
if includeCR {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
pos.X = 0
|
||||||
|
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// executeLF executes a LF without a CR.
|
||||||
|
func (h *windowsAnsiEventHandler) executeLF() error {
|
||||||
|
handled, err := h.simulateLF(false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !handled {
|
||||||
|
// Windows LF will reset the cursor column position. Write the LF
|
||||||
|
// and restore the cursor position.
|
||||||
|
pos, _, err := h.getCurrentInfo()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.buffer.WriteByte(ansiterm.ANSI_LINE_FEED)
|
||||||
|
if pos.X != 0 {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("Resetting cursor position for LF without CR")
|
||||||
|
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) Print(b byte) error {
|
||||||
|
if h.wrapNext {
|
||||||
|
h.buffer.WriteByte(h.marginByte)
|
||||||
|
h.clearWrap()
|
||||||
|
if _, err := h.simulateLF(true); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pos, info, err := h.getCurrentInfo()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if pos.X == info.Size.X-1 {
|
||||||
|
h.wrapNext = true
|
||||||
|
h.marginByte = b
|
||||||
|
} else {
|
||||||
|
pos.X++
|
||||||
|
h.updatePos(pos)
|
||||||
|
h.buffer.WriteByte(b)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) Execute(b byte) error {
|
||||||
|
switch b {
|
||||||
|
case ansiterm.ANSI_TAB:
|
||||||
|
h.logf("Execute(TAB)")
|
||||||
|
// Move to the next tab stop, but preserve auto-wrap if already set.
|
||||||
|
if !h.wrapNext {
|
||||||
|
pos, info, err := h.getCurrentInfo()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
pos.X = (pos.X + 8) - pos.X%8
|
||||||
|
if pos.X >= info.Size.X {
|
||||||
|
pos.X = info.Size.X - 1
|
||||||
|
}
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
case ansiterm.ANSI_BEL:
|
||||||
|
h.buffer.WriteByte(ansiterm.ANSI_BEL)
|
||||||
|
return nil
|
||||||
|
|
||||||
|
case ansiterm.ANSI_BACKSPACE:
|
||||||
|
if h.wrapNext {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.clearWrap()
|
||||||
|
}
|
||||||
|
pos, _, err := h.getCurrentInfo()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if pos.X > 0 {
|
||||||
|
pos.X--
|
||||||
|
h.updatePos(pos)
|
||||||
|
h.buffer.WriteByte(ansiterm.ANSI_BACKSPACE)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
case ansiterm.ANSI_VERTICAL_TAB, ansiterm.ANSI_FORM_FEED:
|
||||||
|
// Treat as true LF.
|
||||||
|
return h.executeLF()
|
||||||
|
|
||||||
|
case ansiterm.ANSI_LINE_FEED:
|
||||||
|
// Simulate a CR and LF for now since there is no way in go-ansiterm
|
||||||
|
// to tell if the LF should include CR (and more things break when it's
|
||||||
|
// missing than when it's incorrectly added).
|
||||||
|
handled, err := h.simulateLF(true)
|
||||||
|
if handled || err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return h.buffer.WriteByte(ansiterm.ANSI_LINE_FEED)
|
||||||
|
|
||||||
|
case ansiterm.ANSI_CARRIAGE_RETURN:
|
||||||
|
if h.wrapNext {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.clearWrap()
|
||||||
|
}
|
||||||
|
pos, _, err := h.getCurrentInfo()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if pos.X != 0 {
|
||||||
|
pos.X = 0
|
||||||
|
h.updatePos(pos)
|
||||||
|
h.buffer.WriteByte(ansiterm.ANSI_CARRIAGE_RETURN)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) CUU(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("CUU: [%v]", []string{strconv.Itoa(param)})
|
||||||
|
h.clearWrap()
|
||||||
|
return h.moveCursorVertical(-param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) CUD(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("CUD: [%v]", []string{strconv.Itoa(param)})
|
||||||
|
h.clearWrap()
|
||||||
|
return h.moveCursorVertical(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) CUF(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("CUF: [%v]", []string{strconv.Itoa(param)})
|
||||||
|
h.clearWrap()
|
||||||
|
return h.moveCursorHorizontal(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) CUB(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("CUB: [%v]", []string{strconv.Itoa(param)})
|
||||||
|
h.clearWrap()
|
||||||
|
return h.moveCursorHorizontal(-param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) CNL(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("CNL: [%v]", []string{strconv.Itoa(param)})
|
||||||
|
h.clearWrap()
|
||||||
|
return h.moveCursorLine(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) CPL(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("CPL: [%v]", []string{strconv.Itoa(param)})
|
||||||
|
h.clearWrap()
|
||||||
|
return h.moveCursorLine(-param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) CHA(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("CHA: [%v]", []string{strconv.Itoa(param)})
|
||||||
|
h.clearWrap()
|
||||||
|
return h.moveCursorColumn(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) VPA(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("VPA: [[%d]]", param)
|
||||||
|
h.clearWrap()
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
window := h.getCursorWindow(info)
|
||||||
|
position := info.CursorPosition
|
||||||
|
position.Y = window.Top + int16(param) - 1
|
||||||
|
return h.setCursorPosition(position, window)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) CUP(row int, col int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("CUP: [[%d %d]]", row, col)
|
||||||
|
h.clearWrap()
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
window := h.getCursorWindow(info)
|
||||||
|
position := COORD{window.Left + int16(col) - 1, window.Top + int16(row) - 1}
|
||||||
|
return h.setCursorPosition(position, window)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) HVP(row int, col int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("HVP: [[%d %d]]", row, col)
|
||||||
|
h.clearWrap()
|
||||||
|
return h.CUP(row, col)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) DECTCEM(visible bool) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("DECTCEM: [%v]", []string{strconv.FormatBool(visible)})
|
||||||
|
h.clearWrap()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) DECOM(enable bool) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("DECOM: [%v]", []string{strconv.FormatBool(enable)})
|
||||||
|
h.clearWrap()
|
||||||
|
h.originMode = enable
|
||||||
|
return h.CUP(1, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) DECCOLM(use132 bool) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("DECCOLM: [%v]", []string{strconv.FormatBool(use132)})
|
||||||
|
h.clearWrap()
|
||||||
|
if err := h.ED(2); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
targetWidth := int16(80)
|
||||||
|
if use132 {
|
||||||
|
targetWidth = 132
|
||||||
|
}
|
||||||
|
if info.Size.X < targetWidth {
|
||||||
|
if err := SetConsoleScreenBufferSize(h.fd, COORD{targetWidth, info.Size.Y}); err != nil {
|
||||||
|
h.logf("set buffer failed: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
window := info.Window
|
||||||
|
window.Left = 0
|
||||||
|
window.Right = targetWidth - 1
|
||||||
|
if err := SetConsoleWindowInfo(h.fd, true, window); err != nil {
|
||||||
|
h.logf("set window failed: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if info.Size.X > targetWidth {
|
||||||
|
if err := SetConsoleScreenBufferSize(h.fd, COORD{targetWidth, info.Size.Y}); err != nil {
|
||||||
|
h.logf("set buffer failed: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SetConsoleCursorPosition(h.fd, COORD{0, 0})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) ED(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("ED: [%v]", []string{strconv.Itoa(param)})
|
||||||
|
h.clearWrap()
|
||||||
|
|
||||||
|
// [J -- Erases from the cursor to the end of the screen, including the cursor position.
|
||||||
|
// [1J -- Erases from the beginning of the screen to the cursor, including the cursor position.
|
||||||
|
// [2J -- Erases the complete display. The cursor does not move.
|
||||||
|
// Notes:
|
||||||
|
// -- Clearing the entire buffer, versus just the Window, works best for Windows Consoles
|
||||||
|
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var start COORD
|
||||||
|
var end COORD
|
||||||
|
|
||||||
|
switch param {
|
||||||
|
case 0:
|
||||||
|
start = info.CursorPosition
|
||||||
|
end = COORD{info.Size.X - 1, info.Size.Y - 1}
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
start = COORD{0, 0}
|
||||||
|
end = info.CursorPosition
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
start = COORD{0, 0}
|
||||||
|
end = COORD{info.Size.X - 1, info.Size.Y - 1}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = h.clearRange(h.attributes, start, end)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the whole buffer was cleared, move the window to the top while preserving
|
||||||
|
// the window-relative cursor position.
|
||||||
|
if param == 2 {
|
||||||
|
pos := info.CursorPosition
|
||||||
|
window := info.Window
|
||||||
|
pos.Y -= window.Top
|
||||||
|
window.Bottom -= window.Top
|
||||||
|
window.Top = 0
|
||||||
|
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := SetConsoleWindowInfo(h.fd, true, window); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) EL(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("EL: [%v]", strconv.Itoa(param))
|
||||||
|
h.clearWrap()
|
||||||
|
|
||||||
|
// [K -- Erases from the cursor to the end of the line, including the cursor position.
|
||||||
|
// [1K -- Erases from the beginning of the line to the cursor, including the cursor position.
|
||||||
|
// [2K -- Erases the complete line.
|
||||||
|
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var start COORD
|
||||||
|
var end COORD
|
||||||
|
|
||||||
|
switch param {
|
||||||
|
case 0:
|
||||||
|
start = info.CursorPosition
|
||||||
|
end = COORD{info.Size.X, info.CursorPosition.Y}
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
start = COORD{0, info.CursorPosition.Y}
|
||||||
|
end = info.CursorPosition
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
start = COORD{0, info.CursorPosition.Y}
|
||||||
|
end = COORD{info.Size.X, info.CursorPosition.Y}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = h.clearRange(h.attributes, start, end)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) IL(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("IL: [%v]", strconv.Itoa(param))
|
||||||
|
h.clearWrap()
|
||||||
|
return h.insertLines(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) DL(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("DL: [%v]", strconv.Itoa(param))
|
||||||
|
h.clearWrap()
|
||||||
|
return h.deleteLines(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) ICH(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("ICH: [%v]", strconv.Itoa(param))
|
||||||
|
h.clearWrap()
|
||||||
|
return h.insertCharacters(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) DCH(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("DCH: [%v]", strconv.Itoa(param))
|
||||||
|
h.clearWrap()
|
||||||
|
return h.deleteCharacters(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) SGR(params []int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
strings := []string{}
|
||||||
|
for _, v := range params {
|
||||||
|
strings = append(strings, strconv.Itoa(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
h.logf("SGR: [%v]", strings)
|
||||||
|
|
||||||
|
if len(params) <= 0 {
|
||||||
|
h.attributes = h.infoReset.Attributes
|
||||||
|
h.inverted = false
|
||||||
|
} else {
|
||||||
|
for _, attr := range params {
|
||||||
|
|
||||||
|
if attr == ansiterm.ANSI_SGR_RESET {
|
||||||
|
h.attributes = h.infoReset.Attributes
|
||||||
|
h.inverted = false
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
h.attributes, h.inverted = collectAnsiIntoWindowsAttributes(h.attributes, h.inverted, h.infoReset.Attributes, int16(attr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
attributes := h.attributes
|
||||||
|
if h.inverted {
|
||||||
|
attributes = invertAttributes(attributes)
|
||||||
|
}
|
||||||
|
err := SetConsoleTextAttribute(h.fd, attributes)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) SU(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("SU: [%v]", []string{strconv.Itoa(param)})
|
||||||
|
h.clearWrap()
|
||||||
|
return h.scrollUp(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) SD(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("SD: [%v]", []string{strconv.Itoa(param)})
|
||||||
|
h.clearWrap()
|
||||||
|
return h.scrollDown(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) DA(params []string) error {
|
||||||
|
h.logf("DA: [%v]", params)
|
||||||
|
// DA cannot be implemented because it must send data on the VT100 input stream,
|
||||||
|
// which is not available to go-ansiterm.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) DECSTBM(top int, bottom int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("DECSTBM: [%d, %d]", top, bottom)
|
||||||
|
|
||||||
|
// Windows is 0 indexed, Linux is 1 indexed
|
||||||
|
h.sr.top = int16(top - 1)
|
||||||
|
h.sr.bottom = int16(bottom - 1)
|
||||||
|
|
||||||
|
// This command also moves the cursor to the origin.
|
||||||
|
h.clearWrap()
|
||||||
|
return h.CUP(1, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) RI() error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("RI: []")
|
||||||
|
h.clearWrap()
|
||||||
|
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
sr := h.effectiveSr(info.Window)
|
||||||
|
if info.CursorPosition.Y == sr.top {
|
||||||
|
return h.scrollDown(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return h.moveCursorVertical(-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) IND() error {
|
||||||
|
h.logf("IND: []")
|
||||||
|
return h.executeLF()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) Flush() error {
|
||||||
|
h.curInfo = nil
|
||||||
|
if h.buffer.Len() > 0 {
|
||||||
|
h.logf("Flush: [%s]", h.buffer.Bytes())
|
||||||
|
if _, err := h.buffer.WriteTo(h.file); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if h.wrapNext && !h.drewMarginByte {
|
||||||
|
h.logf("Flush: drawing margin byte '%c'", h.marginByte)
|
||||||
|
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
charInfo := []CHAR_INFO{{UnicodeChar: uint16(h.marginByte), Attributes: info.Attributes}}
|
||||||
|
size := COORD{1, 1}
|
||||||
|
position := COORD{0, 0}
|
||||||
|
region := SMALL_RECT{Left: info.CursorPosition.X, Top: info.CursorPosition.Y, Right: info.CursorPosition.X, Bottom: info.CursorPosition.Y}
|
||||||
|
if err := WriteConsoleOutput(h.fd, charInfo, size, position, ®ion); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.drewMarginByte = true
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// cacheConsoleInfo ensures that the current console screen information has been queried
|
||||||
|
// since the last call to Flush(). It must be called before accessing h.curInfo or h.curPos.
|
||||||
|
func (h *windowsAnsiEventHandler) getCurrentInfo() (COORD, *CONSOLE_SCREEN_BUFFER_INFO, error) {
|
||||||
|
if h.curInfo == nil {
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return COORD{}, nil, err
|
||||||
|
}
|
||||||
|
h.curInfo = info
|
||||||
|
h.curPos = info.CursorPosition
|
||||||
|
}
|
||||||
|
return h.curPos, h.curInfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) updatePos(pos COORD) {
|
||||||
|
if h.curInfo == nil {
|
||||||
|
panic("failed to call getCurrentInfo before calling updatePos")
|
||||||
|
}
|
||||||
|
h.curPos = pos
|
||||||
|
}
|
||||||
|
|
||||||
|
// clearWrap clears the state where the cursor is in the margin
|
||||||
|
// waiting for the next character before wrapping the line. This must
|
||||||
|
// be done before most operations that act on the cursor.
|
||||||
|
func (h *windowsAnsiEventHandler) clearWrap() {
|
||||||
|
h.wrapNext = false
|
||||||
|
h.drewMarginByte = false
|
||||||
|
}
|
||||||
+32
@@ -0,0 +1,32 @@
|
|||||||
|
# The standard Go .gitignore file follows. (Sourced from: github.com/github/gitignore/master/Go.gitignore)
|
||||||
|
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||||
|
*.o
|
||||||
|
*.a
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Folders
|
||||||
|
_obj
|
||||||
|
_test
|
||||||
|
.DS_Store
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
# Architecture specific extensions/prefixes
|
||||||
|
*.[568vq]
|
||||||
|
[568vq].out
|
||||||
|
|
||||||
|
*.cgo1.go
|
||||||
|
*.cgo2.c
|
||||||
|
_cgo_defun.c
|
||||||
|
_cgo_gotypes.go
|
||||||
|
_cgo_export.*
|
||||||
|
|
||||||
|
_testmain.go
|
||||||
|
|
||||||
|
*.exe
|
||||||
|
*.test
|
||||||
|
*.prof
|
||||||
|
|
||||||
|
# go-autorest specific
|
||||||
|
vendor/
|
||||||
|
autorest/azure/example/example
|
||||||
+1004
File diff suppressed because it is too large.
Load diff
+23
@@ -0,0 +1,23 @@
|
|||||||
|
DIR?=./autorest/
|
||||||
|
|
||||||
|
default: build
|
||||||
|
|
||||||
|
build: fmt
|
||||||
|
go install $(DIR)
|
||||||
|
|
||||||
|
test:
|
||||||
|
go test $(DIR) || exit 1
|
||||||
|
|
||||||
|
vet:
|
||||||
|
@echo "go vet ."
|
||||||
|
@go vet $(DIR)... ; if [ $$? -eq 1 ]; then \
|
||||||
|
echo ""; \
|
||||||
|
echo "Vet found suspicious constructs. Please check the reported constructs"; \
|
||||||
|
echo "and fix them if necessary before submitting the code for review."; \
|
||||||
|
exit 1; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
fmt:
|
||||||
|
gofmt -w $(DIR)
|
||||||
|
|
||||||
|
.PHONY: build test vet fmt
|
||||||
+324
@@ -0,0 +1,324 @@
|
|||||||
|
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||||
|
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:892e39e5c083d0943f1e80ab8351690f183c6a5ab24e1d280adcad424c26255e"
|
||||||
|
name = "contrib.go.opencensus.io/exporter/ocagent"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "a8a6f458bbc1d5042322ad1f9b65eeb0b69be9ea"
|
||||||
|
version = "v0.6.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:8f5acd4d4462b5136af644d25101f0968a7a94ee90fcb2059cec5b7cc42e0b20"
|
||||||
|
name = "github.com/census-instrumentation/opencensus-proto"
|
||||||
|
packages = [
|
||||||
|
"gen-go/agent/common/v1",
|
||||||
|
"gen-go/agent/metrics/v1",
|
||||||
|
"gen-go/agent/trace/v1",
|
||||||
|
"gen-go/metrics/v1",
|
||||||
|
"gen-go/resource/v1",
|
||||||
|
"gen-go/trace/v1",
|
||||||
|
]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "d89fa54de508111353cb0b06403c00569be780d8"
|
||||||
|
version = "v0.2.1"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec"
|
||||||
|
name = "github.com/davecgh/go-spew"
|
||||||
|
packages = ["spew"]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73"
|
||||||
|
version = "v1.1.1"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:76dc72490af7174349349838f2fe118996381b31ea83243812a97e5a0fd5ed55"
|
||||||
|
name = "github.com/dgrijalva/jwt-go"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "06ea1031745cb8b3dab3f6a236daf2b0aa468b7e"
|
||||||
|
version = "v3.2.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:cf0d2e435fd4ce45b789e93ef24b5f08e86be0e9807a16beb3694e2d8c9af965"
|
||||||
|
name = "github.com/dimchansky/utfbom"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "d2133a1ce379ef6fa992b0514a77146c60db9d1c"
|
||||||
|
version = "v1.1.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
digest = "1:b7cb6054d3dff43b38ad2e92492f220f57ae6087ee797dca298139776749ace8"
|
||||||
|
name = "github.com/golang/groupcache"
|
||||||
|
packages = ["lru"]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "611e8accdfc92c4187d399e95ce826046d4c8d73"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:e3839df32927e8d3403cd5aa7253d966e8ff80fc8f10e2e35d146461cd83fcfa"
|
||||||
|
name = "github.com/golang/protobuf"
|
||||||
|
packages = [
|
||||||
|
"descriptor",
|
||||||
|
"jsonpb",
|
||||||
|
"proto",
|
||||||
|
"protoc-gen-go/descriptor",
|
||||||
|
"ptypes",
|
||||||
|
"ptypes/any",
|
||||||
|
"ptypes/duration",
|
||||||
|
"ptypes/struct",
|
||||||
|
"ptypes/timestamp",
|
||||||
|
"ptypes/wrappers",
|
||||||
|
]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "6c65a5562fc06764971b7c5d05c76c75e84bdbf7"
|
||||||
|
version = "v1.3.2"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:c560cd79300fac84f124b96225181a637a70b60155919a3c36db50b7cca6b806"
|
||||||
|
name = "github.com/grpc-ecosystem/grpc-gateway"
|
||||||
|
packages = [
|
||||||
|
"internal",
|
||||||
|
"runtime",
|
||||||
|
"utilities",
|
||||||
|
]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "f7120437bb4f6c71f7f5076ad65a45310de2c009"
|
||||||
|
version = "v1.12.1"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:5d231480e1c64a726869bc4142d270184c419749d34f167646baa21008eb0a79"
|
||||||
|
name = "github.com/mitchellh/go-homedir"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "af06845cf3004701891bf4fdb884bfe4920b3727"
|
||||||
|
version = "v1.1.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:0028cb19b2e4c3112225cd871870f2d9cf49b9b4276531f03438a88e94be86fe"
|
||||||
|
name = "github.com/pmezard/go-difflib"
|
||||||
|
packages = ["difflib"]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
|
||||||
|
version = "v1.0.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:99d32780e5238c2621fff621123997c3e3cca96db8be13179013aea77dfab551"
|
||||||
|
name = "github.com/stretchr/testify"
|
||||||
|
packages = [
|
||||||
|
"assert",
|
||||||
|
"require",
|
||||||
|
]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "221dbe5ed46703ee255b1da0dec05086f5035f62"
|
||||||
|
version = "v1.4.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:7c5e00383399fe13de0b4b65c9fdde16275407ce8ac02d867eafeaa916edcc71"
|
||||||
|
name = "go.opencensus.io"
|
||||||
|
packages = [
|
||||||
|
".",
|
||||||
|
"internal",
|
||||||
|
"internal/tagencoding",
|
||||||
|
"metric/metricdata",
|
||||||
|
"metric/metricproducer",
|
||||||
|
"plugin/ocgrpc",
|
||||||
|
"plugin/ochttp",
|
||||||
|
"plugin/ochttp/propagation/b3",
|
||||||
|
"plugin/ochttp/propagation/tracecontext",
|
||||||
|
"resource",
|
||||||
|
"stats",
|
||||||
|
"stats/internal",
|
||||||
|
"stats/view",
|
||||||
|
"tag",
|
||||||
|
"trace",
|
||||||
|
"trace/internal",
|
||||||
|
"trace/propagation",
|
||||||
|
"trace/tracestate",
|
||||||
|
]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "aad2c527c5defcf89b5afab7f37274304195a6b2"
|
||||||
|
version = "v0.22.2"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
digest = "1:f604f5e2ee721b6757d962dfe7bab4f28aae50c456e39cfb2f3819762a44a6ae"
|
||||||
|
name = "golang.org/x/crypto"
|
||||||
|
packages = [
|
||||||
|
"pkcs12",
|
||||||
|
"pkcs12/internal/rc2",
|
||||||
|
]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "e9b2fee46413994441b28dfca259d911d963dfed"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
digest = "1:334b27eac455cb6567ea28cd424230b07b1a64334a2f861a8075ac26ce10af43"
|
||||||
|
name = "golang.org/x/lint"
|
||||||
|
packages = [
|
||||||
|
".",
|
||||||
|
"golint",
|
||||||
|
]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "fdd1cda4f05fd1fd86124f0ef9ce31a0b72c8448"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
digest = "1:257a75d024975428ab9192bfc334c3490882f8cb21322ea5784ca8eca000a910"
|
||||||
|
name = "golang.org/x/net"
|
||||||
|
packages = [
|
||||||
|
"http/httpguts",
|
||||||
|
"http2",
|
||||||
|
"http2/hpack",
|
||||||
|
"idna",
|
||||||
|
"internal/timeseries",
|
||||||
|
"trace",
|
||||||
|
]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "1ddd1de85cb0337b623b740a609d35817d516a8d"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
digest = "1:382bb5a7fb4034db3b6a2d19e5a4a6bcf52f4750530603c01ca18a172fa3089b"
|
||||||
|
name = "golang.org/x/sync"
|
||||||
|
packages = ["semaphore"]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "cd5d95a43a6e21273425c7ae415d3df9ea832eeb"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
digest = "1:4da420ceda5f68e8d748aa2169d0ed44ffadb1bbd6537cf778a49563104189b8"
|
||||||
|
name = "golang.org/x/sys"
|
||||||
|
packages = ["unix"]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "ce4227a45e2eb77e5c847278dcc6a626742e2945"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:8d8faad6b12a3a4c819a3f9618cb6ee1fa1cfc33253abeeea8b55336721e3405"
|
||||||
|
name = "golang.org/x/text"
|
||||||
|
packages = [
|
||||||
|
"collate",
|
||||||
|
"collate/build",
|
||||||
|
"internal/colltab",
|
||||||
|
"internal/gen",
|
||||||
|
"internal/language",
|
||||||
|
"internal/language/compact",
|
||||||
|
"internal/tag",
|
||||||
|
"internal/triegen",
|
||||||
|
"internal/ucd",
|
||||||
|
"language",
|
||||||
|
"secure/bidirule",
|
||||||
|
"transform",
|
||||||
|
"unicode/bidi",
|
||||||
|
"unicode/cldr",
|
||||||
|
"unicode/norm",
|
||||||
|
"unicode/rangetable",
|
||||||
|
]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "342b2e1fbaa52c93f31447ad2c6abc048c63e475"
|
||||||
|
version = "v0.3.2"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
digest = "1:4eb5ea8395fb60212dd58b92c9db80bab59d5e99c7435f9a6a0a528c373b60e7"
|
||||||
|
name = "golang.org/x/tools"
|
||||||
|
packages = [
|
||||||
|
"go/ast/astutil",
|
||||||
|
"go/gcexportdata",
|
||||||
|
"go/internal/gcimporter",
|
||||||
|
"go/types/typeutil",
|
||||||
|
]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "259af5ff87bdcd4abf2ecda8edc3f13f04f26a42"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:964bb30febc27fabfbec4759fa530c6ec35e77a7c85fed90b9317ea39a054877"
|
||||||
|
name = "google.golang.org/api"
|
||||||
|
packages = ["support/bundler"]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "8a410c21381766a810817fd6200fce8838ecb277"
|
||||||
|
version = "v0.14.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
digest = "1:a8d5c2c6e746b3485e36908ab2a9e3d77b86b81f8156d88403c7d2b462431dfd"
|
||||||
|
name = "google.golang.org/genproto"
|
||||||
|
packages = [
|
||||||
|
"googleapis/api/httpbody",
|
||||||
|
"googleapis/rpc/status",
|
||||||
|
"protobuf/field_mask",
|
||||||
|
]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "51378566eb590fa106d1025ea12835a4416dda84"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:b59ce3ddb11daeeccccc9cb3183b58ebf8e9a779f1c853308cd91612e817a301"
|
||||||
|
name = "google.golang.org/grpc"
|
||||||
|
packages = [
|
||||||
|
".",
|
||||||
|
"backoff",
|
||||||
|
"balancer",
|
||||||
|
"balancer/base",
|
||||||
|
"balancer/roundrobin",
|
||||||
|
"binarylog/grpc_binarylog_v1",
|
||||||
|
"codes",
|
||||||
|
"connectivity",
|
||||||
|
"credentials",
|
||||||
|
"credentials/internal",
|
||||||
|
"encoding",
|
||||||
|
"encoding/proto",
|
||||||
|
"grpclog",
|
||||||
|
"internal",
|
||||||
|
"internal/backoff",
|
||||||
|
"internal/balancerload",
|
||||||
|
"internal/binarylog",
|
||||||
|
"internal/buffer",
|
||||||
|
"internal/channelz",
|
||||||
|
"internal/envconfig",
|
||||||
|
"internal/grpcrand",
|
||||||
|
"internal/grpcsync",
|
||||||
|
"internal/resolver/dns",
|
||||||
|
"internal/resolver/passthrough",
|
||||||
|
"internal/syscall",
|
||||||
|
"internal/transport",
|
||||||
|
"keepalive",
|
||||||
|
"metadata",
|
||||||
|
"naming",
|
||||||
|
"peer",
|
||||||
|
"resolver",
|
||||||
|
"serviceconfig",
|
||||||
|
"stats",
|
||||||
|
"status",
|
||||||
|
"tap",
|
||||||
|
]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "1a3960e4bd028ac0cec0a2afd27d7d8e67c11514"
|
||||||
|
version = "v1.25.1"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
digest = "1:b75b3deb2bce8bc079e16bb2aecfe01eb80098f5650f9e93e5643ca8b7b73737"
|
||||||
|
name = "gopkg.in/yaml.v2"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "1f64d6156d11335c3f22d9330b0ad14fc1e789ce"
|
||||||
|
version = "v2.2.7"
|
||||||
|
|
||||||
|
[solve-meta]
|
||||||
|
analyzer-name = "dep"
|
||||||
|
analyzer-version = 1
|
||||||
|
input-imports = [
|
||||||
|
"contrib.go.opencensus.io/exporter/ocagent",
|
||||||
|
"github.com/dgrijalva/jwt-go",
|
||||||
|
"github.com/dimchansky/utfbom",
|
||||||
|
"github.com/mitchellh/go-homedir",
|
||||||
|
"github.com/stretchr/testify/require",
|
||||||
|
"go.opencensus.io/plugin/ochttp",
|
||||||
|
"go.opencensus.io/plugin/ochttp/propagation/tracecontext",
|
||||||
|
"go.opencensus.io/stats/view",
|
||||||
|
"go.opencensus.io/trace",
|
||||||
|
"golang.org/x/crypto/pkcs12",
|
||||||
|
"golang.org/x/lint/golint",
|
||||||
|
]
|
||||||
|
solver-name = "gps-cdcl"
|
||||||
|
solver-version = 1
|
||||||
+59
@@ -0,0 +1,59 @@
|
|||||||
|
# Gopkg.toml example
|
||||||
|
#
|
||||||
|
# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html
|
||||||
|
# for detailed Gopkg.toml documentation.
|
||||||
|
#
|
||||||
|
# required = ["github.com/user/thing/cmd/thing"]
|
||||||
|
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
||||||
|
#
|
||||||
|
# [[constraint]]
|
||||||
|
# name = "github.com/user/project"
|
||||||
|
# version = "1.0.0"
|
||||||
|
#
|
||||||
|
# [[constraint]]
|
||||||
|
# name = "github.com/user/project2"
|
||||||
|
# branch = "dev"
|
||||||
|
# source = "github.com/myfork/project2"
|
||||||
|
#
|
||||||
|
# [[override]]
|
||||||
|
# name = "github.com/x/y"
|
||||||
|
# version = "2.4.0"
|
||||||
|
#
|
||||||
|
# [prune]
|
||||||
|
# non-go = false
|
||||||
|
# go-tests = true
|
||||||
|
# unused-packages = true
|
||||||
|
|
||||||
|
required = ["golang.org/x/lint/golint"]
|
||||||
|
|
||||||
|
[prune]
|
||||||
|
go-tests = true
|
||||||
|
unused-packages = true
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "contrib.go.opencensus.io/exporter/ocagent"
|
||||||
|
version = "0.6.0"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/dgrijalva/jwt-go"
|
||||||
|
version = "3.2.0"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/dimchansky/utfbom"
|
||||||
|
version = "1.1.0"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/mitchellh/go-homedir"
|
||||||
|
version = "1.1.0"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/stretchr/testify"
|
||||||
|
version = "1.3.0"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "go.opencensus.io"
|
||||||
|
version = "0.22.0"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
branch = "master"
|
||||||
|
name = "golang.org/x/crypto"
|
||||||
+191
@@ -0,0 +1,191 @@
|
|||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
Copyright 2015 Microsoft Corporation
|
||||||
|
|
||||||
|
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.
|
||||||
+165
@@ -0,0 +1,165 @@
|
|||||||
|
# go-autorest
|
||||||
|
|
||||||
|
[](https://godoc.org/github.com/Azure/go-autorest/autorest)
|
||||||
|
[](https://dev.azure.com/azure-sdk/public/_build/latest?definitionId=625&branchName=master)
|
||||||
|
[](https://goreportcard.com/report/Azure/go-autorest)
|
||||||
|
|
||||||
|
Package go-autorest provides an HTTP request client for use with [Autorest](https://github.com/Azure/autorest.go)-generated API client packages.
|
||||||
|
|
||||||
|
An authentication client tested with Azure Active Directory (AAD) is also
|
||||||
|
provided in this repo in the package
|
||||||
|
`github.com/Azure/go-autorest/autorest/adal`. Despite its name, this package
|
||||||
|
is maintained only as part of the Azure Go SDK and is not related to other
|
||||||
|
"ADAL" libraries in [github.com/AzureAD](https://github.com/AzureAD).
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Package go-autorest implements an HTTP request pipeline suitable for use across
|
||||||
|
multiple goroutines and provides the shared routines used by packages generated
|
||||||
|
by [Autorest](https://github.com/Azure/autorest.go).
|
||||||
|
|
||||||
|
The package breaks sending and responding to HTTP requests into three phases: Preparing, Sending,
|
||||||
|
and Responding. A typical pattern is:
|
||||||
|
|
||||||
|
```go
|
||||||
|
req, err := Prepare(&http.Request{},
|
||||||
|
token.WithAuthorization())
|
||||||
|
|
||||||
|
resp, err := Send(req,
|
||||||
|
WithLogging(logger),
|
||||||
|
DoErrorIfStatusCode(http.StatusInternalServerError),
|
||||||
|
DoCloseIfError(),
|
||||||
|
DoRetryForAttempts(5, time.Second))
|
||||||
|
|
||||||
|
err = Respond(resp,
|
||||||
|
ByDiscardingBody(),
|
||||||
|
ByClosing())
|
||||||
|
```
|
||||||
|
|
||||||
|
Each phase relies on decorators to modify and / or manage processing. Decorators may first modify
|
||||||
|
and then pass the data along, pass the data first and then modify the result, or wrap themselves
|
||||||
|
around passing the data (such as a logger might do). Decorators run in the order provided. For
|
||||||
|
example, the following:
|
||||||
|
|
||||||
|
```go
|
||||||
|
req, err := Prepare(&http.Request{},
|
||||||
|
WithBaseURL("https://microsoft.com/"),
|
||||||
|
WithPath("a"),
|
||||||
|
WithPath("b"),
|
||||||
|
WithPath("c"))
|
||||||
|
```
|
||||||
|
|
||||||
|
will set the URL to:
|
||||||
|
|
||||||
|
```
|
||||||
|
https://microsoft.com/a/b/c
|
||||||
|
```
|
||||||
|
|
||||||
|
Preparers and Responders may be shared and re-used (assuming the underlying decorators support
|
||||||
|
sharing and re-use). Performant use is obtained by creating one or more Preparers and Responders
|
||||||
|
shared among multiple go-routines, and a single Sender shared among multiple sending go-routines,
|
||||||
|
all bound together by means of input / output channels.
|
||||||
|
|
||||||
|
Decorators hold their passed state within a closure (such as the path components in the example
|
||||||
|
above). Be careful to share Preparers and Responders only in a context where such held state
|
||||||
|
applies. For example, it may not make sense to share a Preparer that applies a query string from a
|
||||||
|
fixed set of values. Similarly, sharing a Responder that reads the response body into a passed
|
||||||
|
struct (e.g., `ByUnmarshallingJson`) is likely incorrect.
|
||||||
|
|
||||||
|
Errors raised by autorest objects and methods will conform to the `autorest.Error` interface.
|
||||||
|
|
||||||
|
See the included examples for more detail. For details on the suggested use of this package by
|
||||||
|
generated clients, see the Client described below.
|
||||||
|
|
||||||
|
## Helpers
|
||||||
|
|
||||||
|
### Handling Swagger Dates
|
||||||
|
|
||||||
|
The Swagger specification (https://swagger.io) that drives AutoRest
|
||||||
|
(https://github.com/Azure/autorest/) precisely defines two date forms: date and date-time. The
|
||||||
|
github.com/Azure/go-autorest/autorest/date package provides time.Time derivations to ensure correct
|
||||||
|
parsing and formatting.
|
||||||
|
|
||||||
|
### Handling Empty Values
|
||||||
|
|
||||||
|
In JSON, missing values have different semantics than empty values. This is especially true for
|
||||||
|
services using the HTTP PATCH verb. The JSON submitted with a PATCH request generally contains
|
||||||
|
only those values to modify. Missing values are to be left unchanged. Developers, then, require a
|
||||||
|
means to both specify an empty value and to leave the value out of the submitted JSON.
|
||||||
|
|
||||||
|
The Go JSON package (`encoding/json`) supports the `omitempty` tag. When specified, it omits
|
||||||
|
empty values from the rendered JSON. Since Go defines default values for all base types (such as ""
|
||||||
|
for string and 0 for int) and provides no means to mark a value as actually empty, the JSON package
|
||||||
|
treats default values as meaning empty, omitting them from the rendered JSON. This means that, using
|
||||||
|
the Go base types encoded through the default JSON package, it is not possible to create JSON to
|
||||||
|
clear a value at the server.
|
||||||
|
|
||||||
|
The workaround within the Go community is to use pointers to base types in lieu of base types within
|
||||||
|
structures that map to JSON. For example, instead of a value of type `string`, the workaround uses
|
||||||
|
`*string`. While this enables distinguishing empty values from those to be unchanged, creating
|
||||||
|
pointers to a base type (notably constant, in-line values) requires additional variables. This, for
|
||||||
|
example,
|
||||||
|
|
||||||
|
```go
|
||||||
|
s := struct {
|
||||||
|
S *string
|
||||||
|
}{ S: &"foo" }
|
||||||
|
```
|
||||||
|
fails, while, this
|
||||||
|
|
||||||
|
```go
|
||||||
|
v := "foo"
|
||||||
|
s := struct {
|
||||||
|
S *string
|
||||||
|
}{ S: &v }
|
||||||
|
```
|
||||||
|
succeeds.
|
||||||
|
|
||||||
|
To ease using pointers, the subpackage `to` contains helpers that convert to and from pointers for
|
||||||
|
Go base types which have Swagger analogs. It also provides a helper that converts between
|
||||||
|
`map[string]string` and `map[string]*string`, enabling the JSON to specify that the value
|
||||||
|
associated with a key should be cleared. With the helpers, the previous example becomes
|
||||||
|
|
||||||
|
```go
|
||||||
|
s := struct {
|
||||||
|
S *string
|
||||||
|
}{ S: to.StringPtr("foo") }
|
||||||
|
```
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go get github.com/Azure/go-autorest/autorest
|
||||||
|
go get github.com/Azure/go-autorest/autorest/azure
|
||||||
|
go get github.com/Azure/go-autorest/autorest/date
|
||||||
|
go get github.com/Azure/go-autorest/autorest/to
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using with Go Modules
|
||||||
|
In [v12.0.1](https://github.com/Azure/go-autorest/pull/386), this repository introduced the following modules.
|
||||||
|
|
||||||
|
- autorest/adal
|
||||||
|
- autorest/azure/auth
|
||||||
|
- autorest/azure/cli
|
||||||
|
- autorest/date
|
||||||
|
- autorest/mocks
|
||||||
|
- autorest/to
|
||||||
|
- autorest/validation
|
||||||
|
- autorest
|
||||||
|
- logger
|
||||||
|
- tracing
|
||||||
|
|
||||||
|
Tagging cumulative SDK releases as a whole (e.g. `v12.3.0`) is still enabled to support consumers of this repo that have not yet migrated to modules.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
See LICENSE file.
|
||||||
|
|
||||||
|
-----
|
||||||
|
|
||||||
|
This project has adopted the [Microsoft Open Source Code of
|
||||||
|
Conduct](https://opensource.microsoft.com/codeofconduct/). For more information
|
||||||
|
see the [Code of Conduct
|
||||||
|
FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact
|
||||||
|
[opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional
|
||||||
|
questions or comments.
|
||||||
+191
@@ -0,0 +1,191 @@
|
|||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
Copyright 2015 Microsoft Corporation
|
||||||
|
|
||||||
|
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.
|
||||||
+191
@@ -0,0 +1,191 @@
|
|||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
Copyright 2015 Microsoft Corporation
|
||||||
|
|
||||||
|
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.
|
||||||
+292
@@ -0,0 +1,292 @@
|
|||||||
|
# Azure Active Directory authentication for Go
|
||||||
|
|
||||||
|
This is a standalone package for authenticating with Azure Active
|
||||||
|
Directory from other Go libraries and applications, in particular the [Azure SDK
|
||||||
|
for Go](https://github.com/Azure/azure-sdk-for-go).
|
||||||
|
|
||||||
|
Note: Despite the package's name it is not related to other "ADAL" libraries
|
||||||
|
maintained in the [github.com/AzureAD](https://github.com/AzureAD) org. Issues
|
||||||
|
should be opened in [this repo's](https://github.com/Azure/go-autorest/issues)
|
||||||
|
or [the SDK's](https://github.com/Azure/azure-sdk-for-go/issues) issue
|
||||||
|
trackers.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go get -u github.com/Azure/go-autorest/autorest/adal
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
An Active Directory application is required in order to use this library. An application can be registered in the [Azure Portal](https://portal.azure.com/) by following these [guidelines](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-integrating-applications) or using the [Azure CLI](https://github.com/Azure/azure-cli).
|
||||||
|
|
||||||
|
### Register an Azure AD Application with secret
|
||||||
|
|
||||||
|
|
||||||
|
1. Register a new application with a `secret` credential
|
||||||
|
|
||||||
|
```
|
||||||
|
az ad app create \
|
||||||
|
--display-name example-app \
|
||||||
|
--homepage https://example-app/home \
|
||||||
|
--identifier-uris https://example-app/app \
|
||||||
|
--password secret
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Create a service principal using the `Application ID` from previous step
|
||||||
|
|
||||||
|
```
|
||||||
|
az ad sp create --id "Application ID"
|
||||||
|
```
|
||||||
|
|
||||||
|
* Replace `Application ID` with `appId` from step 1.
|
||||||
|
|
||||||
|
### Register an Azure AD Application with certificate
|
||||||
|
|
||||||
|
1. Create a private key
|
||||||
|
|
||||||
|
```
|
||||||
|
openssl genrsa -out "example-app.key" 2048
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Create the certificate
|
||||||
|
|
||||||
|
```
|
||||||
|
openssl req -new -key "example-app.key" -subj "/CN=example-app" -out "example-app.csr"
|
||||||
|
openssl x509 -req -in "example-app.csr" -signkey "example-app.key" -out "example-app.crt" -days 10000
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Create the PKCS12 version of the certificate containing also the private key
|
||||||
|
|
||||||
|
```
|
||||||
|
openssl pkcs12 -export -out "example-app.pfx" -inkey "example-app.key" -in "example-app.crt" -passout pass:
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Register a new application with the certificate content form `example-app.crt`
|
||||||
|
|
||||||
|
```
|
||||||
|
certificateContents="$(tail -n+2 "example-app.crt" | head -n-1)"
|
||||||
|
|
||||||
|
az ad app create \
|
||||||
|
--display-name example-app \
|
||||||
|
--homepage https://example-app/home \
|
||||||
|
--identifier-uris https://example-app/app \
|
||||||
|
--key-usage Verify --end-date 2018-01-01 \
|
||||||
|
--key-value "${certificateContents}"
|
||||||
|
```
|
||||||
|
|
||||||
|
5. Create a service principal using the `Application ID` from previous step
|
||||||
|
|
||||||
|
```
|
||||||
|
az ad sp create --id "APPLICATION_ID"
|
||||||
|
```
|
||||||
|
|
||||||
|
* Replace `APPLICATION_ID` with `appId` from step 4.
|
||||||
|
|
||||||
|
|
||||||
|
### Grant the necessary permissions
|
||||||
|
|
||||||
|
Azure relies on a Role-Based Access Control (RBAC) model to manage the access to resources at a fine-grained
|
||||||
|
level. There is a set of [pre-defined roles](https://docs.microsoft.com/en-us/azure/active-directory/role-based-access-built-in-roles)
|
||||||
|
which can be assigned to a service principal of an Azure AD application depending of your needs.
|
||||||
|
|
||||||
|
```
|
||||||
|
az role assignment create --assigner "SERVICE_PRINCIPAL_ID" --role "ROLE_NAME"
|
||||||
|
```
|
||||||
|
|
||||||
|
* Replace the `SERVICE_PRINCIPAL_ID` with the `appId` from previous step.
|
||||||
|
* Replace the `ROLE_NAME` with a role name of your choice.
|
||||||
|
|
||||||
|
It is also possible to define custom role definitions.
|
||||||
|
|
||||||
|
```
|
||||||
|
az role definition create --role-definition role-definition.json
|
||||||
|
```
|
||||||
|
|
||||||
|
* Check [custom roles](https://docs.microsoft.com/en-us/azure/active-directory/role-based-access-control-custom-roles) for more details regarding the content of `role-definition.json` file.
|
||||||
|
|
||||||
|
|
||||||
|
### Acquire Access Token
|
||||||
|
|
||||||
|
The common configuration used by all flows:
|
||||||
|
|
||||||
|
```Go
|
||||||
|
const activeDirectoryEndpoint = "https://login.microsoftonline.com/"
|
||||||
|
tenantID := "TENANT_ID"
|
||||||
|
oauthConfig, err := adal.NewOAuthConfig(activeDirectoryEndpoint, tenantID)
|
||||||
|
|
||||||
|
applicationID := "APPLICATION_ID"
|
||||||
|
|
||||||
|
callback := func(token adal.Token) error {
|
||||||
|
// This is called after the token is acquired
|
||||||
|
}
|
||||||
|
|
||||||
|
// The resource for which the token is acquired
|
||||||
|
resource := "https://management.core.windows.net/"
|
||||||
|
```
|
||||||
|
|
||||||
|
* Replace the `TENANT_ID` with your tenant ID.
|
||||||
|
* Replace the `APPLICATION_ID` with the value from previous section.
|
||||||
|
|
||||||
|
#### Client Credentials
|
||||||
|
|
||||||
|
```Go
|
||||||
|
applicationSecret := "APPLICATION_SECRET"
|
||||||
|
|
||||||
|
spt, err := adal.NewServicePrincipalToken(
|
||||||
|
*oauthConfig,
|
||||||
|
appliationID,
|
||||||
|
applicationSecret,
|
||||||
|
resource,
|
||||||
|
callbacks...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Acquire a new access token
|
||||||
|
err = spt.Refresh()
|
||||||
|
if (err == nil) {
|
||||||
|
token := spt.Token
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
* Replace the `APPLICATION_SECRET` with the `password` value from previous section.
|
||||||
|
|
||||||
|
#### Client Certificate
|
||||||
|
|
||||||
|
```Go
|
||||||
|
certificatePath := "./example-app.pfx"
|
||||||
|
|
||||||
|
certData, err := ioutil.ReadFile(certificatePath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to read the certificate file (%s): %v", certificatePath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the certificate and private key from pfx file
|
||||||
|
certificate, rsaPrivateKey, err := decodePkcs12(certData, "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to decode pkcs12 certificate while creating spt: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
spt, err := adal.NewServicePrincipalTokenFromCertificate(
|
||||||
|
*oauthConfig,
|
||||||
|
applicationID,
|
||||||
|
certificate,
|
||||||
|
rsaPrivateKey,
|
||||||
|
resource,
|
||||||
|
callbacks...)
|
||||||
|
|
||||||
|
// Acquire a new access token
|
||||||
|
err = spt.Refresh()
|
||||||
|
if (err == nil) {
|
||||||
|
token := spt.Token
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
* Update the certificate path to point to the example-app.pfx file which was created in previous section.
|
||||||
|
|
||||||
|
|
||||||
|
#### Device Code
|
||||||
|
|
||||||
|
```Go
|
||||||
|
oauthClient := &http.Client{}
|
||||||
|
|
||||||
|
// Acquire the device code
|
||||||
|
deviceCode, err := adal.InitiateDeviceAuth(
|
||||||
|
oauthClient,
|
||||||
|
*oauthConfig,
|
||||||
|
applicationID,
|
||||||
|
resource)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Failed to start device auth flow: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display the authentication message
|
||||||
|
fmt.Println(*deviceCode.Message)
|
||||||
|
|
||||||
|
// Wait here until the user is authenticated
|
||||||
|
token, err := adal.WaitForUserCompletion(oauthClient, deviceCode)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Failed to finish device auth flow: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
spt, err := adal.NewServicePrincipalTokenFromManualToken(
|
||||||
|
*oauthConfig,
|
||||||
|
applicationID,
|
||||||
|
resource,
|
||||||
|
*token,
|
||||||
|
callbacks...)
|
||||||
|
|
||||||
|
if (err == nil) {
|
||||||
|
token := spt.Token
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Username password authenticate
|
||||||
|
|
||||||
|
```Go
|
||||||
|
spt, err := adal.NewServicePrincipalTokenFromUsernamePassword(
|
||||||
|
*oauthConfig,
|
||||||
|
applicationID,
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
resource,
|
||||||
|
callbacks...)
|
||||||
|
|
||||||
|
if (err == nil) {
|
||||||
|
token := spt.Token
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Authorization code authenticate
|
||||||
|
|
||||||
|
``` Go
|
||||||
|
spt, err := adal.NewServicePrincipalTokenFromAuthorizationCode(
|
||||||
|
*oauthConfig,
|
||||||
|
applicationID,
|
||||||
|
clientSecret,
|
||||||
|
authorizationCode,
|
||||||
|
redirectURI,
|
||||||
|
resource,
|
||||||
|
callbacks...)
|
||||||
|
|
||||||
|
err = spt.Refresh()
|
||||||
|
if (err == nil) {
|
||||||
|
token := spt.Token
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Command Line Tool
|
||||||
|
|
||||||
|
A command line tool is available in `cmd/adal.go` that can acquire a token for a given resource. It supports all flows mentioned above.
|
||||||
|
|
||||||
|
```
|
||||||
|
adal -h
|
||||||
|
|
||||||
|
Usage of ./adal:
|
||||||
|
-applicationId string
|
||||||
|
application id
|
||||||
|
-certificatePath string
|
||||||
|
path to pk12/PFC application certificate
|
||||||
|
-mode string
|
||||||
|
authentication mode (device, secret, cert, refresh) (default "device")
|
||||||
|
-resource string
|
||||||
|
resource for which the token is requested
|
||||||
|
-secret string
|
||||||
|
application secret
|
||||||
|
-tenantId string
|
||||||
|
tenant id
|
||||||
|
-tokenCachePath string
|
||||||
|
location of oath token cache (default "/home/cgc/.adal/accessToken.json")
|
||||||
|
```
|
||||||
|
|
||||||
|
Example acquire a token for `https://management.core.windows.net/` using device code flow:
|
||||||
|
|
||||||
|
```
|
||||||
|
adal -mode device \
|
||||||
|
-applicationId "APPLICATION_ID" \
|
||||||
|
-tenantId "TENANT_ID" \
|
||||||
|
-resource https://management.core.windows.net/
|
||||||
|
|
||||||
|
```
|
||||||
+151
@@ -0,0 +1,151 @@
|
|||||||
|
package adal
|
||||||
|
|
||||||
|
// Copyright 2017 Microsoft Corporation
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
activeDirectoryEndpointTemplate = "%s/oauth2/%s%s"
|
||||||
|
)
|
||||||
|
|
||||||
|
// OAuthConfig represents the endpoints needed
|
||||||
|
// in OAuth operations
|
||||||
|
type OAuthConfig struct {
|
||||||
|
AuthorityEndpoint url.URL `json:"authorityEndpoint"`
|
||||||
|
AuthorizeEndpoint url.URL `json:"authorizeEndpoint"`
|
||||||
|
TokenEndpoint url.URL `json:"tokenEndpoint"`
|
||||||
|
DeviceCodeEndpoint url.URL `json:"deviceCodeEndpoint"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsZero returns true if the OAuthConfig object is zero-initialized.
|
||||||
|
func (oac OAuthConfig) IsZero() bool {
|
||||||
|
return oac == OAuthConfig{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateStringParam(param, name string) error {
|
||||||
|
if len(param) == 0 {
|
||||||
|
return fmt.Errorf("parameter '" + name + "' cannot be empty")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewOAuthConfig returns an OAuthConfig with tenant specific urls
|
||||||
|
func NewOAuthConfig(activeDirectoryEndpoint, tenantID string) (*OAuthConfig, error) {
|
||||||
|
apiVer := "1.0"
|
||||||
|
return NewOAuthConfigWithAPIVersion(activeDirectoryEndpoint, tenantID, &apiVer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewOAuthConfigWithAPIVersion returns an OAuthConfig with tenant specific urls.
|
||||||
|
// If apiVersion is not nil the "api-version" query parameter will be appended to the endpoint URLs with the specified value.
|
||||||
|
func NewOAuthConfigWithAPIVersion(activeDirectoryEndpoint, tenantID string, apiVersion *string) (*OAuthConfig, error) {
|
||||||
|
if err := validateStringParam(activeDirectoryEndpoint, "activeDirectoryEndpoint"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
api := ""
|
||||||
|
// it's legal for tenantID to be empty so don't validate it
|
||||||
|
if apiVersion != nil {
|
||||||
|
if err := validateStringParam(*apiVersion, "apiVersion"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
api = fmt.Sprintf("?api-version=%s", *apiVersion)
|
||||||
|
}
|
||||||
|
u, err := url.Parse(activeDirectoryEndpoint)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
authorityURL, err := u.Parse(tenantID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
authorizeURL, err := u.Parse(fmt.Sprintf(activeDirectoryEndpointTemplate, tenantID, "authorize", api))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
tokenURL, err := u.Parse(fmt.Sprintf(activeDirectoryEndpointTemplate, tenantID, "token", api))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
deviceCodeURL, err := u.Parse(fmt.Sprintf(activeDirectoryEndpointTemplate, tenantID, "devicecode", api))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &OAuthConfig{
|
||||||
|
AuthorityEndpoint: *authorityURL,
|
||||||
|
AuthorizeEndpoint: *authorizeURL,
|
||||||
|
TokenEndpoint: *tokenURL,
|
||||||
|
DeviceCodeEndpoint: *deviceCodeURL,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MultiTenantOAuthConfig provides endpoints for primary and aulixiary tenant IDs.
|
||||||
|
type MultiTenantOAuthConfig interface {
|
||||||
|
PrimaryTenant() *OAuthConfig
|
||||||
|
AuxiliaryTenants() []*OAuthConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
// OAuthOptions contains optional OAuthConfig creation arguments.
|
||||||
|
type OAuthOptions struct {
|
||||||
|
APIVersion string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c OAuthOptions) apiVersion() string {
|
||||||
|
if c.APIVersion != "" {
|
||||||
|
return fmt.Sprintf("?api-version=%s", c.APIVersion)
|
||||||
|
}
|
||||||
|
return "1.0"
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMultiTenantOAuthConfig creates an object that support multitenant OAuth configuration.
|
||||||
|
// See https://docs.microsoft.com/en-us/azure/azure-resource-manager/authenticate-multi-tenant for more information.
|
||||||
|
func NewMultiTenantOAuthConfig(activeDirectoryEndpoint, primaryTenantID string, auxiliaryTenantIDs []string, options OAuthOptions) (MultiTenantOAuthConfig, error) {
|
||||||
|
if len(auxiliaryTenantIDs) == 0 || len(auxiliaryTenantIDs) > 3 {
|
||||||
|
return nil, errors.New("must specify one to three auxiliary tenants")
|
||||||
|
}
|
||||||
|
mtCfg := multiTenantOAuthConfig{
|
||||||
|
cfgs: make([]*OAuthConfig, len(auxiliaryTenantIDs)+1),
|
||||||
|
}
|
||||||
|
apiVer := options.apiVersion()
|
||||||
|
pri, err := NewOAuthConfigWithAPIVersion(activeDirectoryEndpoint, primaryTenantID, &apiVer)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create OAuthConfig for primary tenant: %v", err)
|
||||||
|
}
|
||||||
|
mtCfg.cfgs[0] = pri
|
||||||
|
for i := range auxiliaryTenantIDs {
|
||||||
|
aux, err := NewOAuthConfig(activeDirectoryEndpoint, auxiliaryTenantIDs[i])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create OAuthConfig for tenant '%s': %v", auxiliaryTenantIDs[i], err)
|
||||||
|
}
|
||||||
|
mtCfg.cfgs[i+1] = aux
|
||||||
|
}
|
||||||
|
return mtCfg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type multiTenantOAuthConfig struct {
|
||||||
|
// first config in the slice is the primary tenant
|
||||||
|
cfgs []*OAuthConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m multiTenantOAuthConfig) PrimaryTenant() *OAuthConfig {
|
||||||
|
return m.cfgs[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m multiTenantOAuthConfig) AuxiliaryTenants() []*OAuthConfig {
|
||||||
|
return m.cfgs[1:]
|
||||||
|
}
|
||||||
Loaded 100 of 4711 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user