Merge pull request #20326 from hashicorp/vendor-grpc-go-bump

vendor: Bump google.golang.org/grpc & cloud.google.com/go & oauth2
This commit is contained in:
Radek Simko 2019-02-21 07:29:12 +00:00 committed by GitHub
commit 4ab701620e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
246 changed files with 45178 additions and 13295 deletions

15
go.mod
View File

@ -1,7 +1,7 @@
module github.com/hashicorp/terraform module github.com/hashicorp/terraform
require ( require (
cloud.google.com/go v0.15.0 cloud.google.com/go v0.36.0
github.com/Azure/azure-sdk-for-go v21.3.0+incompatible github.com/Azure/azure-sdk-for-go v21.3.0+incompatible
github.com/Azure/go-autorest v10.15.4+incompatible github.com/Azure/go-autorest v10.15.4+incompatible
github.com/Azure/go-ntlmssp v0.0.0-20170803034930-c92175d54006 // indirect github.com/Azure/go-ntlmssp v0.0.0-20170803034930-c92175d54006 // indirect
@ -28,25 +28,20 @@ require (
github.com/coreos/bbolt v1.3.0 // indirect github.com/coreos/bbolt v1.3.0 // indirect
github.com/coreos/etcd v3.3.10+incompatible github.com/coreos/etcd v3.3.10+incompatible
github.com/coreos/go-semver v0.2.0 // indirect github.com/coreos/go-semver v0.2.0 // indirect
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d // indirect
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f // indirect github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f // indirect
github.com/davecgh/go-spew v1.1.1 github.com/davecgh/go-spew v1.1.1
github.com/dnaeon/go-vcr v0.0.0-20180920040454-5637cf3d8a31 // indirect github.com/dnaeon/go-vcr v0.0.0-20180920040454-5637cf3d8a31 // indirect
github.com/dylanmei/iso8601 v0.1.0 // indirect github.com/dylanmei/iso8601 v0.1.0 // indirect
github.com/dylanmei/winrmtest v0.0.0-20170819153634-c2fbb09e6c08 github.com/dylanmei/winrmtest v0.0.0-20170819153634-c2fbb09e6c08
github.com/ghodss/yaml v1.0.0 // indirect
github.com/go-test/deep v1.0.1 github.com/go-test/deep v1.0.1
github.com/gogo/protobuf v1.2.0 // indirect github.com/gogo/protobuf v1.2.0 // indirect
github.com/golang/groupcache v0.0.0-20180513044358-24b0969c4cb7 // indirect github.com/golang/groupcache v0.0.0-20180513044358-24b0969c4cb7 // indirect
github.com/golang/mock v1.2.0 github.com/golang/mock v1.2.0
github.com/golang/protobuf v1.2.0 github.com/golang/protobuf v1.2.0
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db // indirect github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db // indirect
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c // indirect
github.com/google/go-cmp v0.2.0 github.com/google/go-cmp v0.2.0
github.com/googleapis/gax-go v0.0.0-20161107002406-da06d194a00e // indirect
github.com/gophercloud/gophercloud v0.0.0-20190208042652-bc37892e1968 github.com/gophercloud/gophercloud v0.0.0-20190208042652-bc37892e1968
github.com/gophercloud/utils v0.0.0-20190128072930-fbb6ab446f01 // indirect github.com/gophercloud/utils v0.0.0-20190128072930-fbb6ab446f01 // indirect
github.com/gopherjs/gopherjs v0.0.0-20181004151105-1babbf986f6f // indirect
github.com/gorilla/websocket v1.4.0 // indirect github.com/gorilla/websocket v1.4.0 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 // indirect
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
@ -125,16 +120,14 @@ require (
github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18 // indirect github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18 // indirect
github.com/xlab/treeprint v0.0.0-20161029104018-1d6e34225557 github.com/xlab/treeprint v0.0.0-20161029104018-1d6e34225557
github.com/zclconf/go-cty v0.0.0-20190201220620-4ca19710f056 github.com/zclconf/go-cty v0.0.0-20190201220620-4ca19710f056
go.opencensus.io v0.17.0 // indirect
go.uber.org/atomic v1.3.2 // indirect go.uber.org/atomic v1.3.2 // indirect
go.uber.org/multierr v1.1.0 // indirect go.uber.org/multierr v1.1.0 // indirect
go.uber.org/zap v1.9.1 // indirect go.uber.org/zap v1.9.1 // indirect
golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85 golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd golang.org/x/net v0.0.0-20190213061140-3a22650c66bd
golang.org/x/oauth2 v0.0.0-20181003184128-c57b0facaced golang.org/x/oauth2 v0.0.0-20190220154721-9b3c75971fc9
google.golang.org/api v0.0.0-20181015145326-625cd1887957 google.golang.org/api v0.1.0
google.golang.org/appengine v1.3.0 // indirect google.golang.org/grpc v1.18.0
google.golang.org/grpc v1.14.0
gopkg.in/vmihailenco/msgpack.v2 v2.9.1 // indirect gopkg.in/vmihailenco/msgpack.v2 v2.9.1 // indirect
labix.org/v2/mgo v0.0.0-20140701140051-000000000287 // indirect labix.org/v2/mgo v0.0.0-20140701140051-000000000287 // indirect
launchpad.net/gocheck v0.0.0-20140225173054-000000000087 // indirect launchpad.net/gocheck v0.0.0-20140225173054-000000000087 // indirect

123
go.sum
View File

@ -1,5 +1,13 @@
cloud.google.com/go v0.15.0 h1:/e2wXYguItvFu4fJCvhMRPIwwrimuUxI+aCVx/ahLjg= cloud.google.com/go v0.26.0 h1:e0WKqKTd5BnrG8aKH3J3h+QvEIQtSUcf2n5UZ5ZgLtQ=
cloud.google.com/go v0.15.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.31.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.36.0 h1:+aCSj7tOo2LODWVEuZDZeGCckdt6MlSF+X/rB3wUiS8=
cloud.google.com/go v0.36.0/go.mod h1:RUoy9p/M4ge0HzT8L+SDZ8jg+Q6fth0CiBuhFJpSV40=
dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU=
dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU=
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
github.com/Azure/azure-sdk-for-go v21.3.0+incompatible h1:YFvAka2WKAl2xnJkYV1e1b7E2z88AgFszDzWU18ejMY= github.com/Azure/azure-sdk-for-go v21.3.0+incompatible h1:YFvAka2WKAl2xnJkYV1e1b7E2z88AgFszDzWU18ejMY=
github.com/Azure/azure-sdk-for-go v21.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v21.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
@ -7,6 +15,7 @@ github.com/Azure/go-autorest v10.15.4+incompatible h1:q+DRrRdbCnkY7f2WxQBx58TwCG
github.com/Azure/go-autorest v10.15.4+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest v10.15.4+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-ntlmssp v0.0.0-20170803034930-c92175d54006 h1:dVyNL14dq1500JomYVzJTVi0XEcZFCYwwiNpDeCfoes= github.com/Azure/go-ntlmssp v0.0.0-20170803034930-c92175d54006 h1:dVyNL14dq1500JomYVzJTVi0XEcZFCYwwiNpDeCfoes=
github.com/Azure/go-ntlmssp v0.0.0-20170803034930-c92175d54006/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/Azure/go-ntlmssp v0.0.0-20170803034930-c92175d54006/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/ChrisTrenkamp/goxpath v0.0.0-20170625215350-4fe035839290 h1:K9I21XUHNbYD3GNMmJBN0UKJCpdP+glftwNZ7Bo8kqY= github.com/ChrisTrenkamp/goxpath v0.0.0-20170625215350-4fe035839290 h1:K9I21XUHNbYD3GNMmJBN0UKJCpdP+glftwNZ7Bo8kqY=
github.com/ChrisTrenkamp/goxpath v0.0.0-20170625215350-4fe035839290/go.mod h1:nuWgzSkT5PnyOd+272uUmV0dnAnAn42Mk7PiQC5VzN4= github.com/ChrisTrenkamp/goxpath v0.0.0-20170625215350-4fe035839290/go.mod h1:nuWgzSkT5PnyOd+272uUmV0dnAnAn42Mk7PiQC5VzN4=
github.com/Unknwon/com v0.0.0-20151008135407-28b053d5a292 h1:tuQ7w+my8a8mkwN7x2TSd7OzTjkZ7rAeSyH4xncuAMI= github.com/Unknwon/com v0.0.0-20151008135407-28b053d5a292 h1:tuQ7w+my8a8mkwN7x2TSd7OzTjkZ7rAeSyH4xncuAMI=
@ -17,6 +26,7 @@ github.com/agext/levenshtein v1.2.1 h1:QmvMAjj2aEICytGiWzmxoE0x2KZvE0fvmqMOfy2tj
github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
github.com/agl/ed25519 v0.0.0-20150830182803-278e1ec8e8a6 h1:LoeFxdq5zUCBQPhbQKE6zvoGwHMxCBlqwbH9+9kHoHA= github.com/agl/ed25519 v0.0.0-20150830182803-278e1ec8e8a6 h1:LoeFxdq5zUCBQPhbQKE6zvoGwHMxCBlqwbH9+9kHoHA=
github.com/agl/ed25519 v0.0.0-20150830182803-278e1ec8e8a6/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0= github.com/agl/ed25519 v0.0.0-20150830182803-278e1ec8e8a6/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/antchfx/xpath v0.0.0-20170728053731-b5c552e1acbd h1:S3Fr6QnkpW9VRjiEY4psQHhhbbahASuNVj52YIce7lI= github.com/antchfx/xpath v0.0.0-20170728053731-b5c552e1acbd h1:S3Fr6QnkpW9VRjiEY4psQHhhbbahASuNVj52YIce7lI=
github.com/antchfx/xpath v0.0.0-20170728053731-b5c552e1acbd/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk= github.com/antchfx/xpath v0.0.0-20170728053731-b5c552e1acbd/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk=
github.com/antchfx/xquery v0.0.0-20170730121040-eb8c3c172607 h1:BFFG6KP8ASFBg2ptWsJn8p8RDufBjBDKIxLU7BTYGOM= github.com/antchfx/xquery v0.0.0-20170730121040-eb8c3c172607 h1:BFFG6KP8ASFBg2ptWsJn8p8RDufBjBDKIxLU7BTYGOM=
@ -45,6 +55,7 @@ github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdn
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4= github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4=
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
github.com/bsm/go-vlq v0.0.0-20150828105119-ec6e8d4f5f4e/go.mod h1:N+BjUcTjSxc2mtRGSCPsat1kze3CUtvJN3/jTXlp29k= github.com/bsm/go-vlq v0.0.0-20150828105119-ec6e8d4f5f4e/go.mod h1:N+BjUcTjSxc2mtRGSCPsat1kze3CUtvJN3/jTXlp29k=
github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE= github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
@ -52,6 +63,7 @@ github.com/chzyer/readline v0.0.0-20161106042343-c914be64f07d h1:aG5FcWiZTOhPQzY
github.com/chzyer/readline v0.0.0-20161106042343-c914be64f07d/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/readline v0.0.0-20161106042343-c914be64f07d/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 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/coreos/bbolt v1.3.0 h1:HIgH5xUWXT914HCI671AxuTTqjj64UOFr7pHn48LUTI= github.com/coreos/bbolt v1.3.0 h1:HIgH5xUWXT914HCI671AxuTTqjj64UOFr7pHn48LUTI=
github.com/coreos/bbolt v1.3.0/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/bbolt v1.3.0/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible h1:jFneRYjIvLMLhDLCzuTuU4rSJUjRplcJQ7pD7MnhC04= github.com/coreos/etcd v3.3.10+incompatible h1:jFneRYjIvLMLhDLCzuTuU4rSJUjRplcJQ7pD7MnhC04=
@ -71,21 +83,27 @@ github.com/dimchansky/utfbom v1.0.0 h1:fGC2kkf4qOoKqZ4q7iIh+Vef4ubC1c38UDsEyZynZ
github.com/dimchansky/utfbom v1.0.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= github.com/dimchansky/utfbom v1.0.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
github.com/dnaeon/go-vcr v0.0.0-20180920040454-5637cf3d8a31 h1:Dzuw9GtbmllUqEcoHfScT9YpKFUssSiZ5PgZkIGf/YQ= github.com/dnaeon/go-vcr v0.0.0-20180920040454-5637cf3d8a31 h1:Dzuw9GtbmllUqEcoHfScT9YpKFUssSiZ5PgZkIGf/YQ=
github.com/dnaeon/go-vcr v0.0.0-20180920040454-5637cf3d8a31/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/dnaeon/go-vcr v0.0.0-20180920040454-5637cf3d8a31/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dylanmei/iso8601 v0.1.0 h1:812NGQDBcqquTfH5Yeo7lwR0nzx/cKdsmf3qMjPURUI= github.com/dylanmei/iso8601 v0.1.0 h1:812NGQDBcqquTfH5Yeo7lwR0nzx/cKdsmf3qMjPURUI=
github.com/dylanmei/iso8601 v0.1.0/go.mod h1:w9KhXSgIyROl1DefbMYIE7UVSIvELTbMrCfx+QkYnoQ= github.com/dylanmei/iso8601 v0.1.0/go.mod h1:w9KhXSgIyROl1DefbMYIE7UVSIvELTbMrCfx+QkYnoQ=
github.com/dylanmei/winrmtest v0.0.0-20170819153634-c2fbb09e6c08 h1:0bp6/GrNOrTDtSXe9YYGCwf8jp5Fb/b+4a6MTRm4qzY= github.com/dylanmei/winrmtest v0.0.0-20170819153634-c2fbb09e6c08 h1:0bp6/GrNOrTDtSXe9YYGCwf8jp5Fb/b+4a6MTRm4qzY=
github.com/dylanmei/winrmtest v0.0.0-20170819153634-c2fbb09e6c08/go.mod h1:VBVDFSBXCIW8JaHQpI8lldSKfYaLMzP9oyq6IJ4fhzY= github.com/dylanmei/winrmtest v0.0.0-20170819153634-c2fbb09e6c08/go.mod h1:VBVDFSBXCIW8JaHQpI8lldSKfYaLMzP9oyq6IJ4fhzY=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-test/deep v1.0.1 h1:UQhStjbkDClarlmv0am7OXXO4/GaPdCGiUiMTvi28sg= github.com/go-test/deep v1.0.1 h1:UQhStjbkDClarlmv0am7OXXO4/GaPdCGiUiMTvi28sg=
github.com/go-test/deep v1.0.1/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/go-test/deep v1.0.1/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0 h1:xU6/SpYbvkNYiptHJYEDRseDLvYE7wSqhYYNy0QSUzI= github.com/gogo/protobuf v1.2.0 h1:xU6/SpYbvkNYiptHJYEDRseDLvYE7wSqhYYNy0QSUzI=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= 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/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20180513044358-24b0969c4cb7 h1:u4bArs140e9+AfE52mFHOXVFnOSBJBRlzTHrOPLOIhE= github.com/golang/groupcache v0.0.0-20180513044358-24b0969c4cb7 h1:u4bArs140e9+AfE52mFHOXVFnOSBJBRlzTHrOPLOIhE=
github.com/golang/groupcache v0.0.0-20180513044358-24b0969c4cb7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20180513044358-24b0969c4cb7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
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 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@ -97,22 +115,30 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCy
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= 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.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/googleapis/gax-go v0.0.0-20161107002406-da06d194a00e h1:CYRpN206UTHUinz3VJoLaBdy1gEGeJNsqT0mvswDcMw= github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
github.com/googleapis/gax-go v0.0.0-20161107002406-da06d194a00e/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/googleapis/gax-go v2.0.0+incompatible h1:j0GKcs05QVmm7yesiZq2+9cxHkNK9YM6zKx4D2qucQU=
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
github.com/googleapis/gax-go/v2 v2.0.3 h1:siORttZ36U2R/WjiJuDz8znElWBiAlO9rVt+mqJt0Cc=
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
github.com/gophercloud/gophercloud v0.0.0-20190208042652-bc37892e1968 h1:Pu+HW4kcQozw0QyrTTgLE+3RXNqFhQNNzhbnoLFL83c= github.com/gophercloud/gophercloud v0.0.0-20190208042652-bc37892e1968 h1:Pu+HW4kcQozw0QyrTTgLE+3RXNqFhQNNzhbnoLFL83c=
github.com/gophercloud/gophercloud v0.0.0-20190208042652-bc37892e1968/go.mod h1:3WdhXV3rUYy9p6AUW8d94kr+HS62Y4VL9mBnFxsD8q4= github.com/gophercloud/gophercloud v0.0.0-20190208042652-bc37892e1968/go.mod h1:3WdhXV3rUYy9p6AUW8d94kr+HS62Y4VL9mBnFxsD8q4=
github.com/gophercloud/utils v0.0.0-20190128072930-fbb6ab446f01 h1:OgCNGSnEalfkRpn//WGJHhpo7fkP+LhTpvEITZ7CkK4= github.com/gophercloud/utils v0.0.0-20190128072930-fbb6ab446f01 h1:OgCNGSnEalfkRpn//WGJHhpo7fkP+LhTpvEITZ7CkK4=
github.com/gophercloud/utils v0.0.0-20190128072930-fbb6ab446f01/go.mod h1:wjDF8z83zTeg5eMLml5EBSlAhbF7G8DobyI1YsMuyzw= github.com/gophercloud/utils v0.0.0-20190128072930-fbb6ab446f01/go.mod h1:wjDF8z83zTeg5eMLml5EBSlAhbF7G8DobyI1YsMuyzw=
github.com/gopherjs/gopherjs v0.0.0-20181004151105-1babbf986f6f h1:JJ2EP5vV3LAD2U1CxQtD7PTOO15Y96kXmKDz7TjxGHs= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181004151105-1babbf986f6f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 h1:Iju5GlWwrvL6UBg4zJJt3btmonfrMlCDdsejg4CZE7c= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 h1:Iju5GlWwrvL6UBg4zJJt3btmonfrMlCDdsejg4CZE7c=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
github.com/grpc-ecosystem/grpc-gateway v1.5.1 h1:3scN4iuXkNOyP98jF55Lv8a9j1o/IwvnDIZ0LHJK1nk= github.com/grpc-ecosystem/grpc-gateway v1.5.1 h1:3scN4iuXkNOyP98jF55Lv8a9j1o/IwvnDIZ0LHJK1nk=
github.com/grpc-ecosystem/grpc-gateway v1.5.1/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/grpc-ecosystem/grpc-gateway v1.5.1/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
github.com/hashicorp/aws-sdk-go-base v0.2.0 h1:5bjZnWCvQg9Im5CHZr9t90IaFC4uvVlMl2fTh23IoCk= github.com/hashicorp/aws-sdk-go-base v0.2.0 h1:5bjZnWCvQg9Im5CHZr9t90IaFC4uvVlMl2fTh23IoCk=
@ -140,8 +166,6 @@ github.com/hashicorp/go-msgpack v0.0.0-20150518234257-fa3f63826f7c/go.mod h1:ahL
github.com/hashicorp/go-multierror v0.0.0-20180717150148-3d5d8f294aa0/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= github.com/hashicorp/go-multierror v0.0.0-20180717150148-3d5d8f294aa0/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I=
github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-plugin v0.0.0-20190212232519-b838ffee39ce h1:I3KJUf8jyMubLFeHit2ibr9YeVxJX2CXMXVM6xlB+Qk=
github.com/hashicorp/go-plugin v0.0.0-20190212232519-b838ffee39ce/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY=
github.com/hashicorp/go-plugin v0.0.0-20190220160451-3f118e8ee104 h1:9iQ/zrTOJqzP+kH37s6xNb6T1RysiT7fnDD3DJbspVw= github.com/hashicorp/go-plugin v0.0.0-20190220160451-3f118e8ee104 h1:9iQ/zrTOJqzP+kH37s6xNb6T1RysiT7fnDD3DJbspVw=
github.com/hashicorp/go-plugin v0.0.0-20190220160451-3f118e8ee104/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY= github.com/hashicorp/go-plugin v0.0.0-20190220160451-3f118e8ee104/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY=
github.com/hashicorp/go-retryablehttp v0.5.1 h1:Vsx5XKPqPs3M6sM4U4GWyUqFS8aBiL9U5gkgvpkg4SE= github.com/hashicorp/go-retryablehttp v0.5.1 h1:Vsx5XKPqPs3M6sM4U4GWyUqFS8aBiL9U5gkgvpkg4SE=
@ -182,6 +206,7 @@ github.com/hashicorp/vault v0.10.4/go.mod h1:KfSyffbKxoVyspOdlaGVjIuwLobi07qD1bA
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M=
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
@ -195,11 +220,13 @@ github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 h1:PJPDf8OUfOK1bb/
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
github.com/keybase/go-crypto v0.0.0-20161004153544-93f5b35093ba h1:NARVGAAgEXvoMeNPHhPFt1SBt1VMznA3Gnz9d0qj+co= github.com/keybase/go-crypto v0.0.0-20161004153544-93f5b35093ba h1:NARVGAAgEXvoMeNPHhPFt1SBt1VMznA3Gnz9d0qj+co=
github.com/keybase/go-crypto v0.0.0-20161004153544-93f5b35093ba/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M= github.com/keybase/go-crypto v0.0.0-20161004153544-93f5b35093ba/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe h1:CHRGQ8V7OlCYtwaKPJi3iA7J+YdNKdo8j7nG5IgDhjs= github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe h1:CHRGQ8V7OlCYtwaKPJi3iA7J+YdNKdo8j7nG5IgDhjs=
github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= 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/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 h1:MtvEpTB6LX3vkb4ax0b5D2DHbNAUsen0Gx5wZoq3lV4= github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 h1:MtvEpTB6LX3vkb4ax0b5D2DHbNAUsen0Gx5wZoq3lV4=
@ -222,6 +249,7 @@ github.com/mattn/go-shellwords v1.0.1 h1:2/mQs/EosKUge1MHnAavnrNwa0wLnWDjG4dTYMG
github.com/mattn/go-shellwords v1.0.1/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= github.com/mattn/go-shellwords v1.0.1/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
github.com/miekg/dns v1.0.8 h1:Zi8HNpze3NeRWH1PQV6O71YcvJRQ6j0lORO6DAEmAAI= github.com/miekg/dns v1.0.8 h1:Zi8HNpze3NeRWH1PQV6O71YcvJRQ6j0lORO6DAEmAAI=
github.com/miekg/dns v1.0.8/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.0.8/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v0.0.0-20171129193617-33edc47170b5 h1:OYr3N2fY3e3kP/x/d81CJXlcZrIV2hH8gPnuRLpiME4= github.com/mitchellh/cli v0.0.0-20171129193617-33edc47170b5 h1:OYr3N2fY3e3kP/x/d81CJXlcZrIV2hH8gPnuRLpiME4=
@ -249,6 +277,8 @@ github.com/mitchellh/prefixedio v0.0.0-20151214002211-6e6954073784 h1:+DAetXqxv/
github.com/mitchellh/prefixedio v0.0.0-20151214002211-6e6954073784/go.mod h1:kB1naBgV9ORnkiTVeyJOI1DavaJkG4oNIq0Af6ZVKUo= github.com/mitchellh/prefixedio v0.0.0-20151214002211-6e6954073784/go.mod h1:kB1naBgV9ORnkiTVeyJOI1DavaJkG4oNIq0Af6ZVKUo=
github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ=
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U=
github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
@ -275,12 +305,35 @@ github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e h1:n/3MEhJQjQxrO
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273 h1:agujYaXJSxSo18YNX3jzl+4G6Bstwt+kqv47GS12uL0= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273 h1:agujYaXJSxSo18YNX3jzl+4G6Bstwt+kqv47GS12uL0=
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/satori/go.uuid v0.0.0-20160927100844-b061729afc07 h1:DEZDfcCVq3xDJrjqdCgyN/dHYVoqR92MCsdqCdxmnhM= github.com/satori/go.uuid v0.0.0-20160927100844-b061729afc07 h1:DEZDfcCVq3xDJrjqdCgyN/dHYVoqR92MCsdqCdxmnhM=
github.com/satori/go.uuid v0.0.0-20160927100844-b061729afc07/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/satori/go.uuid v0.0.0-20160927100844-b061729afc07/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0=
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw=
github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI=
github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU=
github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag=
github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg=
github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw=
github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y=
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q=
github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ=
github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I=
github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0=
github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=
github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk=
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
github.com/sirupsen/logrus v1.1.1 h1:VzGj7lhU7KEB9e9gMpAV/v5XT2NVSvLJhJLCWbnkgXg= github.com/sirupsen/logrus v1.1.1 h1:VzGj7lhU7KEB9e9gMpAV/v5XT2NVSvLJhJLCWbnkgXg=
github.com/sirupsen/logrus v1.1.1/go.mod h1:zrgwTnHtNr00buQ1vSptGe8m1f/BbgsPukg8qsT7A+A= github.com/sirupsen/logrus v1.1.1/go.mod h1:zrgwTnHtNr00buQ1vSptGe8m1f/BbgsPukg8qsT7A+A=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
@ -289,6 +342,8 @@ github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a h1:JSvGDIbm
github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E= github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
github.com/spf13/afero v1.0.2 h1:5bRmqmInNmNFkI9NG9O0Xc/Lgl9wOWWUUA/O8XZqTCo= github.com/spf13/afero v1.0.2 h1:5bRmqmInNmNFkI9NG9O0Xc/Lgl9wOWWUUA/O8XZqTCo=
github.com/spf13/afero v1.0.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.0.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/pflag v1.0.2 h1:Fy0orTDgHdbnzHcsOgfCN4LtHf0ec3wwtiwJqwvf3Gc= github.com/spf13/pflag v1.0.2 h1:Fy0orTDgHdbnzHcsOgfCN4LtHf0ec3wwtiwJqwvf3Gc=
@ -299,6 +354,7 @@ github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/svanharmelen/jsonapi v0.0.0-20180618144545-0c0828c3f16d h1:Z4EH+5EffvBEhh37F0C0DnpklTMh00JOkjW5zK3ofBI= github.com/svanharmelen/jsonapi v0.0.0-20180618144545-0c0828c3f16d h1:Z4EH+5EffvBEhh37F0C0DnpklTMh00JOkjW5zK3ofBI=
github.com/svanharmelen/jsonapi v0.0.0-20180618144545-0c0828c3f16d/go.mod h1:BSTlc8jOjh0niykqEGVXOLXdi9o0r0kR8tCYiMvjFgw= github.com/svanharmelen/jsonapi v0.0.0-20180618144545-0c0828c3f16d/go.mod h1:BSTlc8jOjh0niykqEGVXOLXdi9o0r0kR8tCYiMvjFgw=
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
github.com/terraform-providers/terraform-provider-openstack v1.15.0 h1:adpjqej+F8BAX9dHmuPF47sUIkgifeqBu6p7iCsyj0Y= github.com/terraform-providers/terraform-provider-openstack v1.15.0 h1:adpjqej+F8BAX9dHmuPF47sUIkgifeqBu6p7iCsyj0Y=
github.com/terraform-providers/terraform-provider-openstack v1.15.0/go.mod h1:2aQ6n/BtChAl1y2S60vebhyJyZXBsuAI5G4+lHrT1Ew= github.com/terraform-providers/terraform-provider-openstack v1.15.0/go.mod h1:2aQ6n/BtChAl1y2S60vebhyJyZXBsuAI5G4+lHrT1Ew=
github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6 h1:lYIiVDtZnyTWlNwiAxLj0bbpTcx1BWCFhXjfsvmPdNc= github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6 h1:lYIiVDtZnyTWlNwiAxLj0bbpTcx1BWCFhXjfsvmPdNc=
@ -321,64 +377,103 @@ github.com/zclconf/go-cty v0.0.0-20190124225737-a385d646c1e9 h1:hHCAGde+QfwbqXSA
github.com/zclconf/go-cty v0.0.0-20190124225737-a385d646c1e9/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s= github.com/zclconf/go-cty v0.0.0-20190124225737-a385d646c1e9/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s=
github.com/zclconf/go-cty v0.0.0-20190201220620-4ca19710f056 h1:C6LhH3JHz2k6tnw5sYXBc8rD8SD/qFp6EhiZAcVyalk= github.com/zclconf/go-cty v0.0.0-20190201220620-4ca19710f056 h1:C6LhH3JHz2k6tnw5sYXBc8rD8SD/qFp6EhiZAcVyalk=
github.com/zclconf/go-cty v0.0.0-20190201220620-4ca19710f056/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s= github.com/zclconf/go-cty v0.0.0-20190201220620-4ca19710f056/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s=
go.opencensus.io v0.17.0 h1:2Cu88MYg+1LU+WVD+NWwYhyP0kKgRlN9QjWGaX0jKTE= go.opencensus.io v0.18.0 h1:Mk5rgZcggtbvtAun5aJzAtjKKN/t0R3jJPlWILlv938=
go.opencensus.io v0.17.0/go.mod h1:mp1VrMQxhlqqDpKvH4UcQUa4YwlzNmymAjPrDdfxNpI= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4= go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o= go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
golang.org/x/crypto v0.0.0-20180816225734-aabede6cba87/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180816225734-aabede6cba87/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85 h1:et7+NAX3lLIk5qUCTA9QelBjGE/NkhzYw/mhnr0s7nI= golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85 h1:et7+NAX3lLIk5qUCTA9QelBjGE/NkhzYw/mhnr0s7nI=
golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180811021610-c39426892332/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-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181129055619-fae4c4e3ad76 h1:xx5MUFyRQRbPk6VjWjIE1epE/K5AoDD8QUN116NCy8k= golang.org/x/net v0.0.0-20181129055619-fae4c4e3ad76 h1:xx5MUFyRQRbPk6VjWjIE1epE/K5AoDD8QUN116NCy8k=
golang.org/x/net v0.0.0-20181129055619-fae4c4e3ad76/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181129055619-fae4c4e3ad76/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 h1:HuTn7WObtcDo9uEEU7rEqL0jYthdXAmZ6PP+meazmaU= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd h1:HuTn7WObtcDo9uEEU7rEqL0jYthdXAmZ6PP+meazmaU=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/oauth2 v0.0.0-20181003184128-c57b0facaced h1:4oqSq7eft7MdPKBGQK11X9WYUxmj6ZLgGTqYIbY1kyw= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181003184128-c57b0facaced/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890 h1:uESlIz09WIHT2I+pasSXcpLYqYK8wHcdCetU3VuMBJE=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190220154721-9b3c75971fc9 h1:pfyU+l9dEu0vZzDDMsdAKa1gZbJYEn6urYXj/+Xkz7s=
golang.org/x/oauth2 v0.0.0-20190220154721-9b3c75971fc9/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc h1:WiYx1rIFmx8c0mXAFtv5D/mHyKe1+jmuP7PViuwqwuQ= golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc h1:WiYx1rIFmx8c0mXAFtv5D/mHyKe1+jmuP7PViuwqwuQ=
golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.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/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c h1:fqgJT0MGcGpPgpWU7VRdRjuArfcOvC4AoJmILihzhDg= 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-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.0.0-20181015145326-625cd1887957 h1:jwCmWUTrTFfjsobRuGurnCQeW4NZKijaIf6yAXwLR0E= google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.0.0-20181015145326-625cd1887957/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.1.0 h1:K6z2u68e86TPdSdefXdzvXgR1zEMa+459vBSfWYAZkI=
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.3.0 h1:FBSsiFRMz3LBeXIomRnVzrQwSDj4ibvcRexLG0LZGQk= google.golang.org/appengine v1.3.0 h1:FBSsiFRMz3LBeXIomRnVzrQwSDj4ibvcRexLG0LZGQk=
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
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/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
google.golang.org/genproto v0.0.0-20190201180003-4b09977fb922 h1:mBVYJnbrXLA/ZCBTCe7PtEgAUP+1bg92qTaFoPHdz+8=
google.golang.org/genproto v0.0.0-20190201180003-4b09977fb922/go.mod h1:L3J43x8/uS+qIUoksaLKe6OS3nUKxOKuIFz1sl2/jx4=
google.golang.org/grpc v1.14.0 h1:ArxJuB1NWfPY6r9Gp9gqwplT0Ge7nqv9msgu03lHLmo= google.golang.org/grpc v1.14.0 h1:ArxJuB1NWfPY6r9Gp9gqwplT0Ge7nqv9msgu03lHLmo=
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.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.18.0 h1:IZl7mfBGfbhYx2p2rKRtYgDFw6SBz+kclmxYrCksPPA=
google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 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 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/vmihailenco/msgpack.v2 v2.9.1 h1:kb0VV7NuIojvRfzwslQeP3yArBqJHW9tOl4t38VS1jM= gopkg.in/vmihailenco/msgpack.v2 v2.9.1 h1:kb0VV7NuIojvRfzwslQeP3yArBqJHW9tOl4t38VS1jM=
gopkg.in/vmihailenco/msgpack.v2 v2.9.1/go.mod h1:/3Dn1Npt9+MYyLpYYXjInO/5jvMLamn+AEGwNEOatn8= gopkg.in/vmihailenco/msgpack.v2 v2.9.1/go.mod h1:/3Dn1Npt9+MYyLpYYXjInO/5jvMLamn+AEGwNEOatn8=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0=
labix.org/v2/mgo v0.0.0-20140701140051-000000000287 h1:L0cnkNl4TfAXzvdrqsYEmxOHOCv2p5I3taaReO8BWFs= labix.org/v2/mgo v0.0.0-20140701140051-000000000287 h1:L0cnkNl4TfAXzvdrqsYEmxOHOCv2p5I3taaReO8BWFs=
labix.org/v2/mgo v0.0.0-20140701140051-000000000287/go.mod h1:Lg7AYkt1uXJoR9oeSZ3W/8IXLdvOfIITgZnommstyz4= labix.org/v2/mgo v0.0.0-20140701140051-000000000287/go.mod h1:Lg7AYkt1uXJoR9oeSZ3W/8IXLdvOfIITgZnommstyz4=
launchpad.net/gocheck v0.0.0-20140225173054-000000000087 h1:Izowp2XBH6Ya6rv+hqbceQyw/gSGoXfH/UPoTGduL54= launchpad.net/gocheck v0.0.0-20140225173054-000000000087 h1:Izowp2XBH6Ya6rv+hqbceQyw/gSGoXfH/UPoTGduL54=
launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM= launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM=
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=

View File

@ -22,10 +22,13 @@ David Symonds <dsymonds@golang.org>
Filippo Valsorda <hi@filippo.io> Filippo Valsorda <hi@filippo.io>
Glenn Lewis <gmlewis@google.com> Glenn Lewis <gmlewis@google.com>
Ingo Oeser <nightlyone@googlemail.com> Ingo Oeser <nightlyone@googlemail.com>
James Hall <james.hall@shopify.com>
Johan Euphrosine <proppy@google.com> Johan Euphrosine <proppy@google.com>
Jonathan Amsterdam <jba@google.com> Jonathan Amsterdam <jba@google.com>
Kunpei Sakai <namusyaka@gmail.com>
Luna Duclos <luna.duclos@palmstonegames.com> Luna Duclos <luna.duclos@palmstonegames.com>
Magnus Hiie <magnus.hiie@gmail.com> Magnus Hiie <magnus.hiie@gmail.com>
Mario Castro <mariocaster@gmail.com>
Michael McGreevy <mcgreevy@golang.org> Michael McGreevy <mcgreevy@golang.org>
Omar Jarjur <ojarjur@google.com> Omar Jarjur <ojarjur@google.com>
Paweł Knap <pawelknap88@gmail.com> Paweł Knap <pawelknap88@gmail.com>

2
vendor/cloud.google.com/go/LICENSE generated vendored
View File

@ -187,7 +187,7 @@
same "printed page" as the copyright notice for easier same "printed page" as the copyright notice for easier
identification within third-party archives. identification within third-party archives.
Copyright 2014 Google Inc. Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
// Copyright 2014 Google Inc. All Rights Reserved. // Copyright 2014 Google LLC
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@ -20,6 +20,7 @@
package metadata // import "cloud.google.com/go/compute/metadata" package metadata // import "cloud.google.com/go/compute/metadata"
import ( import (
"context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
@ -31,9 +32,6 @@ import (
"strings" "strings"
"sync" "sync"
"time" "time"
"golang.org/x/net/context"
"golang.org/x/net/context/ctxhttp"
) )
const ( const (
@ -64,7 +62,7 @@ var (
) )
var ( var (
metaClient = &http.Client{ defaultClient = &Client{hc: &http.Client{
Transport: &http.Transport{ Transport: &http.Transport{
Dial: (&net.Dialer{ Dial: (&net.Dialer{
Timeout: 2 * time.Second, Timeout: 2 * time.Second,
@ -72,15 +70,15 @@ var (
}).Dial, }).Dial,
ResponseHeaderTimeout: 2 * time.Second, ResponseHeaderTimeout: 2 * time.Second,
}, },
} }}
subscribeClient = &http.Client{ subscribeClient = &Client{hc: &http.Client{
Transport: &http.Transport{ Transport: &http.Transport{
Dial: (&net.Dialer{ Dial: (&net.Dialer{
Timeout: 2 * time.Second, Timeout: 2 * time.Second,
KeepAlive: 30 * time.Second, KeepAlive: 30 * time.Second,
}).Dial, }).Dial,
}, },
} }}
) )
// NotDefinedError is returned when requested metadata is not defined. // NotDefinedError is returned when requested metadata is not defined.
@ -95,74 +93,16 @@ func (suffix NotDefinedError) Error() string {
return fmt.Sprintf("metadata: GCE metadata %q not defined", string(suffix)) return fmt.Sprintf("metadata: GCE metadata %q not defined", string(suffix))
} }
// Get returns a value from the metadata service. func (c *cachedValue) get(cl *Client) (v string, err error) {
// 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 Get(suffix string) (string, error) {
val, _, err := getETag(metaClient, suffix)
return val, err
}
// getETag returns a value from the metadata service as well as the associated
// ETag using the provided client. This func is otherwise equivalent to Get.
func getETag(client *http.Client, 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
}
url := "http://" + host + "/computeMetadata/v1/" + suffix
req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("Metadata-Flavor", "Google")
req.Header.Set("User-Agent", userAgent)
res, err := client.Do(req)
if err != nil {
return "", "", err
}
defer res.Body.Close()
if res.StatusCode == http.StatusNotFound {
return "", "", NotDefinedError(suffix)
}
if res.StatusCode != 200 {
return "", "", fmt.Errorf("status code %d trying to fetch %s", res.StatusCode, url)
}
all, err := ioutil.ReadAll(res.Body)
if err != nil {
return "", "", err
}
return string(all), res.Header.Get("Etag"), nil
}
func getTrimmed(suffix string) (s string, err error) {
s, err = Get(suffix)
s = strings.TrimSpace(s)
return
}
func (c *cachedValue) get() (v string, err error) {
defer c.mu.Unlock() defer c.mu.Unlock()
c.mu.Lock() c.mu.Lock()
if c.v != "" { if c.v != "" {
return c.v, nil return c.v, nil
} }
if c.trim { if c.trim {
v, err = getTrimmed(c.k) v, err = cl.getTrimmed(c.k)
} else { } else {
v, err = Get(c.k) v, err = cl.Get(c.k)
} }
if err == nil { if err == nil {
c.v = v c.v = v
@ -197,11 +137,11 @@ func testOnGCE() bool {
resc := make(chan bool, 2) resc := make(chan bool, 2)
// Try two strategies in parallel. // Try two strategies in parallel.
// See https://github.com/GoogleCloudPlatform/google-cloud-go/issues/194 // See https://github.com/googleapis/google-cloud-go/issues/194
go func() { go func() {
req, _ := http.NewRequest("GET", "http://"+metadataIP, nil) req, _ := http.NewRequest("GET", "http://"+metadataIP, nil)
req.Header.Set("User-Agent", userAgent) req.Header.Set("User-Agent", userAgent)
res, err := ctxhttp.Do(ctx, metaClient, req) res, err := defaultClient.hc.Do(req.WithContext(ctx))
if err != nil { if err != nil {
resc <- false resc <- false
return return
@ -266,6 +206,255 @@ func systemInfoSuggestsGCE() bool {
return name == "Google" || name == "Google Compute Engine" return name == "Google" || name == "Google Compute Engine"
} }
// Subscribe calls Client.Subscribe on a client designed for subscribing (one with no
// ResponseHeaderTimeout).
func Subscribe(suffix string, fn func(v string, ok bool) error) error {
return subscribeClient.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() }
// 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. All HTTP requests
// will use the given http.Client instead of the default client.
func NewClient(c *http.Client) *Client {
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
}
u := "http://" + host + "/computeMetadata/v1/" + suffix
req, _ := http.NewRequest("GET", u, nil)
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")
}
// 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) {
host, err := c.Hostname()
if err != nil {
return "", err
}
return strings.Split(host, ".")[0], nil
}
// 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. // Subscribe subscribes to a value from the metadata service.
// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/". // The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
// The suffix may contain query parameters. // The suffix may contain query parameters.
@ -275,11 +464,11 @@ func systemInfoSuggestsGCE() bool {
// and ok false. Subscribe blocks until fn returns a non-nil error or the value // 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 // is deleted. Subscribe returns the error value returned from the last call to
// fn, which may be nil when ok == false. // fn, which may be nil when ok == false.
func Subscribe(suffix string, fn func(v string, ok bool) error) error { func (c *Client) Subscribe(suffix string, fn func(v string, ok bool) error) error {
const failedSubscribeSleep = time.Second * 5 const failedSubscribeSleep = time.Second * 5
// First check to see if the metadata value exists at all. // First check to see if the metadata value exists at all.
val, lastETag, err := getETag(subscribeClient, suffix) val, lastETag, err := c.getETag(suffix)
if err != nil { if err != nil {
return err return err
} }
@ -295,7 +484,7 @@ func Subscribe(suffix string, fn func(v string, ok bool) error) error {
suffix += "?wait_for_change=true&last_etag=" suffix += "?wait_for_change=true&last_etag="
} }
for { for {
val, etag, err := getETag(subscribeClient, suffix+url.QueryEscape(lastETag)) val, etag, err := c.getETag(suffix + url.QueryEscape(lastETag))
if err != nil { if err != nil {
if _, deleted := err.(NotDefinedError); !deleted { if _, deleted := err.(NotDefinedError); !deleted {
time.Sleep(failedSubscribeSleep) time.Sleep(failedSubscribeSleep)
@ -311,127 +500,14 @@ func Subscribe(suffix string, fn func(v string, ok bool) error) error {
} }
} }
// ProjectID returns the current instance's project ID string. // Error contains an error response from the server.
func ProjectID() (string, error) { return projID.get() } type Error struct {
// Code is the HTTP response status code.
// NumericProjectID returns the current instance's numeric project ID. Code int
func NumericProjectID() (string, error) { return projNum.get() } // Message is the server response message.
Message string
// InternalIP returns the instance's primary internal IP address.
func InternalIP() (string, error) {
return getTrimmed("instance/network-interfaces/0/ip")
} }
// ExternalIP returns the instance's primary external (public) IP address. func (e *Error) Error() string {
func ExternalIP() (string, error) { return fmt.Sprintf("compute: Received %d `%s`", e.Code, e.Message)
return 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 Hostname() (string, error) {
return getTrimmed("instance/hostname")
}
// InstanceTags returns the list of user-defined instance tags,
// assigned when initially creating a GCE instance.
func InstanceTags() ([]string, error) {
var s []string
j, err := 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
}
// InstanceID returns the current VM's numeric instance ID.
func InstanceID() (string, error) {
return instID.get()
}
// InstanceName returns the current VM's instance ID string.
func InstanceName() (string, error) {
host, err := Hostname()
if err != nil {
return "", err
}
return strings.Split(host, ".")[0], nil
}
// Zone returns the current VM's zone, such as "us-central1-b".
func Zone() (string, error) {
zone, err := 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 InstanceAttributes() ([]string, error) { return 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 ProjectAttributes() ([]string, error) { return lines("project/attributes/") }
func lines(suffix string) ([]string, error) {
j, err := 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
}
// 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 InstanceAttributeValue(attr string) (string, error) {
return 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 ProjectAttributeValue(attr string) (string, error) {
return 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 Scopes(serviceAccount string) ([]string, error) {
if serviceAccount == "" {
serviceAccount = "default"
}
return lines("instance/service-accounts/" + serviceAccount + "/scopes")
}
func strsContains(ss []string, s string) bool {
for _, v := range ss {
if v == s {
return true
}
}
return false
} }

View File

@ -1,4 +1,4 @@
// Copyright 2016 Google Inc. All Rights Reserved. // Copyright 2016 Google LLC
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@ -22,9 +22,15 @@
package iam package iam
import ( import (
"golang.org/x/net/context" "context"
"fmt"
"time"
gax "github.com/googleapis/gax-go/v2"
pb "google.golang.org/genproto/googleapis/iam/v1" pb "google.golang.org/genproto/googleapis/iam/v1"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
) )
// client abstracts the IAMPolicy API to allow multiple implementations. // client abstracts the IAMPolicy API to allow multiple implementations.
@ -39,26 +45,59 @@ type grpcClient struct {
c pb.IAMPolicyClient 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) { func (g *grpcClient) Get(ctx context.Context, resource string) (*pb.Policy, error) {
proto, err := g.c.GetIamPolicy(ctx, &pb.GetIamPolicyRequest{Resource: resource}) 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})
return err
}, withRetry)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return proto, nil return proto, nil
} }
func (g *grpcClient) Set(ctx context.Context, resource string, p *pb.Policy) error { func (g *grpcClient) Set(ctx context.Context, resource string, p *pb.Policy) error {
_, err := g.c.SetIamPolicy(ctx, &pb.SetIamPolicyRequest{ md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", resource))
Resource: resource, ctx = insertMetadata(ctx, md)
Policy: p,
}) return gax.Invoke(ctx, func(ctx context.Context, _ gax.CallSettings) error {
return err _, 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) { func (g *grpcClient) Test(ctx context.Context, resource string, perms []string) ([]string, error) {
res, err := g.c.TestIamPermissions(ctx, &pb.TestIamPermissionsRequest{ var res *pb.TestIamPermissionsResponse
Resource: resource, md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", resource))
Permissions: perms, 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 { if err != nil {
return nil, err return nil, err
} }
@ -76,7 +115,15 @@ type Handle struct {
// InternalNewHandle returns a Handle for resource. // InternalNewHandle returns a Handle for resource.
// The conn parameter refers to a server that must support the IAMPolicy service. // The conn parameter refers to a server that must support the IAMPolicy service.
func InternalNewHandle(conn *grpc.ClientConn, resource string) *Handle { func InternalNewHandle(conn *grpc.ClientConn, resource string) *Handle {
return InternalNewHandleClient(&grpcClient{c: pb.NewIAMPolicyClient(conn)}, resource) 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 is for use by the Google Cloud Libraries only.
@ -254,3 +301,15 @@ func memberIndex(m string, b *pb.Binding) int {
} }
return -1 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)
}

54
vendor/cloud.google.com/go/internal/annotate.go generated vendored Normal file
View File

@ -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...))
}

View File

@ -1,4 +1,4 @@
// Copyright 2016 Google Inc. All Rights Reserved. // Copyright 2016 Google LLC
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
// Copyright 2016 Google Inc. All Rights Reserved. // Copyright 2016 Google LLC
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@ -15,12 +15,10 @@
package internal package internal
import ( import (
"fmt" "context"
"time" "time"
gax "github.com/googleapis/gax-go" gax "github.com/googleapis/gax-go/v2"
"golang.org/x/net/context"
) )
// Retry calls the supplied function f repeatedly according to the provided // Retry calls the supplied function f repeatedly according to the provided
@ -48,7 +46,7 @@ func retry(ctx context.Context, bo gax.Backoff, f func() (stop bool, err error),
p := bo.Pause() p := bo.Pause()
if cerr := sleep(ctx, p); cerr != nil { if cerr := sleep(ctx, p); cerr != nil {
if lastErr != nil { if lastErr != nil {
return fmt.Errorf("%v; last function err: %v", cerr, lastErr) return Annotatef(lastErr, "retry failed with %v; last error", cerr)
} }
return cerr return cerr
} }

84
vendor/cloud.google.com/go/internal/trace/trace.go generated vendored Normal file
View File

@ -0,0 +1,84 @@
// 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"
"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)
}
}

View File

@ -1,4 +1,4 @@
// Copyright 2016 Google Inc. All Rights Reserved. // Copyright 2016 Google LLC
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@ -26,7 +26,7 @@ import (
// Repo is the current version of the client libraries in this // Repo is the current version of the client libraries in this
// repo. It should be a date in YYYYMMDD format. // repo. It should be a date in YYYYMMDD format.
const Repo = "20170928" const Repo = "20180226"
// Go returns the Go runtime version. The returned string // Go returns the Go runtime version. The returned string
// has no whitespace. // has no whitespace.
@ -67,5 +67,5 @@ func goVer(s string) string {
} }
func notSemverRune(r rune) bool { func notSemverRune(r rune) bool {
return strings.IndexRune("0123456789.", r) < 0 return !strings.ContainsRune("0123456789.", r)
} }

View File

@ -1,4 +1,4 @@
// Copyright 2014 Google Inc. All Rights Reserved. // Copyright 2014 Google LLC
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@ -15,11 +15,11 @@
package storage package storage
import ( import (
"fmt" "context"
"net/http" "net/http"
"reflect" "reflect"
"golang.org/x/net/context" "cloud.google.com/go/internal/trace"
"google.golang.org/api/googleapi" "google.golang.org/api/googleapi"
raw "google.golang.org/api/storage/v1" raw "google.golang.org/api/storage/v1"
) )
@ -48,10 +48,21 @@ const (
AllAuthenticatedUsers ACLEntity = "allAuthenticatedUsers" 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. // 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 { type ACLRule struct {
Entity ACLEntity Entity ACLEntity
Role ACLRole 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. // ACLHandle provides operations on an access control list for a Google Cloud Storage bucket or object.
@ -64,7 +75,10 @@ type ACLHandle struct {
} }
// Delete permanently deletes the ACL entry for the given entity. // Delete permanently deletes the ACL entry for the given entity.
func (a *ACLHandle) Delete(ctx context.Context, entity ACLEntity) error { 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 != "" { if a.object != "" {
return a.objectDelete(ctx, entity) return a.objectDelete(ctx, entity)
} }
@ -74,8 +88,11 @@ func (a *ACLHandle) Delete(ctx context.Context, entity ACLEntity) error {
return a.bucketDelete(ctx, entity) return a.bucketDelete(ctx, entity)
} }
// Set sets the permission level for the given entity. // Set sets the role for the given entity.
func (a *ACLHandle) Set(ctx context.Context, entity ACLEntity, role ACLRole) error { 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 != "" { if a.object != "" {
return a.objectSet(ctx, entity, role, false) return a.objectSet(ctx, entity, role, false)
} }
@ -86,7 +103,10 @@ func (a *ACLHandle) Set(ctx context.Context, entity ACLEntity, role ACLRole) err
} }
// List retrieves ACL entries. // List retrieves ACL entries.
func (a *ACLHandle) List(ctx context.Context) ([]ACLRule, error) { 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 != "" { if a.object != "" {
return a.objectList(ctx) return a.objectList(ctx)
} }
@ -101,26 +121,22 @@ func (a *ACLHandle) bucketDefaultList(ctx context.Context) ([]ACLRule, error) {
var err error var err error
err = runWithRetry(ctx, func() error { err = runWithRetry(ctx, func() error {
req := a.c.raw.DefaultObjectAccessControls.List(a.bucket) req := a.c.raw.DefaultObjectAccessControls.List(a.bucket)
a.configureCall(req, ctx) a.configureCall(ctx, req)
acls, err = req.Do() acls, err = req.Do()
return err return err
}) })
if err != nil { if err != nil {
return nil, fmt.Errorf("storage: error listing default object ACL for bucket %q: %v", a.bucket, err) return nil, err
} }
return toACLRules(acls.Items), nil return toObjectACLRules(acls.Items), nil
} }
func (a *ACLHandle) bucketDefaultDelete(ctx context.Context, entity ACLEntity) error { func (a *ACLHandle) bucketDefaultDelete(ctx context.Context, entity ACLEntity) error {
err := runWithRetry(ctx, func() error { return runWithRetry(ctx, func() error {
req := a.c.raw.DefaultObjectAccessControls.Delete(a.bucket, string(entity)) req := a.c.raw.DefaultObjectAccessControls.Delete(a.bucket, string(entity))
a.configureCall(req, ctx) a.configureCall(ctx, req)
return req.Do() return req.Do()
}) })
if err != nil {
return fmt.Errorf("storage: error deleting default ACL entry for bucket %q, entity %q: %v", a.bucket, entity, err)
}
return nil
} }
func (a *ACLHandle) bucketList(ctx context.Context) ([]ACLRule, error) { func (a *ACLHandle) bucketList(ctx context.Context) ([]ACLRule, error) {
@ -128,19 +144,14 @@ func (a *ACLHandle) bucketList(ctx context.Context) ([]ACLRule, error) {
var err error var err error
err = runWithRetry(ctx, func() error { err = runWithRetry(ctx, func() error {
req := a.c.raw.BucketAccessControls.List(a.bucket) req := a.c.raw.BucketAccessControls.List(a.bucket)
a.configureCall(req, ctx) a.configureCall(ctx, req)
acls, err = req.Do() acls, err = req.Do()
return err return err
}) })
if err != nil { if err != nil {
return nil, fmt.Errorf("storage: error listing bucket ACL for bucket %q: %v", a.bucket, err) return nil, err
} }
r := make([]ACLRule, len(acls.Items)) return toBucketACLRules(acls.Items), nil
for i, v := range acls.Items {
r[i].Entity = ACLEntity(v.Entity)
r[i].Role = ACLRole(v.Role)
}
return r, nil
} }
func (a *ACLHandle) bucketSet(ctx context.Context, entity ACLEntity, role ACLRole) error { func (a *ACLHandle) bucketSet(ctx context.Context, entity ACLEntity, role ACLRole) error {
@ -151,26 +162,22 @@ func (a *ACLHandle) bucketSet(ctx context.Context, entity ACLEntity, role ACLRol
} }
err := runWithRetry(ctx, func() error { err := runWithRetry(ctx, func() error {
req := a.c.raw.BucketAccessControls.Update(a.bucket, string(entity), acl) req := a.c.raw.BucketAccessControls.Update(a.bucket, string(entity), acl)
a.configureCall(req, ctx) a.configureCall(ctx, req)
_, err := req.Do() _, err := req.Do()
return err return err
}) })
if err != nil { if err != nil {
return fmt.Errorf("storage: error updating bucket ACL entry for bucket %q, entity %q: %v", a.bucket, entity, err) return err
} }
return nil return nil
} }
func (a *ACLHandle) bucketDelete(ctx context.Context, entity ACLEntity) error { func (a *ACLHandle) bucketDelete(ctx context.Context, entity ACLEntity) error {
err := runWithRetry(ctx, func() error { return runWithRetry(ctx, func() error {
req := a.c.raw.BucketAccessControls.Delete(a.bucket, string(entity)) req := a.c.raw.BucketAccessControls.Delete(a.bucket, string(entity))
a.configureCall(req, ctx) a.configureCall(ctx, req)
return req.Do() return req.Do()
}) })
if err != nil {
return fmt.Errorf("storage: error deleting bucket ACL entry for bucket %q, entity %q: %v", a.bucket, entity, err)
}
return nil
} }
func (a *ACLHandle) objectList(ctx context.Context) ([]ACLRule, error) { func (a *ACLHandle) objectList(ctx context.Context) ([]ACLRule, error) {
@ -178,14 +185,14 @@ func (a *ACLHandle) objectList(ctx context.Context) ([]ACLRule, error) {
var err error var err error
err = runWithRetry(ctx, func() error { err = runWithRetry(ctx, func() error {
req := a.c.raw.ObjectAccessControls.List(a.bucket, a.object) req := a.c.raw.ObjectAccessControls.List(a.bucket, a.object)
a.configureCall(req, ctx) a.configureCall(ctx, req)
acls, err = req.Do() acls, err = req.Do()
return err return err
}) })
if err != nil { if err != nil {
return nil, fmt.Errorf("storage: error listing object ACL for bucket %q, file %q: %v", a.bucket, a.object, err) return nil, err
} }
return toACLRules(acls.Items), nil return toObjectACLRules(acls.Items), nil
} }
func (a *ACLHandle) objectSet(ctx context.Context, entity ACLEntity, role ACLRole, isBucketDefault bool) error { func (a *ACLHandle) objectSet(ctx context.Context, entity ACLEntity, role ACLRole, isBucketDefault bool) error {
@ -205,36 +212,22 @@ func (a *ACLHandle) objectSet(ctx context.Context, entity ACLEntity, role ACLRol
} else { } else {
req = a.c.raw.ObjectAccessControls.Update(a.bucket, a.object, string(entity), acl) req = a.c.raw.ObjectAccessControls.Update(a.bucket, a.object, string(entity), acl)
} }
a.configureCall(req, ctx) a.configureCall(ctx, req)
err := runWithRetry(ctx, func() error { return runWithRetry(ctx, func() error {
_, err := req.Do() _, err := req.Do()
return err return err
}) })
if err != nil {
if isBucketDefault {
return fmt.Errorf("storage: error updating default ACL entry for bucket %q, entity %q: %v", a.bucket, entity, err)
} else {
return fmt.Errorf("storage: error updating object ACL entry for bucket %q, object %q, entity %q: %v", a.bucket, a.object, entity, err)
}
}
return nil
} }
func (a *ACLHandle) objectDelete(ctx context.Context, entity ACLEntity) error { func (a *ACLHandle) objectDelete(ctx context.Context, entity ACLEntity) error {
err := runWithRetry(ctx, func() error { return runWithRetry(ctx, func() error {
req := a.c.raw.ObjectAccessControls.Delete(a.bucket, a.object, string(entity)) req := a.c.raw.ObjectAccessControls.Delete(a.bucket, a.object, string(entity))
a.configureCall(req, ctx) a.configureCall(ctx, req)
return req.Do() return req.Do()
}) })
if err != nil {
return fmt.Errorf("storage: error deleting object ACL entry for bucket %q, file %q, entity %q: %v", a.bucket, a.object, entity, err)
}
return nil
} }
func (a *ACLHandle) configureCall(call interface { func (a *ACLHandle) configureCall(ctx context.Context, call interface{ Header() http.Header }) {
Header() http.Header
}, ctx context.Context) {
vc := reflect.ValueOf(call) vc := reflect.ValueOf(call)
vc.MethodByName("Context").Call([]reflect.Value{reflect.ValueOf(ctx)}) vc.MethodByName("Context").Call([]reflect.Value{reflect.ValueOf(ctx)})
if a.userProject != "" { if a.userProject != "" {
@ -243,10 +236,100 @@ func (a *ACLHandle) configureCall(call interface {
setClientHeader(call.Header()) setClientHeader(call.Header())
} }
func toACLRules(items []*raw.ObjectAccessControl) []ACLRule { func toObjectACLRules(items []*raw.ObjectAccessControl) []ACLRule {
r := make([]ACLRule, 0, len(items)) var rs []ACLRule
for _, item := range items { for _, item := range items {
r = append(r, ACLRule{Entity: ACLEntity(item.Entity), Role: ACLRole(item.Role)}) 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 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,
}
}

View File

@ -1,4 +1,4 @@
// Copyright 2014 Google Inc. LiveAndArchived Rights Reserved. // Copyright 2014 Google LLC
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@ -15,13 +15,14 @@
package storage package storage
import ( import (
"context"
"fmt" "fmt"
"net/http" "net/http"
"reflect" "reflect"
"time" "time"
"cloud.google.com/go/internal/optional" "cloud.google.com/go/internal/optional"
"golang.org/x/net/context" "cloud.google.com/go/internal/trace"
"google.golang.org/api/googleapi" "google.golang.org/api/googleapi"
"google.golang.org/api/iterator" "google.golang.org/api/iterator"
raw "google.golang.org/api/storage/v1" raw "google.golang.org/api/storage/v1"
@ -35,7 +36,7 @@ type BucketHandle struct {
acl ACLHandle acl ACLHandle
defaultObjectACL ACLHandle defaultObjectACL ACLHandle
conds *BucketConditions conds *BucketConditions
userProject string // project for requester-pays buckets userProject string // project for Requester Pays buckets
} }
// Bucket returns a BucketHandle, which provides operations on the named bucket. // Bucket returns a BucketHandle, which provides operations on the named bucket.
@ -63,7 +64,10 @@ func (c *Client) Bucket(name string) *BucketHandle {
// Create creates the Bucket in the project. // Create creates the Bucket in the project.
// If attrs is nil the API defaults will be used. // If attrs is nil the API defaults will be used.
func (b *BucketHandle) Create(ctx context.Context, projectID string, attrs *BucketAttrs) error { func (b *BucketHandle) Create(ctx context.Context, projectID string, attrs *BucketAttrs) (err error) {
ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Create")
defer func() { trace.EndSpan(ctx, err) }()
var bkt *raw.Bucket var bkt *raw.Bucket
if attrs != nil { if attrs != nil {
bkt = attrs.toRawBucket() bkt = attrs.toRawBucket()
@ -78,11 +82,20 @@ func (b *BucketHandle) Create(ctx context.Context, projectID string, attrs *Buck
} }
req := b.c.raw.Buckets.Insert(projectID, bkt) req := b.c.raw.Buckets.Insert(projectID, bkt)
setClientHeader(req.Header()) setClientHeader(req.Header())
if attrs != nil && attrs.PredefinedACL != "" {
req.PredefinedAcl(attrs.PredefinedACL)
}
if attrs != nil && attrs.PredefinedDefaultObjectACL != "" {
req.PredefinedDefaultObjectAcl(attrs.PredefinedDefaultObjectACL)
}
return runWithRetry(ctx, func() error { _, err := req.Context(ctx).Do(); return err }) return runWithRetry(ctx, func() error { _, err := req.Context(ctx).Do(); return err })
} }
// Delete deletes the Bucket. // Delete deletes the Bucket.
func (b *BucketHandle) Delete(ctx context.Context) error { func (b *BucketHandle) Delete(ctx context.Context) (err error) {
ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Delete")
defer func() { trace.EndSpan(ctx, err) }()
req, err := b.newDeleteCall() req, err := b.newDeleteCall()
if err != nil { if err != nil {
return err return err
@ -139,7 +152,10 @@ func (b *BucketHandle) Object(name string) *ObjectHandle {
} }
// Attrs returns the metadata for the bucket. // Attrs returns the metadata for the bucket.
func (b *BucketHandle) Attrs(ctx context.Context) (*BucketAttrs, error) { func (b *BucketHandle) Attrs(ctx context.Context) (attrs *BucketAttrs, err error) {
ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Attrs")
defer func() { trace.EndSpan(ctx, err) }()
req, err := b.newGetCall() req, err := b.newGetCall()
if err != nil { if err != nil {
return nil, err return nil, err
@ -155,7 +171,7 @@ func (b *BucketHandle) Attrs(ctx context.Context) (*BucketAttrs, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return newBucket(resp), nil return newBucket(resp)
} }
func (b *BucketHandle) newGetCall() (*raw.BucketsGetCall, error) { func (b *BucketHandle) newGetCall() (*raw.BucketsGetCall, error) {
@ -170,17 +186,27 @@ func (b *BucketHandle) newGetCall() (*raw.BucketsGetCall, error) {
return req, nil return req, nil
} }
func (b *BucketHandle) Update(ctx context.Context, uattrs BucketAttrsToUpdate) (*BucketAttrs, error) { // Update updates a bucket's attributes.
func (b *BucketHandle) Update(ctx context.Context, uattrs BucketAttrsToUpdate) (attrs *BucketAttrs, err error) {
ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Create")
defer func() { trace.EndSpan(ctx, err) }()
req, err := b.newPatchCall(&uattrs) req, err := b.newPatchCall(&uattrs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if uattrs.PredefinedACL != "" {
req.PredefinedAcl(uattrs.PredefinedACL)
}
if uattrs.PredefinedDefaultObjectACL != "" {
req.PredefinedDefaultObjectAcl(uattrs.PredefinedDefaultObjectACL)
}
// TODO(jba): retry iff metagen is set? // TODO(jba): retry iff metagen is set?
rb, err := req.Context(ctx).Do() rb, err := req.Context(ctx).Do()
if err != nil { if err != nil {
return nil, err return nil, err
} }
return newBucket(rb), nil return newBucket(rb)
} }
func (b *BucketHandle) newPatchCall(uattrs *BucketAttrsToUpdate) (*raw.BucketsPatchCall, error) { func (b *BucketHandle) newPatchCall(uattrs *BucketAttrsToUpdate) (*raw.BucketsPatchCall, error) {
@ -206,10 +232,32 @@ type BucketAttrs struct {
// ACL is the list of access control rules on the bucket. // ACL is the list of access control rules on the bucket.
ACL []ACLRule ACL []ACLRule
// BucketPolicyOnly configures access checks to use only bucket-level IAM
// policies.
BucketPolicyOnly BucketPolicyOnly
// DefaultObjectACL is the list of access controls to // DefaultObjectACL is the list of access controls to
// apply to new objects when no object ACL is provided. // apply to new objects when no object ACL is provided.
DefaultObjectACL []ACLRule DefaultObjectACL []ACLRule
// DefaultEventBasedHold is the default value for event-based hold on
// newly created objects in this bucket. It defaults to false.
DefaultEventBasedHold bool
// If not empty, applies a predefined set of access controls. It should be set
// only when creating a bucket.
// It is always empty for BucketAttrs returned from the service.
// See https://cloud.google.com/storage/docs/json_api/v1/buckets/insert
// for valid values.
PredefinedACL string
// If not empty, applies a predefined set of default object access controls.
// It should be set only when creating a bucket.
// It is always empty for BucketAttrs returned from the service.
// See https://cloud.google.com/storage/docs/json_api/v1/buckets/insert
// for valid values.
PredefinedDefaultObjectACL string
// Location is the location of the bucket. It defaults to "US". // Location is the location of the bucket. It defaults to "US".
Location string Location string
@ -237,9 +285,45 @@ type BucketAttrs struct {
Labels map[string]string Labels map[string]string
// RequesterPays reports whether the bucket is a Requester Pays bucket. // RequesterPays reports whether the bucket is a Requester Pays bucket.
// Clients performing operations on Requester Pays buckets must provide
// a user project (see BucketHandle.UserProject), which will be billed
// for the operations.
RequesterPays bool RequesterPays bool
// Lifecycle is the lifecycle configuration for objects in the bucket. // Lifecycle is the lifecycle configuration for objects in the bucket.
Lifecycle Lifecycle Lifecycle Lifecycle
// Retention policy enforces a minimum retention time for all objects
// contained in the bucket. A RetentionPolicy of nil implies the bucket
// has no minimum data retention.
//
// This feature is in private alpha release. It is not currently available to
// most customers. It might be changed in backwards-incompatible ways and is not
// subject to any SLA or deprecation policy.
RetentionPolicy *RetentionPolicy
// The bucket's Cross-Origin Resource Sharing (CORS) configuration.
CORS []CORS
// The encryption configuration used by default for newly inserted objects.
Encryption *BucketEncryption
// The logging configuration.
Logging *BucketLogging
// The website configuration.
Website *BucketWebsite
}
// BucketPolicyOnly configures access checks to use only bucket-level IAM
// policies.
type BucketPolicyOnly struct {
// Enabled specifies whether access checks use only bucket-level IAM
// policies. Enabled may be disabled until the locked time.
Enabled bool
// LockedTime specifies the deadline for changing Enabled from true to
// false.
LockedTime time.Time
} }
// Lifecycle is the lifecycle configuration for objects in the bucket. // Lifecycle is the lifecycle configuration for objects in the bucket.
@ -247,12 +331,42 @@ type Lifecycle struct {
Rules []LifecycleRule Rules []LifecycleRule
} }
// RetentionPolicy enforces a minimum retention time for all objects
// contained in the bucket.
//
// Any attempt to overwrite or delete objects younger than the retention
// period will result in an error. An unlocked retention policy can be
// modified or removed from the bucket via the Update method. A
// locked retention policy cannot be removed or shortened in duration
// for the lifetime of the bucket.
//
// This feature is in private alpha release. It is not currently available to
// most customers. It might be changed in backwards-incompatible ways and is not
// subject to any SLA or deprecation policy.
type RetentionPolicy struct {
// RetentionPeriod specifies the duration that objects need to be
// retained. Retention duration must be greater than zero and less than
// 100 years. Note that enforcement of retention periods less than a day
// is not guaranteed. Such periods should only be used for testing
// purposes.
RetentionPeriod time.Duration
// EffectiveTime is the time from which the policy was enforced and
// effective. This field is read-only.
EffectiveTime time.Time
// IsLocked describes whether the bucket is locked. Once locked, an
// object retention policy cannot be modified.
// This field is read-only.
IsLocked bool
}
const ( const (
// RFC3339 date with only the date segment, used for CreatedBefore in LifecycleRule. // RFC3339 date with only the date segment, used for CreatedBefore in LifecycleRule.
rfc3339Date = "2006-01-02" rfc3339Date = "2006-01-02"
// DeleteAction is a lifecycle action that deletes a live and/or archived // DeleteAction is a lifecycle action that deletes a live and/or archived
// objects. Takes precendence over SetStorageClass actions. // objects. Takes precedence over SetStorageClass actions.
DeleteAction = "Delete" DeleteAction = "Delete"
// SetStorageClassAction changes the storage class of live and/or archived // SetStorageClassAction changes the storage class of live and/or archived
@ -332,53 +446,66 @@ type LifecycleCondition struct {
NumNewerVersions int64 NumNewerVersions int64
} }
func newBucket(b *raw.Bucket) *BucketAttrs { // BucketLogging holds the bucket's logging configuration, which defines the
// destination bucket and optional name prefix for the current bucket's
// logs.
type BucketLogging struct {
// The destination bucket where the current bucket's logs
// should be placed.
LogBucket string
// A prefix for log object names.
LogObjectPrefix string
}
// BucketWebsite holds the bucket's website configuration, controlling how the
// service behaves when accessing bucket contents as a web site. See
// https://cloud.google.com/storage/docs/static-website for more information.
type BucketWebsite struct {
// If the requested object path is missing, the service will ensure the path has
// a trailing '/', append this suffix, and attempt to retrieve the resulting
// object. This allows the creation of index.html objects to represent directory
// pages.
MainPageSuffix string
// If the requested object path is missing, and any mainPageSuffix object is
// missing, if applicable, the service will return the named object from this
// bucket as the content for a 404 Not Found result.
NotFoundPage string
}
func newBucket(b *raw.Bucket) (*BucketAttrs, error) {
if b == nil { if b == nil {
return nil return nil, nil
} }
bucket := &BucketAttrs{ rp, err := toRetentionPolicy(b.RetentionPolicy)
Name: b.Name, if err != nil {
Location: b.Location, return nil, err
MetaGeneration: b.Metageneration,
StorageClass: b.StorageClass,
Created: convertTime(b.TimeCreated),
VersioningEnabled: b.Versioning != nil && b.Versioning.Enabled,
Labels: b.Labels,
RequesterPays: b.Billing != nil && b.Billing.RequesterPays,
Lifecycle: toLifecycle(b.Lifecycle),
} }
acl := make([]ACLRule, len(b.Acl)) return &BucketAttrs{
for i, rule := range b.Acl { Name: b.Name,
acl[i] = ACLRule{ Location: b.Location,
Entity: ACLEntity(rule.Entity), MetaGeneration: b.Metageneration,
Role: ACLRole(rule.Role), DefaultEventBasedHold: b.DefaultEventBasedHold,
} StorageClass: b.StorageClass,
} Created: convertTime(b.TimeCreated),
bucket.ACL = acl VersioningEnabled: b.Versioning != nil && b.Versioning.Enabled,
objACL := make([]ACLRule, len(b.DefaultObjectAcl)) ACL: toBucketACLRules(b.Acl),
for i, rule := range b.DefaultObjectAcl { DefaultObjectACL: toObjectACLRules(b.DefaultObjectAcl),
objACL[i] = ACLRule{ Labels: b.Labels,
Entity: ACLEntity(rule.Entity), RequesterPays: b.Billing != nil && b.Billing.RequesterPays,
Role: ACLRole(rule.Role), Lifecycle: toLifecycle(b.Lifecycle),
} RetentionPolicy: rp,
} CORS: toCORS(b.Cors),
bucket.DefaultObjectACL = objACL Encryption: toBucketEncryption(b.Encryption),
return bucket Logging: toBucketLogging(b.Logging),
Website: toBucketWebsite(b.Website),
BucketPolicyOnly: toBucketPolicyOnly(b.IamConfiguration),
}, nil
} }
// toRawBucket copies the editable attribute from b to the raw library's Bucket type. // toRawBucket copies the editable attribute from b to the raw library's Bucket type.
func (b *BucketAttrs) toRawBucket() *raw.Bucket { func (b *BucketAttrs) toRawBucket() *raw.Bucket {
var acl []*raw.BucketAccessControl
if len(b.ACL) > 0 {
acl = make([]*raw.BucketAccessControl, len(b.ACL))
for i, rule := range b.ACL {
acl[i] = &raw.BucketAccessControl{
Entity: string(rule.Entity),
Role: string(rule.Role),
}
}
}
dACL := toRawObjectACL(b.DefaultObjectACL)
// Copy label map. // Copy label map.
var labels map[string]string var labels map[string]string
if len(b.Labels) > 0 { if len(b.Labels) > 0 {
@ -398,26 +525,114 @@ func (b *BucketAttrs) toRawBucket() *raw.Bucket {
if b.RequesterPays { if b.RequesterPays {
bb = &raw.BucketBilling{RequesterPays: true} bb = &raw.BucketBilling{RequesterPays: true}
} }
var bktIAM *raw.BucketIamConfiguration
if b.BucketPolicyOnly.Enabled {
bktIAM = &raw.BucketIamConfiguration{
BucketPolicyOnly: &raw.BucketIamConfigurationBucketPolicyOnly{
Enabled: true,
},
}
}
return &raw.Bucket{ return &raw.Bucket{
Name: b.Name, Name: b.Name,
DefaultObjectAcl: dACL,
Location: b.Location, Location: b.Location,
StorageClass: b.StorageClass, StorageClass: b.StorageClass,
Acl: acl, Acl: toRawBucketACL(b.ACL),
DefaultObjectAcl: toRawObjectACL(b.DefaultObjectACL),
Versioning: v, Versioning: v,
Labels: labels, Labels: labels,
Billing: bb, Billing: bb,
Lifecycle: toRawLifecycle(b.Lifecycle), Lifecycle: toRawLifecycle(b.Lifecycle),
RetentionPolicy: b.RetentionPolicy.toRawRetentionPolicy(),
Cors: toRawCORS(b.CORS),
Encryption: b.Encryption.toRawBucketEncryption(),
Logging: b.Logging.toRawBucketLogging(),
Website: b.Website.toRawBucketWebsite(),
IamConfiguration: bktIAM,
} }
} }
// CORS is the bucket's Cross-Origin Resource Sharing (CORS) configuration.
type CORS struct {
// MaxAge is the value to return in the Access-Control-Max-Age
// header used in preflight responses.
MaxAge time.Duration
// Methods is the list of HTTP methods on which to include CORS response
// headers, (GET, OPTIONS, POST, etc) Note: "*" is permitted in the list
// of methods, and means "any method".
Methods []string
// Origins is the list of Origins eligible to receive CORS response
// headers. Note: "*" is permitted in the list of origins, and means
// "any Origin".
Origins []string
// ResponseHeaders is the list of HTTP headers other than the simple
// response headers to give permission for the user-agent to share
// across domains.
ResponseHeaders []string
}
// BucketEncryption is a bucket's encryption configuration.
type BucketEncryption struct {
// A Cloud KMS key name, in the form
// projects/P/locations/L/keyRings/R/cryptoKeys/K, that will be used to encrypt
// objects inserted into this bucket, if no encryption method is specified.
// The key's location must be the same as the bucket's.
DefaultKMSKeyName string
}
// BucketAttrsToUpdate define the attributes to update during an Update call.
type BucketAttrsToUpdate struct { type BucketAttrsToUpdate struct {
// VersioningEnabled, if set, updates whether the bucket uses versioning. // If set, updates whether the bucket uses versioning.
VersioningEnabled optional.Bool VersioningEnabled optional.Bool
// RequesterPays, if set, updates whether the bucket is a Requester Pays bucket. // If set, updates whether the bucket is a Requester Pays bucket.
RequesterPays optional.Bool RequesterPays optional.Bool
// DefaultEventBasedHold is the default value for event-based hold on
// newly created objects in this bucket.
DefaultEventBasedHold optional.Bool
// BucketPolicyOnly configures access checks to use only bucket-level IAM
// policies.
BucketPolicyOnly *BucketPolicyOnly
// If set, updates the retention policy of the bucket. Using
// RetentionPolicy.RetentionPeriod = 0 will delete the existing policy.
//
// This feature is in private alpha release. It is not currently available to
// most customers. It might be changed in backwards-incompatible ways and is not
// subject to any SLA or deprecation policy.
RetentionPolicy *RetentionPolicy
// If set, replaces the CORS configuration with a new configuration.
// An empty (rather than nil) slice causes all CORS policies to be removed.
CORS []CORS
// If set, replaces the encryption configuration of the bucket. Using
// BucketEncryption.DefaultKMSKeyName = "" will delete the existing
// configuration.
Encryption *BucketEncryption
// If set, replaces the lifecycle configuration of the bucket.
Lifecycle *Lifecycle
// If set, replaces the logging configuration of the bucket.
Logging *BucketLogging
// If set, replaces the website configuration of the bucket.
Website *BucketWebsite
// If not empty, applies a predefined set of access controls.
// See https://cloud.google.com/storage/docs/json_api/v1/buckets/patch.
PredefinedACL string
// If not empty, applies a predefined set of default object access controls.
// See https://cloud.google.com/storage/docs/json_api/v1/buckets/patch.
PredefinedDefaultObjectACL string
setLabels map[string]string setLabels map[string]string
deleteLabels map[string]bool deleteLabels map[string]bool
} }
@ -442,6 +657,22 @@ func (ua *BucketAttrsToUpdate) DeleteLabel(name string) {
func (ua *BucketAttrsToUpdate) toRawBucket() *raw.Bucket { func (ua *BucketAttrsToUpdate) toRawBucket() *raw.Bucket {
rb := &raw.Bucket{} rb := &raw.Bucket{}
if ua.CORS != nil {
rb.Cors = toRawCORS(ua.CORS)
rb.ForceSendFields = append(rb.ForceSendFields, "Cors")
}
if ua.DefaultEventBasedHold != nil {
rb.DefaultEventBasedHold = optional.ToBool(ua.DefaultEventBasedHold)
rb.ForceSendFields = append(rb.ForceSendFields, "DefaultEventBasedHold")
}
if ua.RetentionPolicy != nil {
if ua.RetentionPolicy.RetentionPeriod == 0 {
rb.NullFields = append(rb.NullFields, "RetentionPolicy")
rb.RetentionPolicy = nil
} else {
rb.RetentionPolicy = ua.RetentionPolicy.toRawRetentionPolicy()
}
}
if ua.VersioningEnabled != nil { if ua.VersioningEnabled != nil {
rb.Versioning = &raw.BucketVersioning{ rb.Versioning = &raw.BucketVersioning{
Enabled: optional.ToBool(ua.VersioningEnabled), Enabled: optional.ToBool(ua.VersioningEnabled),
@ -454,6 +685,50 @@ func (ua *BucketAttrsToUpdate) toRawBucket() *raw.Bucket {
ForceSendFields: []string{"RequesterPays"}, ForceSendFields: []string{"RequesterPays"},
} }
} }
if ua.BucketPolicyOnly != nil {
rb.IamConfiguration = &raw.BucketIamConfiguration{
BucketPolicyOnly: &raw.BucketIamConfigurationBucketPolicyOnly{
Enabled: ua.BucketPolicyOnly.Enabled,
},
}
}
if ua.Encryption != nil {
if ua.Encryption.DefaultKMSKeyName == "" {
rb.NullFields = append(rb.NullFields, "Encryption")
rb.Encryption = nil
} else {
rb.Encryption = ua.Encryption.toRawBucketEncryption()
}
}
if ua.Lifecycle != nil {
rb.Lifecycle = toRawLifecycle(*ua.Lifecycle)
}
if ua.Logging != nil {
if *ua.Logging == (BucketLogging{}) {
rb.NullFields = append(rb.NullFields, "Logging")
rb.Logging = nil
} else {
rb.Logging = ua.Logging.toRawBucketLogging()
}
}
if ua.Website != nil {
if *ua.Website == (BucketWebsite{}) {
rb.NullFields = append(rb.NullFields, "Website")
rb.Website = nil
} else {
rb.Website = ua.Website.toRawBucketWebsite()
}
}
if ua.PredefinedACL != "" {
// Clear ACL or the call will fail.
rb.Acl = nil
rb.ForceSendFields = append(rb.ForceSendFields, "Acl")
}
if ua.PredefinedDefaultObjectACL != "" {
// Clear ACLs or the call will fail.
rb.DefaultObjectAcl = nil
rb.ForceSendFields = append(rb.ForceSendFields, "DefaultObjectAcl")
}
if ua.setLabels != nil || ua.deleteLabels != nil { if ua.setLabels != nil || ua.deleteLabels != nil {
rb.Labels = map[string]string{} rb.Labels = map[string]string{}
for k, v := range ua.setLabels { for k, v := range ua.setLabels {
@ -471,7 +746,7 @@ func (ua *BucketAttrsToUpdate) toRawBucket() *raw.Bucket {
// If returns a new BucketHandle that applies a set of preconditions. // If returns a new BucketHandle that applies a set of preconditions.
// Preconditions already set on the BucketHandle are ignored. // Preconditions already set on the BucketHandle are ignored.
// Operations on the new handle will only occur if the preconditions are // Operations on the new handle will return an error if the preconditions are not
// satisfied. The only valid preconditions for buckets are MetagenerationMatch // satisfied. The only valid preconditions for buckets are MetagenerationMatch
// and MetagenerationNotMatch. // and MetagenerationNotMatch.
func (b *BucketHandle) If(conds BucketConditions) *BucketHandle { func (b *BucketHandle) If(conds BucketConditions) *BucketHandle {
@ -506,8 +781,10 @@ func (c *BucketConditions) validate(method string) error {
} }
// UserProject returns a new BucketHandle that passes the project ID as the user // UserProject returns a new BucketHandle that passes the project ID as the user
// project for all subsequent calls. A user project is required for all operations // project for all subsequent calls. Calls with a user project will be billed to that
// on requester-pays buckets. // project rather than to the bucket's owning project.
//
// A user project is required for all operations on Requester Pays buckets.
func (b *BucketHandle) UserProject(projectID string) *BucketHandle { func (b *BucketHandle) UserProject(projectID string) *BucketHandle {
b2 := *b b2 := *b
b2.userProject = projectID b2.userProject = projectID
@ -516,6 +793,25 @@ func (b *BucketHandle) UserProject(projectID string) *BucketHandle {
return &b2 return &b2
} }
// LockRetentionPolicy locks a bucket's retention policy until a previously-configured
// RetentionPeriod past the EffectiveTime. Note that if RetentionPeriod is set to less
// than a day, the retention policy is treated as a development configuration and locking
// will have no effect. The BucketHandle must have a metageneration condition that
// matches the bucket's metageneration. See BucketHandle.If.
//
// This feature is in private alpha release. It is not currently available to
// most customers. It might be changed in backwards-incompatible ways and is not
// subject to any SLA or deprecation policy.
func (b *BucketHandle) LockRetentionPolicy(ctx context.Context) error {
var metageneration int64
if b.conds != nil {
metageneration = b.conds.MetagenerationMatch
}
req := b.c.raw.Buckets.LockRetentionPolicy(b.name, metageneration)
_, err := req.Context(ctx).Do()
return err
}
// applyBucketConds modifies the provided call using the conditions in conds. // applyBucketConds modifies the provided call using the conditions in conds.
// call is something that quacks like a *raw.WhateverCall. // call is something that quacks like a *raw.WhateverCall.
func applyBucketConds(method string, conds *BucketConditions, call interface{}) error { func applyBucketConds(method string, conds *BucketConditions, call interface{}) error {
@ -539,6 +835,56 @@ func applyBucketConds(method string, conds *BucketConditions, call interface{})
return nil return nil
} }
func (rp *RetentionPolicy) toRawRetentionPolicy() *raw.BucketRetentionPolicy {
if rp == nil {
return nil
}
return &raw.BucketRetentionPolicy{
RetentionPeriod: int64(rp.RetentionPeriod / time.Second),
}
}
func toRetentionPolicy(rp *raw.BucketRetentionPolicy) (*RetentionPolicy, error) {
if rp == nil {
return nil, nil
}
t, err := time.Parse(time.RFC3339, rp.EffectiveTime)
if err != nil {
return nil, err
}
return &RetentionPolicy{
RetentionPeriod: time.Duration(rp.RetentionPeriod) * time.Second,
EffectiveTime: t,
IsLocked: rp.IsLocked,
}, nil
}
func toRawCORS(c []CORS) []*raw.BucketCors {
var out []*raw.BucketCors
for _, v := range c {
out = append(out, &raw.BucketCors{
MaxAgeSeconds: int64(v.MaxAge / time.Second),
Method: v.Methods,
Origin: v.Origins,
ResponseHeader: v.ResponseHeaders,
})
}
return out
}
func toCORS(rc []*raw.BucketCors) []CORS {
var out []CORS
for _, v := range rc {
out = append(out, CORS{
MaxAge: time.Duration(v.MaxAgeSeconds) * time.Second,
Methods: v.Method,
Origins: v.Origin,
ResponseHeaders: v.ResponseHeader,
})
}
return out
}
func toRawLifecycle(l Lifecycle) *raw.BucketLifecycle { func toRawLifecycle(l Lifecycle) *raw.BucketLifecycle {
var rl raw.BucketLifecycle var rl raw.BucketLifecycle
if len(l.Rules) == 0 { if len(l.Rules) == 0 {
@ -604,10 +950,83 @@ func toLifecycle(rl *raw.BucketLifecycle) Lifecycle {
if rr.Condition.CreatedBefore != "" { if rr.Condition.CreatedBefore != "" {
r.Condition.CreatedBefore, _ = time.Parse(rfc3339Date, rr.Condition.CreatedBefore) r.Condition.CreatedBefore, _ = time.Parse(rfc3339Date, rr.Condition.CreatedBefore)
} }
l.Rules = append(l.Rules, r)
} }
return l return l
} }
func (e *BucketEncryption) toRawBucketEncryption() *raw.BucketEncryption {
if e == nil {
return nil
}
return &raw.BucketEncryption{
DefaultKmsKeyName: e.DefaultKMSKeyName,
}
}
func toBucketEncryption(e *raw.BucketEncryption) *BucketEncryption {
if e == nil {
return nil
}
return &BucketEncryption{DefaultKMSKeyName: e.DefaultKmsKeyName}
}
func (b *BucketLogging) toRawBucketLogging() *raw.BucketLogging {
if b == nil {
return nil
}
return &raw.BucketLogging{
LogBucket: b.LogBucket,
LogObjectPrefix: b.LogObjectPrefix,
}
}
func toBucketLogging(b *raw.BucketLogging) *BucketLogging {
if b == nil {
return nil
}
return &BucketLogging{
LogBucket: b.LogBucket,
LogObjectPrefix: b.LogObjectPrefix,
}
}
func (w *BucketWebsite) toRawBucketWebsite() *raw.BucketWebsite {
if w == nil {
return nil
}
return &raw.BucketWebsite{
MainPageSuffix: w.MainPageSuffix,
NotFoundPage: w.NotFoundPage,
}
}
func toBucketWebsite(w *raw.BucketWebsite) *BucketWebsite {
if w == nil {
return nil
}
return &BucketWebsite{
MainPageSuffix: w.MainPageSuffix,
NotFoundPage: w.NotFoundPage,
}
}
func toBucketPolicyOnly(b *raw.BucketIamConfiguration) BucketPolicyOnly {
if b == nil || b.BucketPolicyOnly == nil || !b.BucketPolicyOnly.Enabled {
return BucketPolicyOnly{}
}
lt, err := time.Parse(time.RFC3339, b.BucketPolicyOnly.LockedTime)
if err != nil {
return BucketPolicyOnly{
Enabled: true,
}
}
return BucketPolicyOnly{
Enabled: true,
LockedTime: lt,
}
}
// Objects returns an iterator over the objects in the bucket that match the Query q. // Objects returns an iterator over the objects in the bucket that match the Query q.
// If q is nil, no filtering is done. // If q is nil, no filtering is done.
func (b *BucketHandle) Objects(ctx context.Context, q *Query) *ObjectIterator { func (b *BucketHandle) Objects(ctx context.Context, q *Query) *ObjectIterator {
@ -689,8 +1108,6 @@ func (it *ObjectIterator) fetch(pageSize int, pageToken string) (string, error)
return resp.NextPageToken, nil return resp.NextPageToken, nil
} }
// TODO(jbd): Add storage.buckets.update.
// Buckets returns an iterator over the buckets in the project. You may // Buckets returns an iterator over the buckets in the project. You may
// optionally set the iterator's Prefix field to restrict the list to buckets // optionally set the iterator's Prefix field to restrict the list to buckets
// whose names begin with the prefix. By default, all buckets in the project // whose names begin with the prefix. By default, all buckets in the project
@ -736,7 +1153,7 @@ func (it *BucketIterator) Next() (*BucketAttrs, error) {
// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. // PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
func (it *BucketIterator) PageInfo() *iterator.PageInfo { return it.pageInfo } func (it *BucketIterator) PageInfo() *iterator.PageInfo { return it.pageInfo }
func (it *BucketIterator) fetch(pageSize int, pageToken string) (string, error) { func (it *BucketIterator) fetch(pageSize int, pageToken string) (token string, err error) {
req := it.client.raw.Buckets.List(it.projectID) req := it.client.raw.Buckets.List(it.projectID)
setClientHeader(req.Header()) setClientHeader(req.Header())
req.Projection("full") req.Projection("full")
@ -746,7 +1163,6 @@ func (it *BucketIterator) fetch(pageSize int, pageToken string) (string, error)
req.MaxResults(int64(pageSize)) req.MaxResults(int64(pageSize))
} }
var resp *raw.Buckets var resp *raw.Buckets
var err error
err = runWithRetry(it.ctx, func() error { err = runWithRetry(it.ctx, func() error {
resp, err = req.Context(it.ctx).Do() resp, err = req.Context(it.ctx).Do()
return err return err
@ -755,7 +1171,11 @@ func (it *BucketIterator) fetch(pageSize int, pageToken string) (string, error)
return "", err return "", err
} }
for _, item := range resp.Items { for _, item := range resp.Items {
it.buckets = append(it.buckets, newBucket(item)) b, err := newBucket(item)
if err != nil {
return "", err
}
it.buckets = append(it.buckets, b)
} }
return resp.NextPageToken, nil return resp.NextPageToken, nil
} }

View File

@ -1,4 +1,4 @@
// Copyright 2016 Google Inc. All Rights Reserved. // Copyright 2016 Google LLC
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@ -15,10 +15,11 @@
package storage package storage
import ( import (
"context"
"errors" "errors"
"fmt" "fmt"
"golang.org/x/net/context" "cloud.google.com/go/internal/trace"
raw "google.golang.org/api/storage/v1" raw "google.golang.org/api/storage/v1"
) )
@ -59,17 +60,32 @@ type Copier struct {
// ProgressFunc should return quickly without blocking. // ProgressFunc should return quickly without blocking.
ProgressFunc func(copiedBytes, totalBytes uint64) 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 dst, src *ObjectHandle
} }
// Run performs the copy. // Run performs the copy.
func (c *Copier) Run(ctx context.Context) (*ObjectAttrs, error) { 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 { if err := c.src.validate(); err != nil {
return nil, err return nil, err
} }
if err := c.dst.validate(); err != nil { if err := c.dst.validate(); err != nil {
return nil, err 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. // Convert destination attributes to raw form, omitting the bucket.
// If the bucket is included but name or content-type aren't, the service // 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 // returns a 400 with "Required" as the only message. Omitting the bucket
@ -96,6 +112,12 @@ func (c *Copier) callRewrite(ctx context.Context, rawObj *raw.Object) (*raw.Rewr
if c.RewriteToken != "" { if c.RewriteToken != "" {
call.RewriteToken(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 { if err := applyConds("Copy destination", c.dst.gen, c.dst.conds, call); err != nil {
return nil, err return nil, err
} }
@ -149,7 +171,10 @@ type Composer struct {
} }
// Run performs the compose operation. // Run performs the compose operation.
func (c *Composer) Run(ctx context.Context) (*ObjectAttrs, error) { 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 { if err := c.dst.validate(); err != nil {
return nil, err return nil, err
} }
@ -187,11 +212,13 @@ func (c *Composer) Run(ctx context.Context) (*ObjectAttrs, error) {
if c.dst.userProject != "" { if c.dst.userProject != "" {
call.UserProject(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 { if err := setEncryptionHeaders(call.Header(), c.dst.encryptionKey, false); err != nil {
return nil, err return nil, err
} }
var obj *raw.Object var obj *raw.Object
var err error
setClientHeader(call.Header()) setClientHeader(call.Header())
err = runWithRetry(ctx, func() error { obj, err = call.Do(); return err }) err = runWithRetry(ctx, func() error { obj, err = call.Do(); return err })
if err != nil { if err != nil {

View File

@ -1,4 +1,4 @@
// Copyright 2016 Google Inc. All Rights Reserved. // Copyright 2016 Google LLC
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@ -19,11 +19,14 @@ Google Cloud Storage stores data in named objects, which are grouped into bucket
More information about Google Cloud Storage is available at More information about Google Cloud Storage is available at
https://cloud.google.com/storage/docs. https://cloud.google.com/storage/docs.
All of the methods of this package use exponential backoff to retry calls See https://godoc.org/cloud.google.com/go for authentication, timeouts,
that fail with certain errors, as described in connection pooling and similar aspects of this package.
https://cloud.google.com/storage/docs/exponential-backoff.
Note: This package is in beta. Some backwards-incompatible changes may occur. 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 Creating a Client
@ -36,6 +39,13 @@ To start working with this package, create a client:
// TODO: Handle error. // TODO: Handle error.
} }
The client will use your default application credentials.
If you only wish to access public data, you can create
an unauthenticated client with
client, err := storage.NewClient(ctx, option.WithoutAuthentication())
Buckets Buckets
A Google Cloud Storage bucket is a collection of objects. To work with a A Google Cloud Storage bucket is a collection of objects. To work with a
@ -56,7 +66,7 @@ global across all projects.
Each bucket has associated metadata, represented in this package by Each bucket has associated metadata, represented in this package by
BucketAttrs. The third argument to BucketHandle.Create allows you to set BucketAttrs. The third argument to BucketHandle.Create allows you to set
the intial BucketAttrs of a bucket. To retrieve a bucket's attributes, use the initial BucketAttrs of a bucket. To retrieve a bucket's attributes, use
Attrs: Attrs:
attrs, err := bkt.Attrs(ctx) attrs, err := bkt.Attrs(ctx)
@ -69,15 +79,16 @@ Attrs:
Objects Objects
An object holds arbitrary data as a sequence of bytes, like a file. You An object holds arbitrary data as a sequence of bytes, like a file. You
refer to objects using a handle, just as with buckets. You can use the refer to objects using a handle, just as with buckets, but unlike buckets
standard Go io.Reader and io.Writer interfaces to read and write you don't explicitly create an object. Instead, the first time you write
object data: 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") obj := bkt.Object("data")
// Write something to obj. // Write something to obj.
// w implements io.Writer. // w implements io.Writer.
w := obj.NewWriter(ctx) w := obj.NewWriter(ctx)
// Write some text to obj. This will overwrite whatever is there. // 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 { if _, err := fmt.Fprintf(w, "This object contains text.\n"); err != nil {
// TODO: Handle error. // TODO: Handle error.
} }
@ -153,9 +164,13 @@ SignedURL for details.
} }
fmt.Println(url) fmt.Println(url)
Authentication Errors
See examples of authorization and authentication at Errors returned by this client are often of the type [`googleapi.Error`](https://godoc.org/google.golang.org/api/googleapi#Error).
https://godoc.org/cloud.google.com/go#pkg-examples. 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" package storage // import "cloud.google.com/go/storage"

View File

@ -1,4 +1,4 @@
// Copyright 2017 Google Inc. All Rights Reserved. // Copyright 2017 Google LLC
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@ -24,6 +24,8 @@ func shouldRetry(err error) bool {
// Retry on 429 and 5xx, according to // Retry on 429 and 5xx, according to
// https://cloud.google.com/storage/docs/exponential-backoff. // https://cloud.google.com/storage/docs/exponential-backoff.
return e.Code == 429 || (e.Code >= 500 && e.Code < 600) return e.Code == 429 || (e.Code >= 500 && e.Code < 600)
case interface{ Temporary() bool }:
return e.Temporary()
default: default:
return false return false
} }

View File

@ -1,26 +0,0 @@
// Copyright 2017 Google Inc. 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.
// +build go1.7
package storage
import (
"context"
"net/http"
)
func withContext(r *http.Request, ctx context.Context) *http.Request {
return r.WithContext(ctx)
}

View File

@ -1,4 +1,4 @@
// Copyright 2017 Google Inc. All Rights Reserved. // Copyright 2017 Google LLC
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@ -15,29 +15,40 @@
package storage package storage
import ( import (
"context"
"cloud.google.com/go/iam" "cloud.google.com/go/iam"
"golang.org/x/net/context" "cloud.google.com/go/internal/trace"
raw "google.golang.org/api/storage/v1" raw "google.golang.org/api/storage/v1"
iampb "google.golang.org/genproto/googleapis/iam/v1" iampb "google.golang.org/genproto/googleapis/iam/v1"
) )
// IAM provides access to IAM access control for the bucket. // IAM provides access to IAM access control for the bucket.
func (b *BucketHandle) IAM() *iam.Handle { func (b *BucketHandle) IAM() *iam.Handle {
return iam.InternalNewHandleClient(&iamClient{raw: b.c.raw}, b.name) return iam.InternalNewHandleClient(&iamClient{
raw: b.c.raw,
userProject: b.userProject,
}, b.name)
} }
// iamClient implements the iam.client interface. // iamClient implements the iam.client interface.
type iamClient struct { type iamClient struct {
raw *raw.Service raw *raw.Service
userProject string
} }
func (c *iamClient) Get(ctx context.Context, resource string) (*iampb.Policy, error) { func (c *iamClient) Get(ctx context.Context, resource string) (p *iampb.Policy, err error) {
req := c.raw.Buckets.GetIamPolicy(resource) ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.IAM.Get")
setClientHeader(req.Header()) defer func() { trace.EndSpan(ctx, err) }()
call := c.raw.Buckets.GetIamPolicy(resource)
setClientHeader(call.Header())
if c.userProject != "" {
call.UserProject(c.userProject)
}
var rp *raw.Policy var rp *raw.Policy
var err error
err = runWithRetry(ctx, func() error { err = runWithRetry(ctx, func() error {
rp, err = req.Context(ctx).Do() rp, err = call.Context(ctx).Do()
return err return err
}) })
if err != nil { if err != nil {
@ -46,23 +57,34 @@ func (c *iamClient) Get(ctx context.Context, resource string) (*iampb.Policy, er
return iamFromStoragePolicy(rp), nil return iamFromStoragePolicy(rp), nil
} }
func (c *iamClient) Set(ctx context.Context, resource string, p *iampb.Policy) error { 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) rp := iamToStoragePolicy(p)
req := c.raw.Buckets.SetIamPolicy(resource, rp) call := c.raw.Buckets.SetIamPolicy(resource, rp)
setClientHeader(req.Header()) setClientHeader(call.Header())
if c.userProject != "" {
call.UserProject(c.userProject)
}
return runWithRetry(ctx, func() error { return runWithRetry(ctx, func() error {
_, err := req.Context(ctx).Do() _, err := call.Context(ctx).Do()
return err return err
}) })
} }
func (c *iamClient) Test(ctx context.Context, resource string, perms []string) ([]string, error) { func (c *iamClient) Test(ctx context.Context, resource string, perms []string) (permissions []string, err error) {
req := c.raw.Buckets.TestIamPermissions(resource, perms) ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.IAM.Test")
setClientHeader(req.Header()) 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 var res *raw.TestIamPermissionsResponse
var err error
err = runWithRetry(ctx, func() error { err = runWithRetry(ctx, func() error {
res, err = req.Context(ctx).Do() res, err = call.Context(ctx).Do()
return err return err
}) })
if err != nil { if err != nil {

View File

@ -1,4 +1,4 @@
// Copyright 2014 Google Inc. All Rights Reserved. // Copyright 2014 Google LLC
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@ -15,9 +15,10 @@
package storage package storage
import ( import (
"context"
"cloud.google.com/go/internal" "cloud.google.com/go/internal"
gax "github.com/googleapis/gax-go" gax "github.com/googleapis/gax-go/v2"
"golang.org/x/net/context"
) )
// runWithRetry calls the function until it returns nil or a non-retryable error, or // runWithRetry calls the function until it returns nil or a non-retryable error, or

View File

@ -1,4 +1,4 @@
// Copyright 2017 Google Inc. All Rights Reserved. // Copyright 2017 Google LLC
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@ -34,6 +34,8 @@ func shouldRetry(err error) bool {
// Unfortunately the error type is unexported, so we resort to string // Unfortunately the error type is unexported, so we resort to string
// matching. // matching.
return strings.Contains(e.Error(), "REFUSED_STREAM") return strings.Contains(e.Error(), "REFUSED_STREAM")
case interface{ Temporary() bool }:
return e.Temporary()
default: default:
return false return false
} }

View File

@ -1,26 +0,0 @@
// Copyright 2017 Google Inc. 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.
// +build !go1.7
package storage
import (
"net/http"
)
func withContext(r *http.Request, _ interface{}) *http.Request {
// In Go 1.6 and below, ignore the context.
return r
}

188
vendor/cloud.google.com/go/storage/notifications.go generated vendored Normal file
View File

@ -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()
}

View File

@ -1,4 +1,4 @@
// Copyright 2016 Google Inc. All Rights Reserved. // Copyright 2016 Google LLC
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@ -15,23 +15,277 @@
package storage package storage
import ( import (
"context"
"errors"
"fmt" "fmt"
"hash/crc32" "hash/crc32"
"io" "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) 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
// 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.
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 {
return nil, fmt.Errorf("storage: invalid offset %d < 0", offset)
}
if o.conds != nil {
if err := o.conds.validate("NewRangeReader"); err != nil {
return nil, err
}
}
u := &url.URL{
Scheme: "https",
Host: "storage.googleapis.com",
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 {
// 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),
}
}
if start > 0 && length != 0 && res.StatusCode != http.StatusPartialContent {
res.Body.Close()
return errors.New("storage: partial request not satisfied")
}
// 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
)
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)
}
} 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-Generation") != "" {
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,
Generation: gen,
Metageneration: metaGen,
}
return &Reader{
Attrs: attrs,
body: body,
size: size,
remain: remain,
wantCRC: crc,
checkCRC: checkCRC,
reopen: reopen,
}, nil
}
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. // Reader reads a Cloud Storage object.
// It implements io.Reader. // 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 { type Reader struct {
body io.ReadCloser Attrs ReaderObjectAttrs
remain, size int64 body io.ReadCloser
contentType string seen, remain, size int64
cacheControl string checkCRC bool // should we check the CRC?
checkCRC bool // should we check the CRC? wantCRC uint32 // the CRC32c value the server sent in the header
wantCRC uint32 // the CRC32c value the server sent in the header gotCRC uint32 // running crc
gotCRC uint32 // running crc reopen func(seen int64) (*http.Response, error)
} }
// Close closes the Reader. It must be called when done reading. // Close closes the Reader. It must be called when done reading.
@ -40,7 +294,7 @@ func (r *Reader) Close() error {
} }
func (r *Reader) Read(p []byte) (int, error) { func (r *Reader) Read(p []byte) (int, error) {
n, err := r.body.Read(p) n, err := r.readWithRetry(p)
if r.remain != -1 { if r.remain != -1 {
r.remain -= int64(n) r.remain -= int64(n)
} }
@ -49,19 +303,52 @@ func (r *Reader) Read(p []byte) (int, error) {
// Check CRC here. It would be natural to check it in Close, but // Check CRC here. It would be natural to check it in Close, but
// everybody defers Close on the assumption that it doesn't return // everybody defers Close on the assumption that it doesn't return
// anything worth looking at. // anything worth looking at.
if r.remain == 0 && r.gotCRC != r.wantCRC { if err == io.EOF {
return n, fmt.Errorf("storage: bad CRC on read: got %d, want %d", if r.gotCRC != r.wantCRC {
r.gotCRC, r.wantCRC) return n, fmt.Errorf("storage: bad CRC on read: got %d, want %d",
r.gotCRC, r.wantCRC)
}
} }
} }
return n, err 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. // Size returns the size of the object in bytes.
// The returned value is always the same and is not affected by // The returned value is always the same and is not affected by
// calls to Read or Close. // calls to Read or Close.
//
// Deprecated: use Reader.Attrs.Size.
func (r *Reader) Size() int64 { func (r *Reader) Size() int64 {
return r.size return r.Attrs.Size
} }
// Remain returns the number of bytes left to read, or -1 if unknown. // Remain returns the number of bytes left to read, or -1 if unknown.
@ -70,11 +357,29 @@ func (r *Reader) Remain() int64 {
} }
// ContentType returns the content type of the object. // ContentType returns the content type of the object.
//
// Deprecated: use Reader.Attrs.ContentType.
func (r *Reader) ContentType() string { func (r *Reader) ContentType() string {
return r.contentType 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. // CacheControl returns the cache control of the object.
//
// Deprecated: use Reader.Attrs.CacheControl.
func (r *Reader) CacheControl() string { func (r *Reader) CacheControl() string {
return r.cacheControl 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
} }

View File

@ -1,4 +1,4 @@
// Copyright 2014 Google Inc. All Rights Reserved. // Copyright 2014 Google LLC
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@ -16,6 +16,7 @@ package storage
import ( import (
"bytes" "bytes"
"context"
"crypto" "crypto"
"crypto/rand" "crypto/rand"
"crypto/rsa" "crypto/rsa"
@ -25,28 +26,29 @@ import (
"encoding/pem" "encoding/pem"
"errors" "errors"
"fmt" "fmt"
"io"
"io/ioutil"
"net/http" "net/http"
"net/url" "net/url"
"reflect" "reflect"
"regexp"
"sort"
"strconv" "strconv"
"strings" "strings"
"time" "time"
"unicode/utf8" "unicode/utf8"
"google.golang.org/api/option"
htransport "google.golang.org/api/transport/http"
"cloud.google.com/go/internal/optional" "cloud.google.com/go/internal/optional"
"cloud.google.com/go/internal/trace"
"cloud.google.com/go/internal/version" "cloud.google.com/go/internal/version"
"golang.org/x/net/context"
"google.golang.org/api/googleapi" "google.golang.org/api/googleapi"
"google.golang.org/api/option"
raw "google.golang.org/api/storage/v1" raw "google.golang.org/api/storage/v1"
htransport "google.golang.org/api/transport/http"
) )
var ( var (
// ErrBucketNotExist indicates that the bucket does not exist.
ErrBucketNotExist = errors.New("storage: bucket doesn't exist") ErrBucketNotExist = errors.New("storage: bucket doesn't exist")
// ErrObjectNotExist indicates that the object does not exist.
ErrObjectNotExist = errors.New("storage: object doesn't exist") ErrObjectNotExist = errors.New("storage: object doesn't exist")
) )
@ -110,8 +112,7 @@ func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error
// //
// Close need not be called at program exit. // Close need not be called at program exit.
func (c *Client) Close() error { func (c *Client) Close() error {
// Set fields to nil so that subsequent uses // Set fields to nil so that subsequent uses will panic.
// will panic.
c.hc = nil c.hc = nil
c.raw = nil c.raw = nil
return nil return nil
@ -170,7 +171,7 @@ type SignedURLOptions struct {
// Optional. // Optional.
ContentType string ContentType string
// Headers is a list of extention headers the client must provide // Headers is a list of extension headers the client must provide
// in order to use the generated signed URL. // in order to use the generated signed URL.
// Optional. // Optional.
Headers []string Headers []string
@ -182,6 +183,60 @@ type SignedURLOptions struct {
MD5 string MD5 string
} }
var (
canonicalHeaderRegexp = regexp.MustCompile(`(?i)^(x-goog-[^:]+):(.*)?$`)
excludedCanonicalHeaders = map[string]bool{
"x-goog-encryption-key": true,
"x-goog-encryption-key-sha256": true,
}
)
// sanitizeHeaders applies the specifications for canonical extension headers at
// https://cloud.google.com/storage/docs/access-control/signed-urls#about-canonical-extension-headers.
func sanitizeHeaders(hdrs []string) []string {
headerMap := map[string][]string{}
for _, hdr := range hdrs {
// No leading or trailing whitespaces.
sanitizedHeader := strings.TrimSpace(hdr)
// Only keep canonical headers, discard any others.
headerMatches := canonicalHeaderRegexp.FindStringSubmatch(sanitizedHeader)
if len(headerMatches) == 0 {
continue
}
header := strings.ToLower(strings.TrimSpace(headerMatches[1]))
if excludedCanonicalHeaders[headerMatches[1]] {
// Do not keep any deliberately excluded canonical headers when signing.
continue
}
value := strings.TrimSpace(headerMatches[2])
if len(value) > 0 {
// Remove duplicate headers by appending the values of duplicates
// in their order of appearance.
headerMap[header] = append(headerMap[header], value)
}
}
var sanitizedHeaders []string
for header, values := range headerMap {
// There should be no spaces around the colon separating the
// header name from the header value or around the values
// themselves. The values should be separated by commas.
// NOTE: The semantics for headers without a value are not clear.
// However from specifications these should be edge-cases
// anyway and we should assume that there will be no
// canonical headers using empty values. Any such headers
// are discarded at the regexp stage above.
sanitizedHeaders = append(
sanitizedHeaders,
fmt.Sprintf("%s:%s", header, strings.Join(values, ",")),
)
}
sort.Strings(sanitizedHeaders)
return sanitizedHeaders
}
// SignedURL returns a URL for the specified object. Signed URLs allow // SignedURL returns a URL for the specified object. Signed URLs allow
// the users access to a restricted resource for a limited time without having a // the users access to a restricted resource for a limited time without having a
// Google account or signing in. For more information about the signed // Google account or signing in. For more information about the signed
@ -208,6 +263,7 @@ func SignedURL(bucket, name string, opts *SignedURLOptions) (string, error) {
return "", errors.New("storage: invalid MD5 checksum") return "", errors.New("storage: invalid MD5 checksum")
} }
} }
opts.Headers = sanitizeHeaders(opts.Headers)
signBytes := opts.SignBytes signBytes := opts.SignBytes
if opts.PrivateKey != nil { if opts.PrivateKey != nil {
@ -258,14 +314,15 @@ func SignedURL(bucket, name string, opts *SignedURLOptions) (string, error) {
// ObjectHandle provides operations on an object in a Google Cloud Storage bucket. // ObjectHandle provides operations on an object in a Google Cloud Storage bucket.
// Use BucketHandle.Object to get a handle. // Use BucketHandle.Object to get a handle.
type ObjectHandle struct { type ObjectHandle struct {
c *Client c *Client
bucket string bucket string
object string object string
acl ACLHandle acl ACLHandle
gen int64 // a negative value indicates latest gen int64 // a negative value indicates latest
conds *Conditions conds *Conditions
encryptionKey []byte // AES-256 key encryptionKey []byte // AES-256 key
userProject string // for requester-pays buckets userProject string // for requester-pays buckets
readCompressed bool // Accept-Encoding: gzip
} }
// ACL provides access to the object's access control list. // ACL provides access to the object's access control list.
@ -288,7 +345,7 @@ func (o *ObjectHandle) Generation(gen int64) *ObjectHandle {
// If returns a new ObjectHandle that applies a set of preconditions. // If returns a new ObjectHandle that applies a set of preconditions.
// Preconditions already set on the ObjectHandle are ignored. // Preconditions already set on the ObjectHandle are ignored.
// Operations on the new handle will only occur if the preconditions are // Operations on the new handle will return an error if the preconditions are not
// satisfied. See https://cloud.google.com/storage/docs/generations-preconditions // satisfied. See https://cloud.google.com/storage/docs/generations-preconditions
// for more details. // for more details.
func (o *ObjectHandle) If(conds Conditions) *ObjectHandle { func (o *ObjectHandle) If(conds Conditions) *ObjectHandle {
@ -310,7 +367,10 @@ func (o *ObjectHandle) Key(encryptionKey []byte) *ObjectHandle {
// Attrs returns meta information about the object. // Attrs returns meta information about the object.
// ErrObjectNotExist will be returned if the object is not found. // ErrObjectNotExist will be returned if the object is not found.
func (o *ObjectHandle) Attrs(ctx context.Context) (*ObjectAttrs, error) { func (o *ObjectHandle) Attrs(ctx context.Context) (attrs *ObjectAttrs, err error) {
ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Object.Attrs")
defer func() { trace.EndSpan(ctx, err) }()
if err := o.validate(); err != nil { if err := o.validate(); err != nil {
return nil, err return nil, err
} }
@ -325,7 +385,6 @@ func (o *ObjectHandle) Attrs(ctx context.Context) (*ObjectAttrs, error) {
return nil, err return nil, err
} }
var obj *raw.Object var obj *raw.Object
var err error
setClientHeader(call.Header()) setClientHeader(call.Header())
err = runWithRetry(ctx, func() error { obj, err = call.Do(); return err }) err = runWithRetry(ctx, func() error { obj, err = call.Do(); return err })
if e, ok := err.(*googleapi.Error); ok && e.Code == http.StatusNotFound { if e, ok := err.(*googleapi.Error); ok && e.Code == http.StatusNotFound {
@ -340,7 +399,10 @@ func (o *ObjectHandle) Attrs(ctx context.Context) (*ObjectAttrs, error) {
// Update updates an object with the provided attributes. // Update updates an object with the provided attributes.
// All zero-value attributes are ignored. // All zero-value attributes are ignored.
// ErrObjectNotExist will be returned if the object is not found. // ErrObjectNotExist will be returned if the object is not found.
func (o *ObjectHandle) Update(ctx context.Context, uattrs ObjectAttrsToUpdate) (*ObjectAttrs, error) { func (o *ObjectHandle) Update(ctx context.Context, uattrs ObjectAttrsToUpdate) (oa *ObjectAttrs, err error) {
ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Object.Update")
defer func() { trace.EndSpan(ctx, err) }()
if err := o.validate(); err != nil { if err := o.validate(); err != nil {
return nil, err return nil, err
} }
@ -379,6 +441,14 @@ func (o *ObjectHandle) Update(ctx context.Context, uattrs ObjectAttrsToUpdate) (
attrs.CacheControl = optional.ToString(uattrs.CacheControl) attrs.CacheControl = optional.ToString(uattrs.CacheControl)
forceSendFields = append(forceSendFields, "CacheControl") forceSendFields = append(forceSendFields, "CacheControl")
} }
if uattrs.EventBasedHold != nil {
attrs.EventBasedHold = optional.ToBool(uattrs.EventBasedHold)
forceSendFields = append(forceSendFields, "EventBasedHold")
}
if uattrs.TemporaryHold != nil {
attrs.TemporaryHold = optional.ToBool(uattrs.TemporaryHold)
forceSendFields = append(forceSendFields, "TemporaryHold")
}
if uattrs.Metadata != nil { if uattrs.Metadata != nil {
attrs.Metadata = uattrs.Metadata attrs.Metadata = uattrs.Metadata
if len(attrs.Metadata) == 0 { if len(attrs.Metadata) == 0 {
@ -404,11 +474,13 @@ func (o *ObjectHandle) Update(ctx context.Context, uattrs ObjectAttrsToUpdate) (
if o.userProject != "" { if o.userProject != "" {
call.UserProject(o.userProject) call.UserProject(o.userProject)
} }
if uattrs.PredefinedACL != "" {
call.PredefinedAcl(uattrs.PredefinedACL)
}
if err := setEncryptionHeaders(call.Header(), o.encryptionKey, false); err != nil { if err := setEncryptionHeaders(call.Header(), o.encryptionKey, false); err != nil {
return nil, err return nil, err
} }
var obj *raw.Object var obj *raw.Object
var err error
setClientHeader(call.Header()) setClientHeader(call.Header())
err = runWithRetry(ctx, func() error { obj, err = call.Do(); return err }) err = runWithRetry(ctx, func() error { obj, err = call.Do(); return err })
if e, ok := err.(*googleapi.Error); ok && e.Code == http.StatusNotFound { if e, ok := err.(*googleapi.Error); ok && e.Code == http.StatusNotFound {
@ -420,6 +492,16 @@ func (o *ObjectHandle) Update(ctx context.Context, uattrs ObjectAttrsToUpdate) (
return newObject(obj), nil return newObject(obj), nil
} }
// BucketName returns the name of the bucket.
func (o *ObjectHandle) BucketName() string {
return o.bucket
}
// ObjectName returns the name of the object.
func (o *ObjectHandle) ObjectName() string {
return o.object
}
// ObjectAttrsToUpdate is used to update the attributes of an object. // ObjectAttrsToUpdate is used to update the attributes of an object.
// Only fields set to non-nil values will be updated. // Only fields set to non-nil values will be updated.
// Set a field to its zero value to delete it. // Set a field to its zero value to delete it.
@ -432,6 +514,8 @@ func (o *ObjectHandle) Update(ctx context.Context, uattrs ObjectAttrsToUpdate) (
// Metadata: map[string]string{}, // Metadata: map[string]string{},
// } // }
type ObjectAttrsToUpdate struct { type ObjectAttrsToUpdate struct {
EventBasedHold optional.Bool
TemporaryHold optional.Bool
ContentType optional.String ContentType optional.String
ContentLanguage optional.String ContentLanguage optional.String
ContentEncoding optional.String ContentEncoding optional.String
@ -439,6 +523,10 @@ type ObjectAttrsToUpdate struct {
CacheControl optional.String CacheControl optional.String
Metadata map[string]string // set to map[string]string{} to delete Metadata map[string]string // set to map[string]string{} to delete
ACL []ACLRule ACL []ACLRule
// If not empty, applies a predefined set of access controls. ACL must be nil.
// See https://cloud.google.com/storage/docs/json_api/v1/objects/patch.
PredefinedACL string
} }
// Delete deletes the single specified object. // Delete deletes the single specified object.
@ -467,140 +555,13 @@ func (o *ObjectHandle) Delete(ctx context.Context) error {
return err return err
} }
// NewReader creates a new Reader to read the contents of the // ReadCompressed when true causes the read to happen without decompressing.
// object. func (o *ObjectHandle) ReadCompressed(compressed bool) *ObjectHandle {
// ErrObjectNotExist will be returned if the object is not found. o2 := *o
// o2.readCompressed = compressed
// The caller must call Close on the returned Reader when done reading. return &o2
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.
func (o *ObjectHandle) NewRangeReader(ctx context.Context, offset, length int64) (*Reader, error) {
if err := o.validate(); err != nil {
return nil, err
}
if offset < 0 {
return nil, fmt.Errorf("storage: invalid offset %d < 0", offset)
}
if o.conds != nil {
if err := o.conds.validate("NewRangeReader"); err != nil {
return nil, err
}
}
u := &url.URL{
Scheme: "https",
Host: "storage.googleapis.com",
Path: fmt.Sprintf("/%s/%s", o.bucket, o.object),
RawQuery: conditionsQuery(o.gen, o.conds),
}
verb := "GET"
if length == 0 {
verb = "HEAD"
}
req, err := http.NewRequest(verb, u.String(), nil)
if err != nil {
return nil, err
}
req = withContext(req, ctx)
if length < 0 && offset > 0 {
req.Header.Set("Range", fmt.Sprintf("bytes=%d-", offset))
} else if length > 0 {
req.Header.Set("Range", fmt.Sprintf("bytes=%d-%d", offset, offset+length-1))
}
if o.userProject != "" {
req.Header.Set("X-Goog-User-Project", o.userProject)
}
if err := setEncryptionHeaders(req.Header, o.encryptionKey, false); err != nil {
return nil, err
}
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),
}
}
if offset > 0 && length != 0 && res.StatusCode != http.StatusPartialContent {
res.Body.Close()
return errors.New("storage: partial request not satisfied")
}
return nil
})
if err != nil {
return nil, err
}
var size int64 // total size of object, even if a range was requested.
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)
}
} else {
size = res.ContentLength
}
remain := res.ContentLength
body := res.Body
if length == 0 {
remain = 0
body.Close()
body = emptyBody
}
var (
checkCRC bool
crc uint32
)
// Even if there is a CRC header, we can't compute the hash on partial data.
if remain == size {
crc, checkCRC = parseCRC32c(res)
}
return &Reader{
body: body,
size: size,
remain: remain,
contentType: res.Header.Get("Content-Type"),
cacheControl: res.Header.Get("Cache-Control"),
wantCRC: crc,
checkCRC: checkCRC,
}, nil
}
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(""))
// NewWriter returns a storage Writer that writes to the GCS object // NewWriter returns a storage Writer that writes to the GCS object
// associated with this ObjectHandle. // associated with this ObjectHandle.
// //
@ -614,7 +575,8 @@ var emptyBody = ioutil.NopCloser(strings.NewReader(""))
// attribute is specified, the content type will be automatically sniffed // attribute is specified, the content type will be automatically sniffed
// using net/http.DetectContentType. // using net/http.DetectContentType.
// //
// It is the caller's responsibility to call Close when writing is done. // It is the caller's responsibility to call Close when writing is done. To
// stop writing without saving the data, cancel the context.
func (o *ObjectHandle) NewWriter(ctx context.Context) *Writer { func (o *ObjectHandle) NewWriter(ctx context.Context) *Writer {
return &Writer{ return &Writer{
ctx: ctx, ctx: ctx,
@ -638,11 +600,10 @@ func (o *ObjectHandle) validate() error {
return nil return nil
} }
// parseKey converts the binary contents of a private key file // parseKey converts the binary contents of a private key file to an
// to an *rsa.PrivateKey. It detects whether the private key is in a // *rsa.PrivateKey. It detects whether the private key is in a PEM container or
// PEM container or not. If so, it extracts the the private key // not. If so, it extracts the private key from PEM container before
// from PEM container before conversion. It only supports PEM // conversion. It only supports PEM containers with no passphrase.
// containers with no passphrase.
func parseKey(key []byte) (*rsa.PrivateKey, error) { func parseKey(key []byte) (*rsa.PrivateKey, error) {
if block, _ := pem.Decode(key); block != nil { if block, _ := pem.Decode(key); block != nil {
key = block.Bytes key = block.Bytes
@ -661,34 +622,26 @@ func parseKey(key []byte) (*rsa.PrivateKey, error) {
return parsed, nil return parsed, nil
} }
func toRawObjectACL(oldACL []ACLRule) []*raw.ObjectAccessControl {
var acl []*raw.ObjectAccessControl
if len(oldACL) > 0 {
acl = make([]*raw.ObjectAccessControl, len(oldACL))
for i, rule := range oldACL {
acl[i] = &raw.ObjectAccessControl{
Entity: string(rule.Entity),
Role: string(rule.Role),
}
}
}
return acl
}
// toRawObject copies the editable attributes from o to the raw library's Object type. // toRawObject copies the editable attributes from o to the raw library's Object type.
func (o *ObjectAttrs) toRawObject(bucket string) *raw.Object { func (o *ObjectAttrs) toRawObject(bucket string) *raw.Object {
acl := toRawObjectACL(o.ACL) var ret string
if !o.RetentionExpirationTime.IsZero() {
ret = o.RetentionExpirationTime.Format(time.RFC3339)
}
return &raw.Object{ return &raw.Object{
Bucket: bucket, Bucket: bucket,
Name: o.Name, Name: o.Name,
ContentType: o.ContentType, EventBasedHold: o.EventBasedHold,
ContentEncoding: o.ContentEncoding, TemporaryHold: o.TemporaryHold,
ContentLanguage: o.ContentLanguage, RetentionExpirationTime: ret,
CacheControl: o.CacheControl, ContentType: o.ContentType,
ContentDisposition: o.ContentDisposition, ContentEncoding: o.ContentEncoding,
StorageClass: o.StorageClass, ContentLanguage: o.ContentLanguage,
Acl: acl, CacheControl: o.CacheControl,
Metadata: o.Metadata, ContentDisposition: o.ContentDisposition,
StorageClass: o.StorageClass,
Acl: toRawObjectACL(o.ACL),
Metadata: o.Metadata,
} }
} }
@ -712,9 +665,32 @@ type ObjectAttrs struct {
// headers when serving the object data. // headers when serving the object data.
CacheControl string CacheControl string
// EventBasedHold specifies whether an object is under event-based hold. New
// objects created in a bucket whose DefaultEventBasedHold is set will
// default to that value.
EventBasedHold bool
// TemporaryHold specifies whether an object is under temporary hold. While
// this flag is set to true, the object is protected against deletion and
// overwrites.
TemporaryHold bool
// RetentionExpirationTime is a server-determined value that specifies the
// earliest time that the object's retention period expires.
// This is a read-only field.
RetentionExpirationTime time.Time
// ACL is the list of access control rules for the object. // ACL is the list of access control rules for the object.
ACL []ACLRule ACL []ACLRule
// If not empty, applies a predefined set of access controls. It should be set
// only when writing, copying or composing an object. When copying or composing,
// it acts as the destinationPredefinedAcl parameter.
// PredefinedACL is always empty for ObjectAttrs returned from the service.
// See https://cloud.google.com/storage/docs/json_api/v1/objects/insert
// for valid values.
PredefinedACL string
// Owner is the owner of the object. This field is read-only. // Owner is the owner of the object. This field is read-only.
// //
// If non-zero, it is in the form of "user-<userId>". // If non-zero, it is in the form of "user-<userId>".
@ -788,6 +764,14 @@ type ObjectAttrs struct {
// encryption in Google Cloud Storage. // encryption in Google Cloud Storage.
CustomerKeySHA256 string CustomerKeySHA256 string
// Cloud KMS key name, in the form
// projects/P/locations/L/keyRings/R/cryptoKeys/K, used to encrypt this object,
// if the object is encrypted by such a key.
//
// Providing both a KMSKeyName and a customer-supplied encryption key (via
// ObjectHandle.Key) will result in an error when writing an object.
KMSKeyName string
// Prefix is set only for ObjectAttrs which represent synthetic "directory // Prefix is set only for ObjectAttrs which represent synthetic "directory
// entries" when iterating over buckets using Query.Delimiter. See // entries" when iterating over buckets using Query.Delimiter. See
// ObjectIterator.Next. When set, no other fields in ObjectAttrs will be // ObjectIterator.Next. When set, no other fields in ObjectAttrs will be
@ -809,13 +793,6 @@ func newObject(o *raw.Object) *ObjectAttrs {
if o == nil { if o == nil {
return nil return nil
} }
acl := make([]ACLRule, len(o.Acl))
for i, rule := range o.Acl {
acl[i] = ACLRule{
Entity: ACLEntity(rule.Entity),
Role: ACLRole(rule.Role),
}
}
owner := "" owner := ""
if o.Owner != nil { if o.Owner != nil {
owner = o.Owner.Entity owner = o.Owner.Entity
@ -827,27 +804,31 @@ func newObject(o *raw.Object) *ObjectAttrs {
sha256 = o.CustomerEncryption.KeySha256 sha256 = o.CustomerEncryption.KeySha256
} }
return &ObjectAttrs{ return &ObjectAttrs{
Bucket: o.Bucket, Bucket: o.Bucket,
Name: o.Name, Name: o.Name,
ContentType: o.ContentType, ContentType: o.ContentType,
ContentLanguage: o.ContentLanguage, ContentLanguage: o.ContentLanguage,
CacheControl: o.CacheControl, CacheControl: o.CacheControl,
ACL: acl, EventBasedHold: o.EventBasedHold,
Owner: owner, TemporaryHold: o.TemporaryHold,
ContentEncoding: o.ContentEncoding, RetentionExpirationTime: convertTime(o.RetentionExpirationTime),
ContentDisposition: o.ContentDisposition, ACL: toObjectACLRules(o.Acl),
Size: int64(o.Size), Owner: owner,
MD5: md5, ContentEncoding: o.ContentEncoding,
CRC32C: crc32c, ContentDisposition: o.ContentDisposition,
MediaLink: o.MediaLink, Size: int64(o.Size),
Metadata: o.Metadata, MD5: md5,
Generation: o.Generation, CRC32C: crc32c,
Metageneration: o.Metageneration, MediaLink: o.MediaLink,
StorageClass: o.StorageClass, Metadata: o.Metadata,
CustomerKeySHA256: sha256, Generation: o.Generation,
Created: convertTime(o.TimeCreated), Metageneration: o.Metageneration,
Deleted: convertTime(o.TimeDeleted), StorageClass: o.StorageClass,
Updated: convertTime(o.Updated), CustomerKeySHA256: sha256,
KMSKeyName: o.KmsKeyName,
Created: convertTime(o.TimeCreated),
Deleted: convertTime(o.TimeDeleted),
Updated: convertTime(o.Updated),
} }
} }
@ -890,17 +871,6 @@ type Query struct {
Versions bool Versions bool
} }
// contentTyper implements ContentTyper to enable an
// io.ReadCloser to specify its MIME type.
type contentTyper struct {
io.Reader
t string
}
func (c *contentTyper) ContentType() string {
return c.t
}
// Conditions constrain methods to act on specific generations of // Conditions constrain methods to act on specific generations of
// objects. // objects.
// //
@ -1130,4 +1100,12 @@ func setEncryptionHeaders(headers http.Header, key []byte, copySource bool) erro
return nil return nil
} }
// TODO(jbd): Add storage.objects.watch. // ServiceAccount fetches the email address of the given project's Google Cloud Storage service account.
func (c *Client) ServiceAccount(ctx context.Context, projectID string) (string, error) {
r := c.raw.Projects.ServiceAccount.Get(projectID)
res, err := r.Context(ctx).Do()
if err != nil {
return "", err
}
return res.EmailAddress, nil
}

24957
vendor/cloud.google.com/go/storage/storage.replay generated vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
// Copyright 2014 Google Inc. All Rights Reserved. // Copyright 2014 Google LLC
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@ -15,13 +15,14 @@
package storage package storage
import ( import (
"context"
"encoding/base64" "encoding/base64"
"errors" "errors"
"fmt" "fmt"
"io" "io"
"sync"
"unicode/utf8" "unicode/utf8"
"golang.org/x/net/context"
"google.golang.org/api/googleapi" "google.golang.org/api/googleapi"
raw "google.golang.org/api/storage/v1" raw "google.golang.org/api/storage/v1"
) )
@ -47,8 +48,11 @@ type Writer struct {
// to the nearest multiple of 256K. If zero, chunking will be disabled and // to the nearest multiple of 256K. If zero, chunking will be disabled and
// the object will be uploaded in a single request. // the object will be uploaded in a single request.
// //
// ChunkSize will default to a reasonable value. Any custom configuration // ChunkSize will default to a reasonable value. If you perform many concurrent
// must be done before the first Write call. // writes of small objects, you may wish set ChunkSize to a value that matches
// your objects' sizes to avoid consuming large amounts of memory.
//
// ChunkSize must be set before the first Write call.
ChunkSize int ChunkSize int
// ProgressFunc can be used to monitor the progress of a large write. // ProgressFunc can be used to monitor the progress of a large write.
@ -68,8 +72,10 @@ type Writer struct {
pw *io.PipeWriter pw *io.PipeWriter
donec chan struct{} // closed after err and obj are set. donec chan struct{} // closed after err and obj are set.
err error
obj *ObjectAttrs obj *ObjectAttrs
mu sync.Mutex
err error
} }
func (w *Writer) open() error { func (w *Writer) open() error {
@ -82,10 +88,15 @@ func (w *Writer) open() error {
if !utf8.ValidString(attrs.Name) { if !utf8.ValidString(attrs.Name) {
return fmt.Errorf("storage: object name %q is not valid UTF-8", 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() pr, pw := io.Pipe()
w.pw = pw w.pw = pw
w.opened = true w.opened = true
go w.monitorCancel()
if w.ChunkSize < 0 { if w.ChunkSize < 0 {
return errors.New("storage: Writer.ChunkSize must be non-negative") return errors.New("storage: Writer.ChunkSize must be non-negative")
} }
@ -113,9 +124,17 @@ func (w *Writer) open() error {
if w.ProgressFunc != nil { if w.ProgressFunc != nil {
call.ProgressUpdater(func(n, _ int64) { w.ProgressFunc(n) }) 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 { if err := setEncryptionHeaders(call.Header(), w.o.encryptionKey, false); err != nil {
w.mu.Lock()
w.err = err w.err = err
pr.CloseWithError(w.err) w.mu.Unlock()
pr.CloseWithError(err)
return return
} }
var resp *raw.Object var resp *raw.Object
@ -142,8 +161,10 @@ func (w *Writer) open() error {
} }
} }
if err != nil { if err != nil {
w.mu.Lock()
w.err = err w.err = err
pr.CloseWithError(w.err) w.mu.Unlock()
pr.CloseWithError(err)
return return
} }
w.obj = newObject(resp) w.obj = newObject(resp)
@ -158,15 +179,30 @@ func (w *Writer) open() error {
// use the error returned from Writer.Close to determine if // use the error returned from Writer.Close to determine if
// the upload was successful. // the upload was successful.
func (w *Writer) Write(p []byte) (n int, err error) { func (w *Writer) Write(p []byte) (n int, err error) {
if w.err != nil { w.mu.Lock()
return 0, w.err werr := w.err
w.mu.Unlock()
if werr != nil {
return 0, werr
} }
if !w.opened { if !w.opened {
if err := w.open(); err != nil { if err := w.open(); err != nil {
return 0, err return 0, err
} }
} }
return w.pw.Write(p) 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. // Close completes the write operation and flushes any buffered data.
@ -178,15 +214,39 @@ func (w *Writer) Close() error {
return err return err
} }
} }
// Closing either the read or write causes the entire pipe to close.
if err := w.pw.Close(); err != nil { if err := w.pw.Close(); err != nil {
return err return err
} }
<-w.donec <-w.donec
w.mu.Lock()
defer w.mu.Unlock()
return w.err return w.err
} }
// monitorCancel is intended to be used as a background goroutine. It monitors the
// 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 aborts the write operation with the provided error.
// CloseWithError always returns nil. // CloseWithError always returns nil.
//
// Deprecated: cancel the context passed to NewWriter instead.
func (w *Writer) CloseWithError(err error) error { func (w *Writer) CloseWithError(err error) error {
if !w.opened { if !w.opened {
return nil return nil

View File

@ -1 +0,0 @@
*.cover

View File

@ -1,15 +0,0 @@
sudo: false
language: go
go:
- 1.6
- 1.7
before_install:
- go get golang.org/x/tools/cmd/cover
- go get golang.org/x/tools/cmd/goimports
script:
- gofmt -l .
- goimports -l .
- go tool vet .
- go test -coverprofile=coverage.txt -covermode=atomic
after_success:
- bash <(curl -s https://codecov.io/bash)

View File

@ -1,27 +0,0 @@
Want to contribute? Great! First, read this page (including the small print at the end).
### Before you contribute
Before we can use your code, you must sign the
[Google Individual Contributor License Agreement]
(https://cla.developers.google.com/about/google-individual)
(CLA), which you can do online. The CLA is necessary mainly because you own the
copyright to your changes, even after your contribution becomes part of our
codebase, so we need your permission to use and distribute your code. We also
need to be sure of various other things—for instance that you'll tell us if you
know that your code infringes on other people's patents. You don't have to sign
the CLA until after you've submitted your code for review and a member has
approved it, but you must do it before we can put your code into our codebase.
Before you start working on a larger contribution, you should get in touch with
us first through the issue tracker with your idea so that we can help out and
possibly guide you. Coordinating up front makes it much easier to avoid
frustration later on.
### Code reviews
All submissions, including submissions by project members, require review. We
use Github pull requests for this purpose.
### The small print
Contributions made by corporations are covered by a different agreement than
the one above, the
[Software Grant and Corporate Contributor License Agreement]
(https://cla.developers.google.com/about/google-corporate).

View File

@ -1,24 +0,0 @@
Google API Extensions for Go
============================
[![Build Status](https://travis-ci.org/googleapis/gax-go.svg?branch=master)](https://travis-ci.org/googleapis/gax-go)
[![Code Coverage](https://img.shields.io/codecov/c/github/googleapis/gax-go.svg)](https://codecov.io/github/googleapis/gax-go)
Google API Extensions for Go (gax-go) is a set of modules which aids the
development of APIs for clients and servers based on `gRPC` and Google API
conventions.
Application code will rarely need to use this library directly,
but the code generated automatically from API definition files can use it
to simplify code generation and to provide more convenient and idiomatic API surface.
**This project is currently experimental and not supported.**
Go Versions
===========
This library requires Go 1.6 or above.
License
=======
BSD - please see [LICENSE](https://github.com/googleapis/gax-go/blob/master/LICENSE)
for more information.

View File

@ -1,176 +0,0 @@
// Copyright 2016, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package gax
import (
"errors"
"fmt"
"strings"
)
type matcher interface {
match([]string) (int, error)
String() string
}
type segment struct {
matcher
name string
}
type labelMatcher string
func (ls labelMatcher) match(segments []string) (int, error) {
if len(segments) == 0 {
return 0, fmt.Errorf("expected %s but no more segments found", ls)
}
if segments[0] != string(ls) {
return 0, fmt.Errorf("expected %s but got %s", ls, segments[0])
}
return 1, nil
}
func (ls labelMatcher) String() string {
return string(ls)
}
type wildcardMatcher int
func (wm wildcardMatcher) match(segments []string) (int, error) {
if len(segments) == 0 {
return 0, errors.New("no more segments found")
}
return 1, nil
}
func (wm wildcardMatcher) String() string {
return "*"
}
type pathWildcardMatcher int
func (pwm pathWildcardMatcher) match(segments []string) (int, error) {
length := len(segments) - int(pwm)
if length <= 0 {
return 0, errors.New("not sufficient segments are supplied for path wildcard")
}
return length, nil
}
func (pwm pathWildcardMatcher) String() string {
return "**"
}
type ParseError struct {
Pos int
Template string
Message string
}
func (pe ParseError) Error() string {
return fmt.Sprintf("at %d of template '%s', %s", pe.Pos, pe.Template, pe.Message)
}
// PathTemplate manages the template to build and match with paths used
// by API services. It holds a template and variable names in it, and
// it can extract matched patterns from a path string or build a path
// string from a binding.
//
// See http.proto in github.com/googleapis/googleapis/ for the details of
// the template syntax.
type PathTemplate struct {
segments []segment
}
// NewPathTemplate parses a path template, and returns a PathTemplate
// instance if successful.
func NewPathTemplate(template string) (*PathTemplate, error) {
return parsePathTemplate(template)
}
// MustCompilePathTemplate is like NewPathTemplate but panics if the
// expression cannot be parsed. It simplifies safe initialization of
// global variables holding compiled regular expressions.
func MustCompilePathTemplate(template string) *PathTemplate {
pt, err := NewPathTemplate(template)
if err != nil {
panic(err)
}
return pt
}
// Match attempts to match the given path with the template, and returns
// the mapping of the variable name to the matched pattern string.
func (pt *PathTemplate) Match(path string) (map[string]string, error) {
paths := strings.Split(path, "/")
values := map[string]string{}
for _, segment := range pt.segments {
length, err := segment.match(paths)
if err != nil {
return nil, err
}
if segment.name != "" {
value := strings.Join(paths[:length], "/")
if oldValue, ok := values[segment.name]; ok {
values[segment.name] = oldValue + "/" + value
} else {
values[segment.name] = value
}
}
paths = paths[length:]
}
if len(paths) != 0 {
return nil, fmt.Errorf("Trailing path %s remains after the matching", strings.Join(paths, "/"))
}
return values, nil
}
// Render creates a path string from its template and the binding from
// the variable name to the value.
func (pt *PathTemplate) Render(binding map[string]string) (string, error) {
result := make([]string, 0, len(pt.segments))
var lastVariableName string
for _, segment := range pt.segments {
name := segment.name
if lastVariableName != "" && name == lastVariableName {
continue
}
lastVariableName = name
if name == "" {
result = append(result, segment.String())
} else if value, ok := binding[name]; ok {
result = append(result, value)
} else {
return "", fmt.Errorf("%s is not found", name)
}
}
built := strings.Join(result, "/")
return built, nil
}

View File

@ -1,227 +0,0 @@
// Copyright 2016, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package gax
import (
"fmt"
"io"
"strings"
)
// This parser follows the syntax of path templates, from
// https://github.com/googleapis/googleapis/blob/master/google/api/http.proto.
// The differences are that there is no custom verb, we allow the initial slash
// to be absent, and that we are not strict as
// https://tools.ietf.org/html/rfc6570 about the characters in identifiers and
// literals.
type pathTemplateParser struct {
r *strings.Reader
runeCount int // the number of the current rune in the original string
nextVar int // the number to use for the next unnamed variable
seenName map[string]bool // names we've seen already
seenPathWildcard bool // have we seen "**" already?
}
func parsePathTemplate(template string) (pt *PathTemplate, err error) {
p := &pathTemplateParser{
r: strings.NewReader(template),
seenName: map[string]bool{},
}
// Handle panics with strings like errors.
// See pathTemplateParser.error, below.
defer func() {
if x := recover(); x != nil {
errmsg, ok := x.(errString)
if !ok {
panic(x)
}
pt = nil
err = ParseError{p.runeCount, template, string(errmsg)}
}
}()
segs := p.template()
// If there is a path wildcard, set its length. We can't do this
// until we know how many segments we've got all together.
for i, seg := range segs {
if _, ok := seg.matcher.(pathWildcardMatcher); ok {
segs[i].matcher = pathWildcardMatcher(len(segs) - i - 1)
break
}
}
return &PathTemplate{segments: segs}, nil
}
// Used to indicate errors "thrown" by this parser. We don't use string because
// many parts of the standard library panic with strings.
type errString string
// Terminates parsing immediately with an error.
func (p *pathTemplateParser) error(msg string) {
panic(errString(msg))
}
// Template = [ "/" ] Segments
func (p *pathTemplateParser) template() []segment {
var segs []segment
if p.consume('/') {
// Initial '/' needs an initial empty matcher.
segs = append(segs, segment{matcher: labelMatcher("")})
}
return append(segs, p.segments("")...)
}
// Segments = Segment { "/" Segment }
func (p *pathTemplateParser) segments(name string) []segment {
var segs []segment
for {
subsegs := p.segment(name)
segs = append(segs, subsegs...)
if !p.consume('/') {
break
}
}
return segs
}
// Segment = "*" | "**" | LITERAL | Variable
func (p *pathTemplateParser) segment(name string) []segment {
if p.consume('*') {
if name == "" {
name = fmt.Sprintf("$%d", p.nextVar)
p.nextVar++
}
if p.consume('*') {
if p.seenPathWildcard {
p.error("multiple '**' disallowed")
}
p.seenPathWildcard = true
// We'll change 0 to the right number at the end.
return []segment{{name: name, matcher: pathWildcardMatcher(0)}}
}
return []segment{{name: name, matcher: wildcardMatcher(0)}}
}
if p.consume('{') {
if name != "" {
p.error("recursive named bindings are not allowed")
}
return p.variable()
}
return []segment{{name: name, matcher: labelMatcher(p.literal())}}
}
// Variable = "{" FieldPath [ "=" Segments ] "}"
// "{" is already consumed.
func (p *pathTemplateParser) variable() []segment {
// Simplification: treat FieldPath as LITERAL, instead of IDENT { '.' IDENT }
name := p.literal()
if p.seenName[name] {
p.error(name + " appears multiple times")
}
p.seenName[name] = true
var segs []segment
if p.consume('=') {
segs = p.segments(name)
} else {
// "{var}" is equivalent to "{var=*}"
segs = []segment{{name: name, matcher: wildcardMatcher(0)}}
}
if !p.consume('}') {
p.error("expected '}'")
}
return segs
}
// A literal is any sequence of characters other than a few special ones.
// The list of stop characters is not quite the same as in the template RFC.
func (p *pathTemplateParser) literal() string {
lit := p.consumeUntil("/*}{=")
if lit == "" {
p.error("empty literal")
}
return lit
}
// Read runes until EOF or one of the runes in stopRunes is encountered.
// If the latter, unread the stop rune. Return the accumulated runes as a string.
func (p *pathTemplateParser) consumeUntil(stopRunes string) string {
var runes []rune
for {
r, ok := p.readRune()
if !ok {
break
}
if strings.IndexRune(stopRunes, r) >= 0 {
p.unreadRune()
break
}
runes = append(runes, r)
}
return string(runes)
}
// If the next rune is r, consume it and return true.
// Otherwise, leave the input unchanged and return false.
func (p *pathTemplateParser) consume(r rune) bool {
rr, ok := p.readRune()
if !ok {
return false
}
if r == rr {
return true
}
p.unreadRune()
return false
}
// Read the next rune from the input. Return it.
// The second return value is false at EOF.
func (p *pathTemplateParser) readRune() (rune, bool) {
r, _, err := p.r.ReadRune()
if err == io.EOF {
return r, false
}
if err != nil {
p.error(err.Error())
}
p.runeCount++
return r, true
}
// Put the last rune that was read back on the input.
func (p *pathTemplateParser) unreadRune() {
if err := p.r.UnreadRune(); err != nil {
p.error(err.Error())
}
p.runeCount--
}

View File

@ -35,6 +35,7 @@ import (
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
) )
// CallOption is an option used by Invoke to control behaviors of RPC calls. // CallOption is an option used by Invoke to control behaviors of RPC calls.
@ -80,7 +81,11 @@ type boRetryer struct {
} }
func (r *boRetryer) Retry(err error) (time.Duration, bool) { func (r *boRetryer) Retry(err error) (time.Duration, bool) {
c := grpc.Code(err) st, ok := status.FromError(err)
if !ok {
return 0, false
}
c := st.Code()
for _, rc := range r.codes { for _, rc := range r.codes {
if c == rc { if c == rc {
return r.backoff.Pause(), true return r.backoff.Pause(), true
@ -108,6 +113,7 @@ type Backoff struct {
cur time.Duration cur time.Duration
} }
// Pause returns the next time.Duration that the caller should use to backoff.
func (bo *Backoff) Pause() time.Duration { func (bo *Backoff) Pause() time.Duration {
if bo.Initial == 0 { if bo.Initial == 0 {
bo.Initial = time.Second bo.Initial = time.Second
@ -121,7 +127,11 @@ func (bo *Backoff) Pause() time.Duration {
if bo.Multiplier < 1 { if bo.Multiplier < 1 {
bo.Multiplier = 2 bo.Multiplier = 2
} }
d := time.Duration(rand.Int63n(int64(bo.cur))) // Select a duration between 1ns and the current max. It might seem
// counterintuitive to have so much jitter, but
// https://www.awsarchitectureblog.com/2015/03/backoff.html argues that
// that is the best strategy.
d := time.Duration(1 + rand.Int63n(int64(bo.cur)))
bo.cur = time.Duration(float64(bo.cur) * bo.Multiplier) bo.cur = time.Duration(float64(bo.cur) * bo.Multiplier)
if bo.cur > bo.Max { if bo.cur > bo.Max {
bo.cur = bo.Max bo.cur = bo.Max
@ -129,8 +139,23 @@ func (bo *Backoff) Pause() time.Duration {
return d return d
} }
type grpcOpt []grpc.CallOption
func (o grpcOpt) Resolve(s *CallSettings) {
s.GRPC = o
}
// WithGRPCOptions allows passing gRPC call options during client creation.
func WithGRPCOptions(opt ...grpc.CallOption) CallOption {
return grpcOpt(append([]grpc.CallOption(nil), opt...))
}
// CallSettings allow fine-grained control over how calls are made.
type CallSettings struct { type CallSettings struct {
// Retry returns a Retryer to be used to control retry logic of a method call. // Retry returns a Retryer to be used to control retry logic of a method call.
// If Retry is nil or the returned Retryer is nil, the call will not be retried. // If Retry is nil or the returned Retryer is nil, the call will not be retried.
Retry func() Retryer Retry func() Retryer
// CallOptions to be forwarded to GRPC.
GRPC []grpc.CallOption
} }

View File

@ -33,8 +33,7 @@
// Application code will rarely need to use this library directly. // Application code will rarely need to use this library directly.
// However, code generated automatically from API definition files can use it // However, code generated automatically from API definition files can use it
// to simplify code generation and to provide more convenient and idiomatic API surfaces. // to simplify code generation and to provide more convenient and idiomatic API surfaces.
//
// This project is currently experimental and not supported.
package gax package gax
const Version = "0.1.0" // Version specifies the gax-go version being used.
const Version = "2.0.3"

3
vendor/github.com/googleapis/gax-go/v2/go.mod generated vendored Normal file
View File

@ -0,0 +1,3 @@
module github.com/googleapis/gax-go/v2
require google.golang.org/grpc v1.16.0

26
vendor/github.com/googleapis/gax-go/v2/go.sum generated vendored Normal file
View File

@ -0,0 +1,26 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
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/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d h1:g9qWBGx4puODJTMVyoPrpoxPFgVGd+z1DZwjfRu4d0I=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522 h1:Ve1ORMCxvRmSXBwJK+t3Oy+V2vRW2OetUQBq4rJIkZE=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/grpc v1.16.0 h1:dz5IJGuC2BB7qXR5AyHNwAUBhZscK2xVez7mznh72sY=
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

53
vendor/github.com/googleapis/gax-go/v2/header.go generated vendored Normal file
View File

@ -0,0 +1,53 @@
// Copyright 2018, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package gax
import "bytes"
// XGoogHeader is for use by the Google Cloud Libraries only.
//
// XGoogHeader formats key-value pairs.
// The resulting string is suitable for x-goog-api-client header.
func XGoogHeader(keyval ...string) string {
if len(keyval) == 0 {
return ""
}
if len(keyval)%2 != 0 {
panic("gax.Header: odd argument count")
}
var buf bytes.Buffer
for i := 0; i < len(keyval); i += 2 {
buf.WriteByte(' ')
buf.WriteString(keyval[i])
buf.WriteByte('/')
buf.WriteString(keyval[i+1])
}
return buf.String()[1:]
}

View File

@ -30,13 +30,13 @@
package gax package gax
import ( import (
"context"
"strings"
"time" "time"
"golang.org/x/net/context"
) )
// A user defined call stub. // APICall is a user defined call stub.
type APICall func(context.Context) error type APICall func(context.Context, CallSettings) error
// Invoke calls the given APICall, // Invoke calls the given APICall,
// performing retries as specified by opts, if any. // performing retries as specified by opts, if any.
@ -67,13 +67,22 @@ type sleeper func(ctx context.Context, d time.Duration) error
func invoke(ctx context.Context, call APICall, settings CallSettings, sp sleeper) error { func invoke(ctx context.Context, call APICall, settings CallSettings, sp sleeper) error {
var retryer Retryer var retryer Retryer
for { for {
err := call(ctx) err := call(ctx, settings)
if err == nil { if err == nil {
return nil return nil
} }
if settings.Retry == nil { if settings.Retry == nil {
return err return err
} }
// Never retry permanent certificate errors. (e.x. if ca-certificates
// are not installed). We should only make very few, targeted
// exceptions: many (other) status=Unavailable should be retried, such
// as if there's a network hiccup, or the internet goes out for a
// minute. This is also why here we are doing string parsing instead of
// simply making Unavailable a non-retried code elsewhere.
if strings.Contains(err.Error(), "x509: certificate signed by unknown authority") {
return err
}
if retryer == nil { if retryer == nil {
if r := settings.Retry(); r != nil { if r := settings.Retry(); r != nil {
retryer = r retryer = r

View File

@ -2,7 +2,7 @@ language: go
go: go:
# 1.8 is tested by AppVeyor # 1.8 is tested by AppVeyor
- 1.10.x - 1.11.x
go_import_path: go.opencensus.io go_import_path: go.opencensus.io
@ -18,10 +18,10 @@ before_script:
script: script:
- embedmd -d README.md # Ensure embedded code is up-to-date - embedmd -d README.md # Ensure embedded code is up-to-date
- dep ensure -v
- go build ./... # Ensure dependency updates don't break build - go build ./... # Ensure dependency updates don't break build
- if [ -n "$(gofmt -s -l $GO_FILES)" ]; then echo "gofmt the following files:"; gofmt -s -l $GO_FILES; exit 1; fi - if [ -n "$(gofmt -s -l $GO_FILES)" ]; then echo "gofmt the following files:"; gofmt -s -l $GO_FILES; exit 1; fi
- go vet ./... - go vet ./...
- go test -v -race $PKGS # Run all the tests with the race detector enabled - go test -v -race $PKGS # Run all the tests with the race detector enabled
- GOARCH=386 go test -v $PKGS # Run all tests against a 386 architecture
- 'if [[ $TRAVIS_GO_VERSION = 1.8* ]]; then ! golint ./... | grep -vE "(_mock|_string|\.pb)\.go:"; fi' - 'if [[ $TRAVIS_GO_VERSION = 1.8* ]]; then ! golint ./... | grep -vE "(_mock|_string|\.pb)\.go:"; fi'
- go run internal/check/version.go - go run internal/check/version.go

17
vendor/go.opencensus.io/README.md generated vendored
View File

@ -7,7 +7,7 @@
OpenCensus Go is a Go implementation of OpenCensus, a toolkit for OpenCensus Go is a Go implementation of OpenCensus, a toolkit for
collecting application performance and behavior monitoring data. collecting application performance and behavior monitoring data.
Currently it consists of three major components: tags, stats, and tracing. Currently it consists of three major components: tags, stats and tracing.
## Installation ## Installation
@ -38,7 +38,7 @@ integration with your RPC framework:
* [Redis goredis/redis](https://godoc.org/github.com/orijtech/redis) * [Redis goredis/redis](https://godoc.org/github.com/orijtech/redis)
* [Memcache](https://godoc.org/github.com/orijtech/gomemcache) * [Memcache](https://godoc.org/github.com/orijtech/gomemcache)
If you're a framework not listed here, you could either implement your own middleware for your If you're using a framework not listed here, you could either implement your own middleware for your
framework or use [custom stats](#stats) and [spans](#spans) directly in your application. framework or use [custom stats](#stats) and [spans](#spans) directly in your application.
## Exporters ## Exporters
@ -56,6 +56,7 @@ can implement their own exporters by implementing the exporter interfaces
* [AWS X-Ray][exporter-xray] for traces * [AWS X-Ray][exporter-xray] for traces
* [Datadog][exporter-datadog] for stats and traces * [Datadog][exporter-datadog] for stats and traces
* [Graphite][exporter-graphite] for stats * [Graphite][exporter-graphite] for stats
* [Honeycomb][exporter-honeycomb] for traces
## Overview ## Overview
@ -73,7 +74,7 @@ in the same process or can be encoded to be transmitted on the wire. Usually, th
be handled by an integration plugin, e.g. `ocgrpc.ServerHandler` and `ocgrpc.ClientHandler` be handled by an integration plugin, e.g. `ocgrpc.ServerHandler` and `ocgrpc.ClientHandler`
for gRPC. for gRPC.
Package tag allows adding or modifying tags in the current context. Package `tag` allows adding or modifying tags in the current context.
[embedmd]:# (internal/readme/tags.go new) [embedmd]:# (internal/readme/tags.go new)
```go ```go
@ -177,8 +178,8 @@ Spans can have parents or can be root spans if they don't have any parents.
The current span is propagated in-process and across the network to allow associating The current span is propagated in-process and across the network to allow associating
new child spans with the parent. new child spans with the parent.
In the same process, context.Context is used to propagate spans. In the same process, `context.Context` is used to propagate spans.
trace.StartSpan creates a new span as a root if the current context `trace.StartSpan` creates a new span as a root if the current context
doesn't contain a span. Or, it creates a child of the span that is doesn't contain a span. Or, it creates a child of the span that is
already in current context. The returned context can be used to keep already in current context. The returned context can be used to keep
propagating the newly created span in the current context. propagating the newly created span in the current context.
@ -194,8 +195,8 @@ defer span.End()
Across the network, OpenCensus provides different propagation Across the network, OpenCensus provides different propagation
methods for different protocols. methods for different protocols.
* gRPC integrations uses the OpenCensus' [binary propagation format](https://godoc.org/go.opencensus.io/trace/propagation). * gRPC integrations use the OpenCensus' [binary propagation format](https://godoc.org/go.opencensus.io/trace/propagation).
* HTTP integrations uses Zipkin's [B3](https://github.com/openzipkin/b3-propagation) * HTTP integrations use Zipkin's [B3](https://github.com/openzipkin/b3-propagation)
by default but can be configured to use a custom propagation method by setting another by default but can be configured to use a custom propagation method by setting another
[propagation.HTTPFormat](https://godoc.org/go.opencensus.io/trace/propagation#HTTPFormat). [propagation.HTTPFormat](https://godoc.org/go.opencensus.io/trace/propagation#HTTPFormat).
@ -259,4 +260,4 @@ release in which the functionality was marked *Deprecated*.
[exporter-xray]: https://github.com/census-ecosystem/opencensus-go-exporter-aws [exporter-xray]: https://github.com/census-ecosystem/opencensus-go-exporter-aws
[exporter-datadog]: https://github.com/DataDog/opencensus-go-exporter-datadog [exporter-datadog]: https://github.com/DataDog/opencensus-go-exporter-datadog
[exporter-graphite]: https://github.com/census-ecosystem/opencensus-go-exporter-graphite [exporter-graphite]: https://github.com/census-ecosystem/opencensus-go-exporter-graphite
[exporter-honeycomb]: https://github.com/honeycombio/opencensus-exporter

12
vendor/go.opencensus.io/appveyor.yml generated vendored
View File

@ -5,8 +5,10 @@ platform: x64
clone_folder: c:\gopath\src\go.opencensus.io clone_folder: c:\gopath\src\go.opencensus.io
environment: environment:
GOPATH: c:\gopath GOPATH: 'c:\gopath'
GOVERSION: 1.8 GOVERSION: '1.11'
GO111MODULE: 'on'
CGO_ENABLED: '0' # See: https://github.com/appveyor/ci/issues/2613
install: install:
- set PATH=%GOPATH%\bin;c:\go\bin;%PATH% - set PATH=%GOPATH%\bin;c:\go\bin;%PATH%
@ -18,7 +20,5 @@ deploy: false
test_script: test_script:
- cd %APPVEYOR_BUILD_FOLDER% - cd %APPVEYOR_BUILD_FOLDER%
- gofmt -w . - go build -v .\...
- go get -v -t .\... - go test -v .\... # No -race because cgo is disabled
- go test -race -v .\...
- go vet .\...

78
vendor/go.opencensus.io/exemplar/exemplar.go generated vendored Normal file
View File

@ -0,0 +1,78 @@
// Copyright 2018, OpenCensus Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package exemplar implements support for exemplars. Exemplars are additional
// data associated with each measurement.
//
// Their purpose it to provide an example of the kind of thing
// (request, RPC, trace span, etc.) that resulted in that measurement.
package exemplar
import (
"context"
"time"
)
const (
KeyTraceID = "trace_id"
KeySpanID = "span_id"
KeyPrefixTag = "tag:"
)
// Exemplar is an example data point associated with each bucket of a
// distribution type aggregation.
type Exemplar struct {
Value float64 // the value that was recorded
Timestamp time.Time // the time the value was recorded
Attachments Attachments // attachments (if any)
}
// Attachments is a map of extra values associated with a recorded data point.
// The map should only be mutated from AttachmentExtractor functions.
type Attachments map[string]string
// AttachmentExtractor is a function capable of extracting exemplar attachments
// from the context used to record measurements.
// The map passed to the function should be mutated and returned. It will
// initially be nil: the first AttachmentExtractor that would like to add keys to the
// map is responsible for initializing it.
type AttachmentExtractor func(ctx context.Context, a Attachments) Attachments
var extractors []AttachmentExtractor
// RegisterAttachmentExtractor registers the given extractor associated with the exemplar
// type name.
//
// Extractors will be used to attempt to extract exemplars from the context
// associated with each recorded measurement.
//
// Packages that support exemplars should register their extractor functions on
// initialization.
//
// RegisterAttachmentExtractor should not be called after any measurements have
// been recorded.
func RegisterAttachmentExtractor(e AttachmentExtractor) {
extractors = append(extractors, e)
}
// NewFromContext extracts exemplars from the given context.
// Each registered AttachmentExtractor (see RegisterAttachmentExtractor) is called in an
// unspecified order to add attachments to the exemplar.
func AttachmentsFromContext(ctx context.Context) Attachments {
var a Attachments
for _, extractor := range extractors {
a = extractor(ctx, a)
}
return a
}

5
vendor/go.opencensus.io/go.mod generated vendored
View File

@ -3,7 +3,11 @@ module go.opencensus.io
require ( require (
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999 git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973
github.com/ghodss/yaml v1.0.0 // indirect
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect
github.com/golang/protobuf v1.2.0 github.com/golang/protobuf v1.2.0
github.com/google/go-cmp v0.2.0
github.com/grpc-ecosystem/grpc-gateway v1.5.0 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 github.com/matttproud/golang_protobuf_extensions v1.0.1
github.com/openzipkin/zipkin-go v0.1.1 github.com/openzipkin/zipkin-go v0.1.1
github.com/prometheus/client_golang v0.8.0 github.com/prometheus/client_golang v0.8.0
@ -17,4 +21,5 @@ require (
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b google.golang.org/genproto v0.0.0-20180831171423-11092d34479b
google.golang.org/grpc v1.14.0 google.golang.org/grpc v1.14.0
gopkg.in/yaml.v2 v2.2.1 // indirect
) )

27
vendor/go.opencensus.io/go.sum generated vendored
View File

@ -1,21 +1,48 @@
git.apache.org/thrift.git v0.0.0-20180807212849-6e67faa92827/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= git.apache.org/thrift.git v0.0.0-20180807212849-6e67faa92827/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999 h1:sihTnRgTOUSCQz0iS0pjZuFQy/z7GXCJgSBg3+rZKHw=
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
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/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
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/grpc-ecosystem/grpc-gateway v1.5.0 h1:WcmKMm43DR7RdtlkEXQJyo5ws8iTp98CyhCCbOHMvNI=
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/openzipkin/zipkin-go v0.1.1 h1:A/ADD6HaPnAKj3yS7HjGHRK77qi41Hi0DirOOIQAeIw=
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
github.com/prometheus/client_golang v0.8.0 h1:1921Yw9Gc3iSc4VQh3PIoOqgPCZS7G/4xQNVUp8Mda8=
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e h1:n/3MEhJQjQxrOUCzh1Y3Re6aJUUWRp2M9+Oc3eVn/54=
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273 h1:agujYaXJSxSo18YNX3jzl+4G6Bstwt+kqv47GS12uL0=
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
golang.org/x/net v0.0.0-20180821023952-922f4815f713/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180821023952-922f4815f713/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180821140842-3b58ed4ad339/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180821140842-3b58ed4ad339/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
google.golang.org/api v0.0.0-20180818000503-e21acd801f91/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20180818000503-e21acd801f91/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf h1:rjxqQmxjyqerRKEj+tZW+MCm4LgpFXu18bsEoCMgDsk=
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/grpc v1.14.0 h1:ArxJuB1NWfPY6r9Gp9gqwplT0Ge7nqv9msgu03lHLmo=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@ -17,5 +17,5 @@ package opencensus // import "go.opencensus.io"
// Version is the current release version of OpenCensus in use. // Version is the current release version of OpenCensus in use.
func Version() string { func Version() string {
return "0.17.0" return "0.18.0"
} }

View File

@ -47,6 +47,10 @@ type Transport struct {
// for spans started by this transport. // for spans started by this transport.
StartOptions trace.StartOptions StartOptions trace.StartOptions
// GetStartOptions allows to set start options per request. If set,
// StartOptions is going to be ignored.
GetStartOptions func(*http.Request) trace.StartOptions
// NameFromRequest holds the function to use for generating the span name // NameFromRequest holds the function to use for generating the span name
// from the information found in the outgoing HTTP Request. By default the // from the information found in the outgoing HTTP Request. By default the
// name equals the URL Path. // name equals the URL Path.
@ -75,11 +79,17 @@ func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
if spanNameFormatter == nil { if spanNameFormatter == nil {
spanNameFormatter = spanNameFromURL spanNameFormatter = spanNameFromURL
} }
startOpts := t.StartOptions
if t.GetStartOptions != nil {
startOpts = t.GetStartOptions(req)
}
rt = &traceTransport{ rt = &traceTransport{
base: rt, base: rt,
format: format, format: format,
startOptions: trace.StartOptions{ startOptions: trace.StartOptions{
Sampler: t.StartOptions.Sampler, Sampler: startOpts.Sampler,
SpanKind: trace.SpanKindClient, SpanKind: trace.SpanKindClient,
}, },
formatSpanName: spanNameFormatter, formatSpanName: spanNameFormatter,

View File

@ -34,8 +34,11 @@ type statsTransport struct {
// RoundTrip implements http.RoundTripper, delegating to Base and recording stats for the request. // RoundTrip implements http.RoundTripper, delegating to Base and recording stats for the request.
func (t statsTransport) RoundTrip(req *http.Request) (*http.Response, error) { func (t statsTransport) RoundTrip(req *http.Request) (*http.Response, error) {
ctx, _ := tag.New(req.Context(), ctx, _ := tag.New(req.Context(),
tag.Upsert(KeyClientHost, req.URL.Host),
tag.Upsert(Host, req.URL.Host), tag.Upsert(Host, req.URL.Host),
tag.Upsert(KeyClientPath, req.URL.Path),
tag.Upsert(Path, req.URL.Path), tag.Upsert(Path, req.URL.Path),
tag.Upsert(KeyClientMethod, req.Method),
tag.Upsert(Method, req.Method)) tag.Upsert(Method, req.Method))
req = req.WithContext(ctx) req = req.WithContext(ctx)
track := &tracker{ track := &tracker{
@ -92,15 +95,22 @@ var _ io.ReadCloser = (*tracker)(nil)
func (t *tracker) end() { func (t *tracker) end() {
t.endOnce.Do(func() { t.endOnce.Do(func() {
latencyMs := float64(time.Since(t.start)) / float64(time.Millisecond)
m := []stats.Measurement{ m := []stats.Measurement{
ClientLatency.M(float64(time.Since(t.start)) / float64(time.Millisecond)), ClientSentBytes.M(t.reqSize),
ClientReceivedBytes.M(t.respSize),
ClientRoundtripLatency.M(latencyMs),
ClientLatency.M(latencyMs),
ClientResponseBytes.M(t.respSize), ClientResponseBytes.M(t.respSize),
} }
if t.reqSize >= 0 { if t.reqSize >= 0 {
m = append(m, ClientRequestBytes.M(t.reqSize)) m = append(m, ClientRequestBytes.M(t.reqSize))
} }
ctx, _ := tag.New(t.ctx, tag.Upsert(StatusCode, strconv.Itoa(t.statusCode)))
stats.Record(ctx, m...) stats.RecordWithTags(t.ctx, []tag.Mutator{
tag.Upsert(StatusCode, strconv.Itoa(t.statusCode)),
tag.Upsert(KeyClientStatus, strconv.Itoa(t.statusCode)),
}, m...)
}) })
} }

View File

@ -56,6 +56,10 @@ type Handler struct {
// for spans started by this transport. // for spans started by this transport.
StartOptions trace.StartOptions StartOptions trace.StartOptions
// GetStartOptions allows to set start options per request. If set,
// StartOptions is going to be ignored.
GetStartOptions func(*http.Request) trace.StartOptions
// IsPublicEndpoint should be set to true for publicly accessible HTTP(S) // IsPublicEndpoint should be set to true for publicly accessible HTTP(S)
// servers. If true, any trace metadata set on the incoming request will // servers. If true, any trace metadata set on the incoming request will
// be added as a linked trace instead of being added as a parent of the // be added as a linked trace instead of being added as a parent of the
@ -93,15 +97,21 @@ func (h *Handler) startTrace(w http.ResponseWriter, r *http.Request) (*http.Requ
name = h.FormatSpanName(r) name = h.FormatSpanName(r)
} }
ctx := r.Context() ctx := r.Context()
startOpts := h.StartOptions
if h.GetStartOptions != nil {
startOpts = h.GetStartOptions(r)
}
var span *trace.Span var span *trace.Span
sc, ok := h.extractSpanContext(r) sc, ok := h.extractSpanContext(r)
if ok && !h.IsPublicEndpoint { if ok && !h.IsPublicEndpoint {
ctx, span = trace.StartSpanWithRemoteParent(ctx, name, sc, ctx, span = trace.StartSpanWithRemoteParent(ctx, name, sc,
trace.WithSampler(h.StartOptions.Sampler), trace.WithSampler(startOpts.Sampler),
trace.WithSpanKind(trace.SpanKindServer)) trace.WithSpanKind(trace.SpanKindServer))
} else { } else {
ctx, span = trace.StartSpan(ctx, name, ctx, span = trace.StartSpan(ctx, name,
trace.WithSampler(h.StartOptions.Sampler), trace.WithSampler(startOpts.Sampler),
trace.WithSpanKind(trace.SpanKindServer), trace.WithSpanKind(trace.SpanKindServer),
) )
if ok { if ok {
@ -168,6 +178,7 @@ func (t *trackingResponseWriter) end(tags *addedTags) {
span := trace.FromContext(t.ctx) span := trace.FromContext(t.ctx)
span.SetStatus(TraceStatus(t.statusCode, t.statusLine)) span.SetStatus(TraceStatus(t.statusCode, t.statusLine))
span.AddAttributes(trace.Int64Attribute(StatusCodeAttribute, int64(t.statusCode)))
m := []stats.Measurement{ m := []stats.Measurement{
ServerLatency.M(float64(time.Since(t.start)) / float64(time.Millisecond)), ServerLatency.M(float64(time.Since(t.start)) / float64(time.Millisecond)),
@ -179,8 +190,7 @@ func (t *trackingResponseWriter) end(tags *addedTags) {
allTags := make([]tag.Mutator, len(tags.t)+1) allTags := make([]tag.Mutator, len(tags.t)+1)
allTags[0] = tag.Upsert(StatusCode, strconv.Itoa(t.statusCode)) allTags[0] = tag.Upsert(StatusCode, strconv.Itoa(t.statusCode))
copy(allTags[1:], tags.t) copy(allTags[1:], tags.t)
ctx, _ := tag.New(t.ctx, allTags...) stats.RecordWithTags(t.ctx, allTags, m...)
stats.Record(ctx, m...)
}) })
} }

View File

@ -29,6 +29,8 @@ type spanAnnotator struct {
// TODO: Remove NewSpanAnnotator at the next release. // TODO: Remove NewSpanAnnotator at the next release.
// NewSpanAnnotator returns a httptrace.ClientTrace which annotates
// all emitted httptrace events on the provided Span.
// Deprecated: Use NewSpanAnnotatingClientTrace instead // Deprecated: Use NewSpanAnnotatingClientTrace instead
func NewSpanAnnotator(r *http.Request, s *trace.Span) *httptrace.ClientTrace { func NewSpanAnnotator(r *http.Request, s *trace.Span) *httptrace.ClientTrace {
return NewSpanAnnotatingClientTrace(r, s) return NewSpanAnnotatingClientTrace(r, s)

View File

@ -22,10 +22,33 @@ import (
// The following client HTTP measures are supported for use in custom views. // The following client HTTP measures are supported for use in custom views.
var ( var (
ClientRequestCount = stats.Int64("opencensus.io/http/client/request_count", "Number of HTTP requests started", stats.UnitDimensionless) // Deprecated: Use a Count aggregation over one of the other client measures to achieve the same effect.
ClientRequestBytes = stats.Int64("opencensus.io/http/client/request_bytes", "HTTP request body size if set as ContentLength (uncompressed)", stats.UnitBytes) ClientRequestCount = stats.Int64("opencensus.io/http/client/request_count", "Number of HTTP requests started", stats.UnitDimensionless)
// Deprecated: Use ClientSentBytes.
ClientRequestBytes = stats.Int64("opencensus.io/http/client/request_bytes", "HTTP request body size if set as ContentLength (uncompressed)", stats.UnitBytes)
// Deprecated: Use ClientReceivedBytes.
ClientResponseBytes = stats.Int64("opencensus.io/http/client/response_bytes", "HTTP response body size (uncompressed)", stats.UnitBytes) ClientResponseBytes = stats.Int64("opencensus.io/http/client/response_bytes", "HTTP response body size (uncompressed)", stats.UnitBytes)
ClientLatency = stats.Float64("opencensus.io/http/client/latency", "End-to-end latency", stats.UnitMilliseconds) // Deprecated: Use ClientRoundtripLatency.
ClientLatency = stats.Float64("opencensus.io/http/client/latency", "End-to-end latency", stats.UnitMilliseconds)
)
// Client measures supported for use in custom views.
var (
ClientSentBytes = stats.Int64(
"opencensus.io/http/client/sent_bytes",
"Total bytes sent in request body (not including headers)",
stats.UnitBytes,
)
ClientReceivedBytes = stats.Int64(
"opencensus.io/http/client/received_bytes",
"Total bytes received in response bodies (not including headers but including error responses with bodies)",
stats.UnitBytes,
)
ClientRoundtripLatency = stats.Float64(
"opencensus.io/http/client/roundtrip_latency",
"Time between first byte of request headers sent to last byte of response received, or terminal error",
stats.UnitMilliseconds,
)
) )
// The following server HTTP measures are supported for use in custom views: // The following server HTTP measures are supported for use in custom views:
@ -67,6 +90,18 @@ var (
KeyServerRoute, _ = tag.NewKey("http_server_route") KeyServerRoute, _ = tag.NewKey("http_server_route")
) )
// Client tag keys.
var (
// KeyClientMethod is the HTTP method, capitalized (i.e. GET, POST, PUT, DELETE, etc.).
KeyClientMethod, _ = tag.NewKey("http_client_method")
// KeyClientPath is the URL path (not including query string).
KeyClientPath, _ = tag.NewKey("http_client_path")
// KeyClientStatus is the HTTP status code as an integer (e.g. 200, 404, 500.), or "error" if no response status line was received.
KeyClientStatus, _ = tag.NewKey("http_client_status")
// KeyClientHost is the value of the request Host header.
KeyClientHost, _ = tag.NewKey("http_client_host")
)
// Default distributions used by views in this package. // Default distributions used by views in this package.
var ( var (
DefaultSizeDistribution = view.Distribution(0, 1024, 2048, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216, 67108864, 268435456, 1073741824, 4294967296) DefaultSizeDistribution = view.Distribution(0, 1024, 2048, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216, 67108864, 268435456, 1073741824, 4294967296)
@ -74,8 +109,43 @@ var (
) )
// Package ochttp provides some convenience views. // Package ochttp provides some convenience views.
// You need to register the views for data to actually be collected. // You still need to register these views for data to actually be collected.
var ( var (
ClientSentBytesDistribution = &view.View{
Name: "opencensus.io/http/client/sent_bytes",
Measure: ClientSentBytes,
Aggregation: DefaultSizeDistribution,
Description: "Total bytes sent in request body (not including headers), by HTTP method and response status",
TagKeys: []tag.Key{KeyClientMethod, KeyClientStatus},
}
ClientReceivedBytesDistribution = &view.View{
Name: "opencensus.io/http/client/received_bytes",
Measure: ClientReceivedBytes,
Aggregation: DefaultSizeDistribution,
Description: "Total bytes received in response bodies (not including headers but including error responses with bodies), by HTTP method and response status",
TagKeys: []tag.Key{KeyClientMethod, KeyClientStatus},
}
ClientRoundtripLatencyDistribution = &view.View{
Name: "opencensus.io/http/client/roundtrip_latency",
Measure: ClientRoundtripLatency,
Aggregation: DefaultLatencyDistribution,
Description: "End-to-end latency, by HTTP method and response status",
TagKeys: []tag.Key{KeyClientMethod, KeyClientStatus},
}
ClientCompletedCount = &view.View{
Name: "opencensus.io/http/client/completed_count",
Measure: ClientRoundtripLatency,
Aggregation: view.Count(),
Description: "Count of completed requests, by HTTP method and response status",
TagKeys: []tag.Key{KeyClientMethod, KeyClientStatus},
}
)
var (
// Deprecated: No direct replacement, but see ClientCompletedCount.
ClientRequestCountView = &view.View{ ClientRequestCountView = &view.View{
Name: "opencensus.io/http/client/request_count", Name: "opencensus.io/http/client/request_count",
Description: "Count of HTTP requests started", Description: "Count of HTTP requests started",
@ -83,43 +153,50 @@ var (
Aggregation: view.Count(), Aggregation: view.Count(),
} }
// Deprecated: Use ClientSentBytesDistribution.
ClientRequestBytesView = &view.View{ ClientRequestBytesView = &view.View{
Name: "opencensus.io/http/client/request_bytes", Name: "opencensus.io/http/client/request_bytes",
Description: "Size distribution of HTTP request body", Description: "Size distribution of HTTP request body",
Measure: ClientRequestBytes, Measure: ClientSentBytes,
Aggregation: DefaultSizeDistribution, Aggregation: DefaultSizeDistribution,
} }
// Deprecated: Use ClientReceivedBytesDistribution.
ClientResponseBytesView = &view.View{ ClientResponseBytesView = &view.View{
Name: "opencensus.io/http/client/response_bytes", Name: "opencensus.io/http/client/response_bytes",
Description: "Size distribution of HTTP response body", Description: "Size distribution of HTTP response body",
Measure: ClientResponseBytes, Measure: ClientReceivedBytes,
Aggregation: DefaultSizeDistribution, Aggregation: DefaultSizeDistribution,
} }
// Deprecated: Use ClientRoundtripLatencyDistribution.
ClientLatencyView = &view.View{ ClientLatencyView = &view.View{
Name: "opencensus.io/http/client/latency", Name: "opencensus.io/http/client/latency",
Description: "Latency distribution of HTTP requests", Description: "Latency distribution of HTTP requests",
Measure: ClientLatency, Measure: ClientRoundtripLatency,
Aggregation: DefaultLatencyDistribution, Aggregation: DefaultLatencyDistribution,
} }
// Deprecated: Use ClientCompletedCount.
ClientRequestCountByMethod = &view.View{ ClientRequestCountByMethod = &view.View{
Name: "opencensus.io/http/client/request_count_by_method", Name: "opencensus.io/http/client/request_count_by_method",
Description: "Client request count by HTTP method", Description: "Client request count by HTTP method",
TagKeys: []tag.Key{Method}, TagKeys: []tag.Key{Method},
Measure: ClientRequestCount, Measure: ClientSentBytes,
Aggregation: view.Count(), Aggregation: view.Count(),
} }
// Deprecated: Use ClientCompletedCount.
ClientResponseCountByStatusCode = &view.View{ ClientResponseCountByStatusCode = &view.View{
Name: "opencensus.io/http/client/response_count_by_status_code", Name: "opencensus.io/http/client/response_count_by_status_code",
Description: "Client response count by status code", Description: "Client response count by status code",
TagKeys: []tag.Key{StatusCode}, TagKeys: []tag.Key{StatusCode},
Measure: ClientLatency, Measure: ClientRoundtripLatency,
Aggregation: view.Count(), Aggregation: view.Count(),
} }
)
var (
ServerRequestCountView = &view.View{ ServerRequestCountView = &view.View{
Name: "opencensus.io/http/server/request_count", Name: "opencensus.io/http/server/request_count",
Description: "Count of HTTP requests started", Description: "Count of HTTP requests started",
@ -166,6 +243,7 @@ var (
) )
// DefaultClientViews are the default client views provided by this package. // DefaultClientViews are the default client views provided by this package.
// Deprecated: No replacement. Register the views you would like individually.
var DefaultClientViews = []*view.View{ var DefaultClientViews = []*view.View{
ClientRequestCountView, ClientRequestCountView,
ClientRequestBytesView, ClientRequestBytesView,
@ -176,6 +254,7 @@ var DefaultClientViews = []*view.View{
} }
// DefaultServerViews are the default server views provided by this package. // DefaultServerViews are the default server views provided by this package.
// Deprecated: No replacement. Register the views you would like individually.
var DefaultServerViews = []*view.View{ var DefaultServerViews = []*view.View{
ServerRequestCountView, ServerRequestCountView,
ServerRequestBytesView, ServerRequestBytesView,

38
vendor/go.opencensus.io/stats/doc.go generated vendored
View File

@ -21,35 +21,49 @@ aggregate the collected data, and export the aggregated data.
Measures Measures
A measure represents a type of metric to be tracked and recorded. A measure represents a type of data point to be tracked and recorded.
For example, latency, request Mb/s, and response Mb/s are measures For example, latency, request Mb/s, and response Mb/s are measures
to collect from a server. to collect from a server.
Each measure needs to be registered before being used. Measure Measure constructors such as Int64 and Float64 automatically
constructors such as Int64 and Float64 automatically
register the measure by the given name. Each registered measure needs register the measure by the given name. Each registered measure needs
to be unique by name. Measures also have a description and a unit. to be unique by name. Measures also have a description and a unit.
Libraries can define and export measures for their end users to Libraries can define and export measures. Application authors can then
create views and collect instrumentation data. create views and collect and break down measures by the tags they are
interested in.
Recording measurements Recording measurements
Measurement is a data point to be collected for a measure. For example, Measurement is a data point to be collected for a measure. For example,
for a latency (ms) measure, 100 is a measurement that represents a 100ms for a latency (ms) measure, 100 is a measurement that represents a 100ms
latency event. Users collect data points on the existing measures with latency event. Measurements are created from measures with
the current context. Tags from the current context are recorded with the the current context. Tags from the current context are recorded with the
measurements if they are any. measurements if they are any.
Recorded measurements are dropped immediately if user is not aggregating Recorded measurements are dropped immediately if no views are registered for them.
them via views. Users don't necessarily need to conditionally enable/disable There is usually no need to conditionally enable and disable
recording to reduce cost. Recording of measurements is cheap. recording to reduce cost. Recording of measurements is cheap.
Libraries can always record measurements, and end-users can later decide Libraries can always record measurements, and applications can later decide
on which measurements they want to collect by registering views. This allows on which measurements they want to collect by registering views. This allows
libraries to turn on the instrumentation by default. libraries to turn on the instrumentation by default.
Exemplars
For a given recorded measurement, the associated exemplar is a diagnostic map
that gives more information about the measurement.
When aggregated using a Distribution aggregation, an exemplar is kept for each
bucket in the Distribution. This allows you to easily find an example of a
measurement that fell into each bucket.
For example, if you also use the OpenCensus trace package and you
record a measurement with a context that contains a sampled trace span,
then the trace span will be added to the exemplar associated with the measurement.
When exported to a supporting back end, you should be able to easily navigate
to example traces that fell into each bucket in the Distribution.
*/ */
package stats // import "go.opencensus.io/stats" package stats // import "go.opencensus.io/stats"
// TODO(acetechnologist): Add a link to the language independent OpenCensus
// spec when it is available.

View File

@ -19,7 +19,7 @@ import (
) )
// DefaultRecorder will be called for each Record call. // DefaultRecorder will be called for each Record call.
var DefaultRecorder func(*tag.Map, interface{}) var DefaultRecorder func(tags *tag.Map, measurement interface{}, attachments map[string]string)
// SubscriptionReporter reports when a view subscribed with a measure. // SubscriptionReporter reports when a view subscribed with a measure.
var SubscriptionReporter func(measure string) var SubscriptionReporter func(measure string)

View File

@ -68,6 +68,21 @@ func (m *measureDescriptor) subscribed() bool {
return atomic.LoadInt32(&m.subs) == 1 return atomic.LoadInt32(&m.subs) == 1
} }
// Name returns the name of the measure.
func (m *measureDescriptor) Name() string {
return m.name
}
// Description returns the description of the measure.
func (m *measureDescriptor) Description() string {
return m.description
}
// Unit returns the unit of the measure.
func (m *measureDescriptor) Unit() string {
return m.unit
}
var ( var (
mu sync.RWMutex mu sync.RWMutex
measures = make(map[string]*measureDescriptor) measures = make(map[string]*measureDescriptor)
@ -94,7 +109,7 @@ func registerMeasureHandle(name, desc, unit string) *measureDescriptor {
// provides M to convert an int64 into a measurement. // provides M to convert an int64 into a measurement.
type Measurement struct { type Measurement struct {
v float64 v float64
m Measure m *measureDescriptor
} }
// Value returns the value of the Measurement as a float64. // Value returns the value of the Measurement as a float64.

View File

@ -17,31 +17,13 @@ package stats
// Float64Measure is a measure for float64 values. // Float64Measure is a measure for float64 values.
type Float64Measure struct { type Float64Measure struct {
md *measureDescriptor *measureDescriptor
}
// Name returns the name of the measure.
func (m *Float64Measure) Name() string {
return m.md.name
}
// Description returns the description of the measure.
func (m *Float64Measure) Description() string {
return m.md.description
}
// Unit returns the unit of the measure.
func (m *Float64Measure) Unit() string {
return m.md.unit
} }
// M creates a new float64 measurement. // M creates a new float64 measurement.
// Use Record to record measurements. // Use Record to record measurements.
func (m *Float64Measure) M(v float64) Measurement { func (m *Float64Measure) M(v float64) Measurement {
if !m.md.subscribed() { return Measurement{m: m.measureDescriptor, v: v}
return Measurement{}
}
return Measurement{m: m, v: v}
} }
// Float64 creates a new measure for float64 values. // Float64 creates a new measure for float64 values.

View File

@ -17,31 +17,13 @@ package stats
// Int64Measure is a measure for int64 values. // Int64Measure is a measure for int64 values.
type Int64Measure struct { type Int64Measure struct {
md *measureDescriptor *measureDescriptor
}
// Name returns the name of the measure.
func (m *Int64Measure) Name() string {
return m.md.name
}
// Description returns the description of the measure.
func (m *Int64Measure) Description() string {
return m.md.description
}
// Unit returns the unit of the measure.
func (m *Int64Measure) Unit() string {
return m.md.unit
} }
// M creates a new int64 measurement. // M creates a new int64 measurement.
// Use Record to record measurements. // Use Record to record measurements.
func (m *Int64Measure) M(v int64) Measurement { func (m *Int64Measure) M(v int64) Measurement {
if !m.md.subscribed() { return Measurement{m: m.measureDescriptor, v: float64(v)}
return Measurement{}
}
return Measurement{m: m, v: float64(v)}
} }
// Int64 creates a new measure for int64 values. // Int64 creates a new measure for int64 values.

View File

@ -18,6 +18,7 @@ package stats
import ( import (
"context" "context"
"go.opencensus.io/exemplar"
"go.opencensus.io/stats/internal" "go.opencensus.io/stats/internal"
"go.opencensus.io/tag" "go.opencensus.io/tag"
) )
@ -30,15 +31,19 @@ func init() {
} }
} }
// Record records one or multiple measurements with the same tags at once. // Record records one or multiple measurements with the same context at once.
// If there are any tags in the context, measurements will be tagged with them. // If there are any tags in the context, measurements will be tagged with them.
func Record(ctx context.Context, ms ...Measurement) { func Record(ctx context.Context, ms ...Measurement) {
recorder := internal.DefaultRecorder
if recorder == nil {
return
}
if len(ms) == 0 { if len(ms) == 0 {
return return
} }
var record bool record := false
for _, m := range ms { for _, m := range ms {
if (m != Measurement{}) { if m.m.subscribed() {
record = true record = true
break break
} }
@ -46,7 +51,19 @@ func Record(ctx context.Context, ms ...Measurement) {
if !record { if !record {
return return
} }
if internal.DefaultRecorder != nil { recorder(tag.FromContext(ctx), ms, exemplar.AttachmentsFromContext(ctx))
internal.DefaultRecorder(tag.FromContext(ctx), ms) }
}
// RecordWithTags records one or multiple measurements at once.
//
// Measurements will be tagged with the tags in the context mutated by the mutators.
// RecordWithTags is useful if you want to record with tag mutations but don't want
// to propagate the mutations in the context.
func RecordWithTags(ctx context.Context, mutators []tag.Mutator, ms ...Measurement) error {
ctx, err := tag.New(ctx, mutators...)
if err != nil {
return err
}
Record(ctx, ms...)
return nil
} }

View File

@ -17,6 +17,8 @@ package view
import ( import (
"math" "math"
"go.opencensus.io/exemplar"
) )
// AggregationData represents an aggregated value from a collection. // AggregationData represents an aggregated value from a collection.
@ -24,7 +26,7 @@ import (
// Mosts users won't directly access aggregration data. // Mosts users won't directly access aggregration data.
type AggregationData interface { type AggregationData interface {
isAggregationData() bool isAggregationData() bool
addSample(v float64) addSample(e *exemplar.Exemplar)
clone() AggregationData clone() AggregationData
equal(other AggregationData) bool equal(other AggregationData) bool
} }
@ -41,7 +43,7 @@ type CountData struct {
func (a *CountData) isAggregationData() bool { return true } func (a *CountData) isAggregationData() bool { return true }
func (a *CountData) addSample(v float64) { func (a *CountData) addSample(_ *exemplar.Exemplar) {
a.Value = a.Value + 1 a.Value = a.Value + 1
} }
@ -68,8 +70,8 @@ type SumData struct {
func (a *SumData) isAggregationData() bool { return true } func (a *SumData) isAggregationData() bool { return true }
func (a *SumData) addSample(f float64) { func (a *SumData) addSample(e *exemplar.Exemplar) {
a.Value += f a.Value += e.Value
} }
func (a *SumData) clone() AggregationData { func (a *SumData) clone() AggregationData {
@ -88,22 +90,30 @@ func (a *SumData) equal(other AggregationData) bool {
// Distribution aggregation. // Distribution aggregation.
// //
// Most users won't directly access distribution data. // Most users won't directly access distribution data.
//
// For a distribution with N bounds, the associated DistributionData will have
// N+1 buckets.
type DistributionData struct { type DistributionData struct {
Count int64 // number of data points aggregated Count int64 // number of data points aggregated
Min float64 // minimum value in the distribution Min float64 // minimum value in the distribution
Max float64 // max value in the distribution Max float64 // max value in the distribution
Mean float64 // mean of the distribution Mean float64 // mean of the distribution
SumOfSquaredDev float64 // sum of the squared deviation from the mean SumOfSquaredDev float64 // sum of the squared deviation from the mean
CountPerBucket []int64 // number of occurrences per bucket CountPerBucket []int64 // number of occurrences per bucket
bounds []float64 // histogram distribution of the values // ExemplarsPerBucket is slice the same length as CountPerBucket containing
// an exemplar for the associated bucket, or nil.
ExemplarsPerBucket []*exemplar.Exemplar
bounds []float64 // histogram distribution of the values
} }
func newDistributionData(bounds []float64) *DistributionData { func newDistributionData(bounds []float64) *DistributionData {
bucketCount := len(bounds) + 1
return &DistributionData{ return &DistributionData{
CountPerBucket: make([]int64, len(bounds)+1), CountPerBucket: make([]int64, bucketCount),
bounds: bounds, ExemplarsPerBucket: make([]*exemplar.Exemplar, bucketCount),
Min: math.MaxFloat64, bounds: bounds,
Max: math.SmallestNonzeroFloat64, Min: math.MaxFloat64,
Max: math.SmallestNonzeroFloat64,
} }
} }
@ -119,7 +129,8 @@ func (a *DistributionData) variance() float64 {
func (a *DistributionData) isAggregationData() bool { return true } func (a *DistributionData) isAggregationData() bool { return true }
func (a *DistributionData) addSample(f float64) { func (a *DistributionData) addSample(e *exemplar.Exemplar) {
f := e.Value
if f < a.Min { if f < a.Min {
a.Min = f a.Min = f
} }
@ -127,7 +138,7 @@ func (a *DistributionData) addSample(f float64) {
a.Max = f a.Max = f
} }
a.Count++ a.Count++
a.incrementBucketCount(f) a.addToBucket(e)
if a.Count == 1 { if a.Count == 1 {
a.Mean = f a.Mean = f
@ -139,26 +150,43 @@ func (a *DistributionData) addSample(f float64) {
a.SumOfSquaredDev = a.SumOfSquaredDev + (f-oldMean)*(f-a.Mean) a.SumOfSquaredDev = a.SumOfSquaredDev + (f-oldMean)*(f-a.Mean)
} }
func (a *DistributionData) incrementBucketCount(f float64) { func (a *DistributionData) addToBucket(e *exemplar.Exemplar) {
if len(a.bounds) == 0 { var count *int64
a.CountPerBucket[0]++ var ex **exemplar.Exemplar
return
}
for i, b := range a.bounds { for i, b := range a.bounds {
if f < b { if e.Value < b {
a.CountPerBucket[i]++ count = &a.CountPerBucket[i]
return ex = &a.ExemplarsPerBucket[i]
break
} }
} }
a.CountPerBucket[len(a.bounds)]++ if count == nil {
count = &a.CountPerBucket[len(a.bounds)]
ex = &a.ExemplarsPerBucket[len(a.bounds)]
}
*count++
*ex = maybeRetainExemplar(*ex, e)
}
func maybeRetainExemplar(old, cur *exemplar.Exemplar) *exemplar.Exemplar {
if old == nil {
return cur
}
// Heuristic to pick the "better" exemplar: first keep the one with a
// sampled trace attachment, if neither have a trace attachment, pick the
// one with more attachments.
_, haveTraceID := cur.Attachments[exemplar.KeyTraceID]
if haveTraceID || len(cur.Attachments) >= len(old.Attachments) {
return cur
}
return old
} }
func (a *DistributionData) clone() AggregationData { func (a *DistributionData) clone() AggregationData {
counts := make([]int64, len(a.CountPerBucket))
copy(counts, a.CountPerBucket)
c := *a c := *a
c.CountPerBucket = counts c.CountPerBucket = append([]int64(nil), a.CountPerBucket...)
c.ExemplarsPerBucket = append([]*exemplar.Exemplar(nil), a.ExemplarsPerBucket...)
return &c return &c
} }
@ -190,8 +218,8 @@ func (l *LastValueData) isAggregationData() bool {
return true return true
} }
func (l *LastValueData) addSample(v float64) { func (l *LastValueData) addSample(e *exemplar.Exemplar) {
l.Value = v l.Value = e.Value
} }
func (l *LastValueData) clone() AggregationData { func (l *LastValueData) clone() AggregationData {

View File

@ -18,6 +18,8 @@ package view
import ( import (
"sort" "sort"
"go.opencensus.io/exemplar"
"go.opencensus.io/internal/tagencoding" "go.opencensus.io/internal/tagencoding"
"go.opencensus.io/tag" "go.opencensus.io/tag"
) )
@ -31,13 +33,13 @@ type collector struct {
a *Aggregation a *Aggregation
} }
func (c *collector) addSample(s string, v float64) { func (c *collector) addSample(s string, e *exemplar.Exemplar) {
aggregator, ok := c.signatures[s] aggregator, ok := c.signatures[s]
if !ok { if !ok {
aggregator = c.a.newData() aggregator = c.a.newData()
c.signatures[s] = aggregator c.signatures[s] = aggregator
} }
aggregator.addSample(v) aggregator.addSample(e)
} }
// collectRows returns a snapshot of the collected Row values. // collectRows returns a snapshot of the collected Row values.

View File

@ -13,33 +13,34 @@
// limitations under the License. // limitations under the License.
// //
/* // Package view contains support for collecting and exposing aggregates over stats.
Package view contains support for collecting and exposing aggregates over stats. //
// In order to collect measurements, views need to be defined and registered.
In order to collect measurements, views need to be defined and registered. // A view allows recorded measurements to be filtered and aggregated.
A view allows recorded measurements to be filtered and aggregated over a time window. //
// All recorded measurements can be grouped by a list of tags.
All recorded measurements can be filtered by a list of tags. //
// OpenCensus provides several aggregation methods: Count, Distribution and Sum.
OpenCensus provides several aggregation methods: count, distribution and sum. //
Count aggregation only counts the number of measurement points. Distribution // Count only counts the number of measurement points recorded.
aggregation provides statistical summary of the aggregated data. Sum distribution // Distribution provides statistical summary of the aggregated data by counting
sums up the measurement points. Aggregations are cumulative. // how many recorded measurements fall into each bucket.
// Sum adds up the measurement values.
Users can dynamically create and delete views. // LastValue just keeps track of the most recently recorded measurement value.
// All aggregations are cumulative.
Libraries can export their own views and claim the view names //
by registering them themselves. // Views can be registerd and unregistered at any time during program execution.
//
Exporting // Libraries can define views but it is recommended that in most cases registering
// views be left up to applications.
Collected and aggregated data can be exported to a metric collection //
backend by registering its exporter. // Exporting
//
Multiple exporters can be registered to upload the data to various // Collected and aggregated data can be exported to a metric collection
different backends. Users need to unregister the exporters once they // backend by registering its exporter.
no longer are needed. //
*/ // Multiple exporters can be registered to upload the data to various
// different back ends.
package view // import "go.opencensus.io/stats/view" package view // import "go.opencensus.io/stats/view"
// TODO(acetechnologist): Add a link to the language independent OpenCensus // TODO(acetechnologist): Add a link to the language independent OpenCensus

View File

@ -23,6 +23,8 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"go.opencensus.io/exemplar"
"go.opencensus.io/stats" "go.opencensus.io/stats"
"go.opencensus.io/stats/internal" "go.opencensus.io/stats/internal"
"go.opencensus.io/tag" "go.opencensus.io/tag"
@ -127,12 +129,12 @@ func (v *viewInternal) collectedRows() []*Row {
return v.collector.collectedRows(v.view.TagKeys) return v.collector.collectedRows(v.view.TagKeys)
} }
func (v *viewInternal) addSample(m *tag.Map, val float64) { func (v *viewInternal) addSample(m *tag.Map, e *exemplar.Exemplar) {
if !v.isSubscribed() { if !v.isSubscribed() {
return return
} }
sig := string(encodeWithKeys(m, v.view.TagKeys)) sig := string(encodeWithKeys(m, v.view.TagKeys))
v.collector.addSample(sig, val) v.collector.addSample(sig, e)
} }
// A Data is a set of rows about usage of the single measure associated // A Data is a set of rows about usage of the single measure associated

View File

@ -107,10 +107,12 @@ func RetrieveData(viewName string) ([]*Row, error) {
return resp.rows, resp.err return resp.rows, resp.err
} }
func record(tags *tag.Map, ms interface{}) { func record(tags *tag.Map, ms interface{}, attachments map[string]string) {
req := &recordReq{ req := &recordReq{
tm: tags, tm: tags,
ms: ms.([]stats.Measurement), ms: ms.([]stats.Measurement),
attachments: attachments,
t: time.Now(),
} }
defaultWorker.c <- req defaultWorker.c <- req
} }

View File

@ -21,6 +21,8 @@ import (
"strings" "strings"
"time" "time"
"go.opencensus.io/exemplar"
"go.opencensus.io/stats" "go.opencensus.io/stats"
"go.opencensus.io/stats/internal" "go.opencensus.io/stats/internal"
"go.opencensus.io/tag" "go.opencensus.io/tag"
@ -140,8 +142,10 @@ func (cmd *retrieveDataReq) handleCommand(w *worker) {
// recordReq is the command to record data related to multiple measures // recordReq is the command to record data related to multiple measures
// at once. // at once.
type recordReq struct { type recordReq struct {
tm *tag.Map tm *tag.Map
ms []stats.Measurement ms []stats.Measurement
attachments map[string]string
t time.Time
} }
func (cmd *recordReq) handleCommand(w *worker) { func (cmd *recordReq) handleCommand(w *worker) {
@ -151,7 +155,12 @@ func (cmd *recordReq) handleCommand(w *worker) {
} }
ref := w.getMeasureRef(m.Measure().Name()) ref := w.getMeasureRef(m.Measure().Name())
for v := range ref.views { for v := range ref.views {
v.addSample(cmd.tm, m.Value()) e := &exemplar.Exemplar{
Value: m.Value(),
Timestamp: cmd.t,
Attachments: cmd.attachments,
}
v.addSample(cmd.tm, e)
} }
} }
} }

View File

@ -15,7 +15,11 @@
package tag package tag
import "context" import (
"context"
"go.opencensus.io/exemplar"
)
// FromContext returns the tag map stored in the context. // FromContext returns the tag map stored in the context.
func FromContext(ctx context.Context) *Map { func FromContext(ctx context.Context) *Map {
@ -39,3 +43,25 @@ func NewContext(ctx context.Context, m *Map) context.Context {
type ctxKey struct{} type ctxKey struct{}
var mapCtxKey = ctxKey{} var mapCtxKey = ctxKey{}
func init() {
exemplar.RegisterAttachmentExtractor(extractTagsAttachments)
}
func extractTagsAttachments(ctx context.Context, a exemplar.Attachments) exemplar.Attachments {
m := FromContext(ctx)
if m == nil {
return a
}
if len(m.m) == 0 {
return a
}
if a == nil {
a = make(map[string]string)
}
for k, v := range m.m {
a[exemplar.KeyPrefixTag+k.Name()] = v
}
return a
}

43
vendor/go.opencensus.io/trace/exemplar.go generated vendored Normal file
View File

@ -0,0 +1,43 @@
// Copyright 2018, OpenCensus Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package trace
import (
"context"
"encoding/hex"
"go.opencensus.io/exemplar"
)
func init() {
exemplar.RegisterAttachmentExtractor(attachSpanContext)
}
func attachSpanContext(ctx context.Context, a exemplar.Attachments) exemplar.Attachments {
span := FromContext(ctx)
if span == nil {
return a
}
sc := span.SpanContext()
if !sc.IsSampled() {
return a
}
if a == nil {
a = make(exemplar.Attachments)
}
a[exemplar.KeyTraceID] = hex.EncodeToString(sc.TraceID[:])
a[exemplar.KeySpanID] = hex.EncodeToString(sc.SpanID[:])
return a
}

View File

@ -243,13 +243,16 @@ func startSpanInternal(name string, hasParent bool, parent SpanContext, remotePa
// End ends the span. // End ends the span.
func (s *Span) End() { func (s *Span) End() {
if s == nil {
return
}
if s.executionTracerTaskEnd != nil {
s.executionTracerTaskEnd()
}
if !s.IsRecordingEvents() { if !s.IsRecordingEvents() {
return return
} }
s.endOnce.Do(func() { s.endOnce.Do(func() {
if s.executionTracerTaskEnd != nil {
s.executionTracerTaskEnd()
}
exp, _ := exporters.Load().(exportersMap) exp, _ := exporters.Load().(exportersMap)
mustExport := s.spanContext.IsSampled() && len(exp) > 0 mustExport := s.spanContext.IsSampled() && len(exp) > 0
if s.spanStore != nil || mustExport { if s.spanStore != nil || mustExport {

View File

@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
// Package tracestate implements support for the Tracestate header of the
// W3C TraceContext propagation format.
package tracestate package tracestate
import ( import (

52
vendor/golang.org/x/oauth2/README.md generated vendored
View File

@ -19,54 +19,12 @@ See godoc for further documentation and examples.
* [godoc.org/golang.org/x/oauth2](http://godoc.org/golang.org/x/oauth2) * [godoc.org/golang.org/x/oauth2](http://godoc.org/golang.org/x/oauth2)
* [godoc.org/golang.org/x/oauth2/google](http://godoc.org/golang.org/x/oauth2/google) * [godoc.org/golang.org/x/oauth2/google](http://godoc.org/golang.org/x/oauth2/google)
## Policy for new packages
## App Engine We no longer accept new provider-specific packages in this repo. For
defining provider endpoints and provider-specific OAuth2 behavior, we
In change 96e89be (March 2015), we removed the `oauth2.Context2` type in favor encourage you to create packages elsewhere. We'll keep the existing
of the [`context.Context`](https://golang.org/x/net/context#Context) type from packages for compatibility.
the `golang.org/x/net/context` package
This means it's no longer possible to use the "Classic App Engine"
`appengine.Context` type with the `oauth2` package. (You're using
Classic App Engine if you import the package `"appengine"`.)
To work around this, you may use the new `"google.golang.org/appengine"`
package. This package has almost the same API as the `"appengine"` package,
but it can be fetched with `go get` and used on "Managed VMs" and well as
Classic App Engine.
See the [new `appengine` package's readme](https://github.com/golang/appengine#updating-a-go-app-engine-app)
for information on updating your app.
If you don't want to update your entire app to use the new App Engine packages,
you may use both sets of packages in parallel, using only the new packages
with the `oauth2` package.
```go
import (
"golang.org/x/net/context"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
newappengine "google.golang.org/appengine"
newurlfetch "google.golang.org/appengine/urlfetch"
"appengine"
)
func handler(w http.ResponseWriter, r *http.Request) {
var c appengine.Context = appengine.NewContext(r)
c.Infof("Logging a message with the old package")
var ctx context.Context = newappengine.NewContext(r)
client := &http.Client{
Transport: &oauth2.Transport{
Source: google.AppEngineTokenSource(ctx, "scope"),
Base: &newurlfetch.Transport{Context: ctx},
},
}
client.Get("...")
}
```
## Report Issues / Send Patches ## Report Issues / Send Patches

10
vendor/golang.org/x/oauth2/go.mod generated vendored Normal file
View File

@ -0,0 +1,10 @@
module golang.org/x/oauth2
go 1.11
require (
cloud.google.com/go v0.34.0
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 // indirect
google.golang.org/appengine v1.4.0
)

12
vendor/golang.org/x/oauth2/go.sum generated vendored Normal file
View File

@ -0,0 +1,12 @@
cloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
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=

View File

@ -5,85 +5,34 @@
package google package google
import ( import (
"sort" "context"
"strings"
"sync"
"time" "time"
"golang.org/x/net/context"
"golang.org/x/oauth2" "golang.org/x/oauth2"
) )
// appengineFlex is set at init time by appengineflex_hook.go. If true, we are on App Engine Flex. // Set at init time by appengine_gen1.go. If nil, we're not on App Engine standard first generation (<= Go 1.9) or App Engine flexible.
var appengineFlex bool
// Set at init time by appengine_hook.go. If nil, we're not on App Engine.
var appengineTokenFunc func(c context.Context, scopes ...string) (token string, expiry time.Time, err error) var appengineTokenFunc func(c context.Context, scopes ...string) (token string, expiry time.Time, err error)
// Set at init time by appengine_hook.go. If nil, we're not on App Engine. // Set at init time by appengine_gen1.go. If nil, we're not on App Engine standard first generation (<= Go 1.9) or App Engine flexible.
var appengineAppIDFunc func(c context.Context) string var appengineAppIDFunc func(c context.Context) string
// AppEngineTokenSource returns a token source that fetches tokens // AppEngineTokenSource returns a token source that fetches tokens from either
// issued to the current App Engine application's service account. // the current application's service account or from the metadata server,
// If you are implementing a 3-legged OAuth 2.0 flow on App Engine // depending on the App Engine environment. See below for environment-specific
// that involves user accounts, see oauth2.Config instead. // details. If you are implementing a 3-legged OAuth 2.0 flow on App Engine that
// involves user accounts, see oauth2.Config instead.
// //
// The provided context must have come from appengine.NewContext. // First generation App Engine runtimes (<= Go 1.9):
// AppEngineTokenSource returns a token source that fetches tokens issued to the
// current App Engine application's service account. The provided context must have
// come from appengine.NewContext.
//
// Second generation App Engine runtimes (>= Go 1.11) and App Engine flexible:
// AppEngineTokenSource is DEPRECATED on second generation runtimes and on the
// flexible environment. It delegates to ComputeTokenSource, and the provided
// context and scopes are not used. Please use DefaultTokenSource (or ComputeTokenSource,
// which DefaultTokenSource will use in this case) instead.
func AppEngineTokenSource(ctx context.Context, scope ...string) oauth2.TokenSource { func AppEngineTokenSource(ctx context.Context, scope ...string) oauth2.TokenSource {
if appengineTokenFunc == nil { return appEngineTokenSource(ctx, scope...)
panic("google: AppEngineTokenSource can only be used on App Engine.")
}
scopes := append([]string{}, scope...)
sort.Strings(scopes)
return &appEngineTokenSource{
ctx: ctx,
scopes: scopes,
key: strings.Join(scopes, " "),
}
}
// aeTokens helps the fetched tokens to be reused until their expiration.
var (
aeTokensMu sync.Mutex
aeTokens = make(map[string]*tokenLock) // key is space-separated scopes
)
type tokenLock struct {
mu sync.Mutex // guards t; held while fetching or updating t
t *oauth2.Token
}
type appEngineTokenSource struct {
ctx context.Context
scopes []string
key string // to aeTokens map; space-separated scopes
}
func (ts *appEngineTokenSource) Token() (*oauth2.Token, error) {
if appengineTokenFunc == nil {
panic("google: AppEngineTokenSource can only be used on App Engine.")
}
aeTokensMu.Lock()
tok, ok := aeTokens[ts.key]
if !ok {
tok = &tokenLock{}
aeTokens[ts.key] = tok
}
aeTokensMu.Unlock()
tok.mu.Lock()
defer tok.mu.Unlock()
if tok.t.Valid() {
return tok.t, nil
}
access, exp, err := appengineTokenFunc(ts.ctx, ts.scopes...)
if err != nil {
return nil, err
}
tok.t = &oauth2.Token{
AccessToken: access,
Expiry: exp,
}
return tok.t, nil
} }

77
vendor/golang.org/x/oauth2/google/appengine_gen1.go generated vendored Normal file
View File

@ -0,0 +1,77 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build appengine
// This file applies to App Engine first generation runtimes (<= Go 1.9).
package google
import (
"context"
"sort"
"strings"
"sync"
"golang.org/x/oauth2"
"google.golang.org/appengine"
)
func init() {
appengineTokenFunc = appengine.AccessToken
appengineAppIDFunc = appengine.AppID
}
// See comment on AppEngineTokenSource in appengine.go.
func appEngineTokenSource(ctx context.Context, scope ...string) oauth2.TokenSource {
scopes := append([]string{}, scope...)
sort.Strings(scopes)
return &gaeTokenSource{
ctx: ctx,
scopes: scopes,
key: strings.Join(scopes, " "),
}
}
// aeTokens helps the fetched tokens to be reused until their expiration.
var (
aeTokensMu sync.Mutex
aeTokens = make(map[string]*tokenLock) // key is space-separated scopes
)
type tokenLock struct {
mu sync.Mutex // guards t; held while fetching or updating t
t *oauth2.Token
}
type gaeTokenSource struct {
ctx context.Context
scopes []string
key string // to aeTokens map; space-separated scopes
}
func (ts *gaeTokenSource) Token() (*oauth2.Token, error) {
aeTokensMu.Lock()
tok, ok := aeTokens[ts.key]
if !ok {
tok = &tokenLock{}
aeTokens[ts.key] = tok
}
aeTokensMu.Unlock()
tok.mu.Lock()
defer tok.mu.Unlock()
if tok.t.Valid() {
return tok.t, nil
}
access, exp, err := appengineTokenFunc(ts.ctx, ts.scopes...)
if err != nil {
return nil, err
}
tok.t = &oauth2.Token{
AccessToken: access,
Expiry: exp,
}
return tok.t, nil
}

View File

@ -0,0 +1,27 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !appengine
// This file applies to App Engine second generation runtimes (>= Go 1.11) and App Engine flexible.
package google
import (
"context"
"log"
"sync"
"golang.org/x/oauth2"
)
var logOnce sync.Once // only spam about deprecation once
// See comment on AppEngineTokenSource in appengine.go.
func appEngineTokenSource(ctx context.Context, scope ...string) oauth2.TokenSource {
logOnce.Do(func() {
log.Print("google: AppEngineTokenSource is deprecated on App Engine standard second generation runtimes (>= Go 1.11) and App Engine flexible. Please use DefaultTokenSource or ComputeTokenSource.")
})
return ComputeTokenSource("")
}

View File

@ -1,14 +0,0 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build appengine appenginevm
package google
import "google.golang.org/appengine"
func init() {
appengineTokenFunc = appengine.AccessToken
appengineAppIDFunc = appengine.AppID
}

View File

@ -1,11 +0,0 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build appenginevm
package google
func init() {
appengineFlex = true // Flex doesn't support appengine.AccessToken; depend on metadata server.
}

View File

@ -5,6 +5,7 @@
package google package google
import ( import (
"context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
@ -14,10 +15,28 @@ import (
"runtime" "runtime"
"cloud.google.com/go/compute/metadata" "cloud.google.com/go/compute/metadata"
"golang.org/x/net/context"
"golang.org/x/oauth2" "golang.org/x/oauth2"
) )
// Credentials holds Google credentials, including "Application Default Credentials".
// For more details, see:
// https://developers.google.com/accounts/docs/application-default-credentials
type Credentials struct {
ProjectID string // may be empty
TokenSource oauth2.TokenSource
// JSON contains the raw bytes from a JSON credentials file.
// This field may be nil if authentication is provided by the
// environment and not with a credentials file, e.g. when code is
// running on Google Cloud Platform.
JSON []byte
}
// DefaultCredentials is the old name of Credentials.
//
// Deprecated: use Credentials instead.
type DefaultCredentials = Credentials
// DefaultClient returns an HTTP Client that uses the // DefaultClient returns an HTTP Client that uses the
// DefaultTokenSource to obtain authentication credentials. // DefaultTokenSource to obtain authentication credentials.
func DefaultClient(ctx context.Context, scope ...string) (*http.Client, error) { func DefaultClient(ctx context.Context, scope ...string) (*http.Client, error) {
@ -39,8 +58,23 @@ func DefaultTokenSource(ctx context.Context, scope ...string) (oauth2.TokenSourc
return creds.TokenSource, nil return creds.TokenSource, nil
} }
// Common implementation for FindDefaultCredentials. // FindDefaultCredentials searches for "Application Default Credentials".
func findDefaultCredentials(ctx context.Context, scopes []string) (*DefaultCredentials, error) { //
// It looks for credentials in the following places,
// preferring the first location found:
//
// 1. A JSON file whose path is specified by the
// GOOGLE_APPLICATION_CREDENTIALS environment variable.
// 2. A JSON file in a location known to the gcloud command-line tool.
// On Windows, this is %APPDATA%/gcloud/application_default_credentials.json.
// On other systems, $HOME/.config/gcloud/application_default_credentials.json.
// 3. On Google App Engine standard first generation runtimes (<= Go 1.9) it uses
// the appengine.AccessToken function.
// 4. On Google Compute Engine, Google App Engine standard second generation runtimes
// (>= Go 1.11), and Google App Engine flexible environment, it fetches
// credentials from the metadata server.
// (In this final case any provided scopes are ignored.)
func FindDefaultCredentials(ctx context.Context, scopes ...string) (*Credentials, error) {
// First, try the environment variable. // First, try the environment variable.
const envVar = "GOOGLE_APPLICATION_CREDENTIALS" const envVar = "GOOGLE_APPLICATION_CREDENTIALS"
if filename := os.Getenv(envVar); filename != "" { if filename := os.Getenv(envVar); filename != "" {
@ -59,15 +93,18 @@ func findDefaultCredentials(ctx context.Context, scopes []string) (*DefaultCrede
return nil, fmt.Errorf("google: error getting credentials using well-known file (%v): %v", filename, err) return nil, fmt.Errorf("google: error getting credentials using well-known file (%v): %v", filename, err)
} }
// Third, if we're on Google App Engine use those credentials. // Third, if we're on a Google App Engine standard first generation runtime (<= Go 1.9)
if appengineTokenFunc != nil && !appengineFlex { // use those credentials. App Engine standard second generation runtimes (>= Go 1.11)
// and App Engine flexible use ComputeTokenSource and the metadata server.
if appengineTokenFunc != nil {
return &DefaultCredentials{ return &DefaultCredentials{
ProjectID: appengineAppIDFunc(ctx), ProjectID: appengineAppIDFunc(ctx),
TokenSource: AppEngineTokenSource(ctx, scopes...), TokenSource: AppEngineTokenSource(ctx, scopes...),
}, nil }, nil
} }
// Fourth, if we're on Google Compute Engine use the metadata server. // Fourth, if we're on Google Compute Engine, an App Engine standard second generation runtime,
// or App Engine flexible, use the metadata server.
if metadata.OnGCE() { if metadata.OnGCE() {
id, _ := metadata.ProjectID() id, _ := metadata.ProjectID()
return &DefaultCredentials{ return &DefaultCredentials{
@ -81,8 +118,11 @@ func findDefaultCredentials(ctx context.Context, scopes []string) (*DefaultCrede
return nil, fmt.Errorf("google: could not find default credentials. See %v for more information.", url) return nil, fmt.Errorf("google: could not find default credentials. See %v for more information.", url)
} }
// Common implementation for CredentialsFromJSON. // CredentialsFromJSON obtains Google credentials from a JSON value. The JSON can
func credentialsFromJSON(ctx context.Context, jsonData []byte, scopes []string) (*DefaultCredentials, error) { // represent either a Google Developers Console client_credentials.json file (as in
// ConfigFromJSON) or a Google Developers service account key file (as in
// JWTConfigFromJSON).
func CredentialsFromJSON(ctx context.Context, jsonData []byte, scopes ...string) (*Credentials, error) {
var f credentialsFile var f credentialsFile
if err := json.Unmarshal(jsonData, &f); err != nil { if err := json.Unmarshal(jsonData, &f); err != nil {
return nil, err return nil, err

View File

@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build go1.9
// Package google provides support for making OAuth2 authorized and authenticated // Package google provides support for making OAuth2 authorized and authenticated
// HTTP requests to Google APIs. It supports the Web server flow, client-side // HTTP requests to Google APIs. It supports the Web server flow, client-side
// credentials, service accounts, Google Compute Engine service accounts, and Google // credentials, service accounts, Google Compute Engine service accounts, and Google

View File

@ -1,43 +0,0 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !go1.9
// Package google provides support for making OAuth2 authorized and authenticated
// HTTP requests to Google APIs. It supports the Web server flow, client-side
// credentials, service accounts, Google Compute Engine service accounts, and Google
// App Engine service accounts.
//
// A brief overview of the package follows. For more information, please read
// https://developers.google.com/accounts/docs/OAuth2
// and
// https://developers.google.com/accounts/docs/application-default-credentials.
//
// OAuth2 Configs
//
// Two functions in this package return golang.org/x/oauth2.Config values from Google credential
// data. Google supports two JSON formats for OAuth2 credentials: one is handled by ConfigFromJSON,
// the other by JWTConfigFromJSON. The returned Config can be used to obtain a TokenSource or
// create an http.Client.
//
//
// Credentials
//
// The DefaultCredentials type represents Google Application Default Credentials, as
// well as other forms of credential.
//
// Use FindDefaultCredentials to obtain Application Default Credentials.
// FindDefaultCredentials looks in some well-known places for a credentials file, and
// will call AppEngineTokenSource or ComputeTokenSource as needed.
//
// DefaultClient and DefaultTokenSource are convenience methods. They first call FindDefaultCredentials,
// then use the credentials to construct an http.Client or an oauth2.TokenSource.
//
// Use CredentialsFromJSON to obtain credentials from either of the two JSON
// formats described in OAuth2 Configs, above. (The DefaultCredentials returned may
// not be "Application Default Credentials".) The TokenSource in the returned value
// is the same as the one obtained from the oauth2.Config returned from
// ConfigFromJSON or JWTConfigFromJSON, but the DefaultCredentials may contain
// additional information that is useful is some circumstances.
package google // import "golang.org/x/oauth2/google"

View File

@ -1,57 +0,0 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.9
package google
import (
"golang.org/x/net/context"
"golang.org/x/oauth2"
)
// Credentials holds Google credentials, including "Application Default Credentials".
// For more details, see:
// https://developers.google.com/accounts/docs/application-default-credentials
type Credentials struct {
ProjectID string // may be empty
TokenSource oauth2.TokenSource
// JSON contains the raw bytes from a JSON credentials file.
// This field may be nil if authentication is provided by the
// environment and not with a credentials file, e.g. when code is
// running on Google Cloud Platform.
JSON []byte
}
// DefaultCredentials is the old name of Credentials.
//
// Deprecated: use Credentials instead.
type DefaultCredentials = Credentials
// FindDefaultCredentials searches for "Application Default Credentials".
//
// It looks for credentials in the following places,
// preferring the first location found:
//
// 1. A JSON file whose path is specified by the
// GOOGLE_APPLICATION_CREDENTIALS environment variable.
// 2. A JSON file in a location known to the gcloud command-line tool.
// On Windows, this is %APPDATA%/gcloud/application_default_credentials.json.
// On other systems, $HOME/.config/gcloud/application_default_credentials.json.
// 3. On Google App Engine it uses the appengine.AccessToken function.
// 4. On Google Compute Engine and Google App Engine Managed VMs, it fetches
// credentials from the metadata server.
// (In this final case any provided scopes are ignored.)
func FindDefaultCredentials(ctx context.Context, scopes ...string) (*Credentials, error) {
return findDefaultCredentials(ctx, scopes)
}
// CredentialsFromJSON obtains Google credentials from a JSON value. The JSON can
// represent either a Google Developers Console client_credentials.json file (as in
// ConfigFromJSON) or a Google Developers service account key file (as in
// JWTConfigFromJSON).
func CredentialsFromJSON(ctx context.Context, jsonData []byte, scopes ...string) (*Credentials, error) {
return credentialsFromJSON(ctx, jsonData, scopes)
}

View File

@ -5,6 +5,7 @@
package google package google
import ( import (
"context"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
@ -12,15 +13,15 @@ import (
"time" "time"
"cloud.google.com/go/compute/metadata" "cloud.google.com/go/compute/metadata"
"golang.org/x/net/context"
"golang.org/x/oauth2" "golang.org/x/oauth2"
"golang.org/x/oauth2/jwt" "golang.org/x/oauth2/jwt"
) )
// Endpoint is Google's OAuth 2.0 endpoint. // Endpoint is Google's OAuth 2.0 endpoint.
var Endpoint = oauth2.Endpoint{ var Endpoint = oauth2.Endpoint{
AuthURL: "https://accounts.google.com/o/oauth2/auth", AuthURL: "https://accounts.google.com/o/oauth2/auth",
TokenURL: "https://accounts.google.com/o/oauth2/token", TokenURL: "https://accounts.google.com/o/oauth2/token",
AuthStyle: oauth2.AuthStyleInParams,
} }
// JWTTokenURL is Google's OAuth 2.0 token URL to use with the JWT flow. // JWTTokenURL is Google's OAuth 2.0 token URL to use with the JWT flow.

View File

@ -1,54 +0,0 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !go1.9
package google
import (
"golang.org/x/net/context"
"golang.org/x/oauth2"
)
// DefaultCredentials holds Google credentials, including "Application Default Credentials".
// For more details, see:
// https://developers.google.com/accounts/docs/application-default-credentials
type DefaultCredentials struct {
ProjectID string // may be empty
TokenSource oauth2.TokenSource
// JSON contains the raw bytes from a JSON credentials file.
// This field may be nil if authentication is provided by the
// environment and not with a credentials file, e.g. when code is
// running on Google Cloud Platform.
JSON []byte
}
// FindDefaultCredentials searches for "Application Default Credentials".
//
// It looks for credentials in the following places,
// preferring the first location found:
//
// 1. A JSON file whose path is specified by the
// GOOGLE_APPLICATION_CREDENTIALS environment variable.
// 2. A JSON file in a location known to the gcloud command-line tool.
// On Windows, this is %APPDATA%/gcloud/application_default_credentials.json.
// On other systems, $HOME/.config/gcloud/application_default_credentials.json.
// 3. On Google App Engine it uses the appengine.AccessToken function.
// 4. On Google Compute Engine and Google App Engine Managed VMs, it fetches
// credentials from the metadata server.
// (In this final case any provided scopes are ignored.)
func FindDefaultCredentials(ctx context.Context, scopes ...string) (*DefaultCredentials, error) {
return findDefaultCredentials(ctx, scopes)
}
// CredentialsFromJSON obtains Google credentials from a JSON value. The JSON can
// represent either a Google Developers Console client_credentials.json file (as in
// ConfigFromJSON) or a Google Developers service account key file (as in
// JWTConfigFromJSON).
//
// Note: despite the name, the returned credentials may not be Application Default Credentials.
func CredentialsFromJSON(ctx context.Context, jsonData []byte, scopes ...string) (*DefaultCredentials, error) {
return credentialsFromJSON(ctx, jsonData, scopes)
}

View File

@ -6,6 +6,7 @@ package google
import ( import (
"bufio" "bufio"
"context"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
@ -18,7 +19,6 @@ import (
"strings" "strings"
"time" "time"
"golang.org/x/net/context"
"golang.org/x/oauth2" "golang.org/x/oauth2"
) )

View File

@ -26,7 +26,7 @@ func ParseKey(key []byte) (*rsa.PrivateKey, error) {
if err != nil { if err != nil {
parsedKey, err = x509.ParsePKCS1PrivateKey(key) parsedKey, err = x509.ParsePKCS1PrivateKey(key)
if err != nil { if err != nil {
return nil, fmt.Errorf("private key should be a PEM or plain PKSC1 or PKCS8; parse error: %v", err) return nil, fmt.Errorf("private key should be a PEM or plain PKCS1 or PKCS8; parse error: %v", err)
} }
} }
parsed, ok := parsedKey.(*rsa.PrivateKey) parsed, ok := parsedKey.(*rsa.PrivateKey)

View File

@ -5,6 +5,7 @@
package internal package internal
import ( import (
"context"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
@ -15,9 +16,9 @@ import (
"net/url" "net/url"
"strconv" "strconv"
"strings" "strings"
"sync"
"time" "time"
"golang.org/x/net/context"
"golang.org/x/net/context/ctxhttp" "golang.org/x/net/context/ctxhttp"
) )
@ -77,6 +78,9 @@ func (e *tokenJSON) expiry() (t time.Time) {
type expirationTime int32 type expirationTime int32
func (e *expirationTime) UnmarshalJSON(b []byte) error { func (e *expirationTime) UnmarshalJSON(b []byte) error {
if len(b) == 0 || string(b) == "null" {
return nil
}
var n json.Number var n json.Number
err := json.Unmarshal(b, &n) err := json.Unmarshal(b, &n)
if err != nil { if err != nil {
@ -90,98 +94,71 @@ func (e *expirationTime) UnmarshalJSON(b []byte) error {
return nil return nil
} }
var brokenAuthHeaderProviders = []string{ // RegisterBrokenAuthHeaderProvider previously did something. It is now a no-op.
"https://accounts.google.com/", //
"https://api.codeswholesale.com/oauth/token", // Deprecated: this function no longer does anything. Caller code that
"https://api.dropbox.com/", // wants to avoid potential extra HTTP requests made during
"https://api.dropboxapi.com/", // auto-probing of the provider's auth style should set
"https://api.instagram.com/", // Endpoint.AuthStyle.
"https://api.netatmo.net/", func RegisterBrokenAuthHeaderProvider(tokenURL string) {}
"https://api.odnoklassniki.ru/",
"https://api.pushbullet.com/", // AuthStyle is a copy of the golang.org/x/oauth2 package's AuthStyle type.
"https://api.soundcloud.com/", type AuthStyle int
"https://api.twitch.tv/",
"https://id.twitch.tv/", const (
"https://app.box.com/", AuthStyleUnknown AuthStyle = 0
"https://api.box.com/", AuthStyleInParams AuthStyle = 1
"https://connect.stripe.com/", AuthStyleInHeader AuthStyle = 2
"https://login.mailchimp.com/", )
"https://login.microsoftonline.com/",
"https://login.salesforce.com/", // authStyleCache is the set of tokenURLs we've successfully used via
"https://login.windows.net", // RetrieveToken and which style auth we ended up using.
"https://login.live.com/", // It's called a cache, but it doesn't (yet?) shrink. It's expected that
"https://login.live-int.com/", // the set of OAuth2 servers a program contacts over time is fixed and
"https://oauth.sandbox.trainingpeaks.com/", // small.
"https://oauth.trainingpeaks.com/", var authStyleCache struct {
"https://oauth.vk.com/", sync.Mutex
"https://openapi.baidu.com/", m map[string]AuthStyle // keyed by tokenURL
"https://slack.com/",
"https://test-sandbox.auth.corp.google.com",
"https://test.salesforce.com/",
"https://user.gini.net/",
"https://www.douban.com/",
"https://www.googleapis.com/",
"https://www.linkedin.com/",
"https://www.strava.com/oauth/",
"https://www.wunderlist.com/oauth/",
"https://api.patreon.com/",
"https://sandbox.codeswholesale.com/oauth/token",
"https://api.sipgate.com/v1/authorization/oauth",
"https://api.medium.com/v1/tokens",
"https://log.finalsurge.com/oauth/token",
"https://multisport.todaysplan.com.au/rest/oauth/access_token",
"https://whats.todaysplan.com.au/rest/oauth/access_token",
"https://stackoverflow.com/oauth/access_token",
"https://account.health.nokia.com",
} }
// brokenAuthHeaderDomains lists broken providers that issue dynamic endpoints. // ResetAuthCache resets the global authentication style cache used
var brokenAuthHeaderDomains = []string{ // for AuthStyleUnknown token requests.
".auth0.com", func ResetAuthCache() {
".force.com", authStyleCache.Lock()
".myshopify.com", defer authStyleCache.Unlock()
".okta.com", authStyleCache.m = nil
".oktapreview.com",
} }
func RegisterBrokenAuthHeaderProvider(tokenURL string) { // lookupAuthStyle reports which auth style we last used with tokenURL
brokenAuthHeaderProviders = append(brokenAuthHeaderProviders, tokenURL) // when calling RetrieveToken and whether we have ever done so.
func lookupAuthStyle(tokenURL string) (style AuthStyle, ok bool) {
authStyleCache.Lock()
defer authStyleCache.Unlock()
style, ok = authStyleCache.m[tokenURL]
return
} }
// providerAuthHeaderWorks reports whether the OAuth2 server identified by the tokenURL // setAuthStyle adds an entry to authStyleCache, documented above.
// implements the OAuth2 spec correctly func setAuthStyle(tokenURL string, v AuthStyle) {
// See https://code.google.com/p/goauth2/issues/detail?id=31 for background. authStyleCache.Lock()
// In summary: defer authStyleCache.Unlock()
// - Reddit only accepts client secret in the Authorization header if authStyleCache.m == nil {
// - Dropbox accepts either it in URL param or Auth header, but not both. authStyleCache.m = make(map[string]AuthStyle)
// - Google only accepts URL param (not spec compliant?), not Auth header
// - Stripe only accepts client secret in Auth header with Bearer method, not Basic
func providerAuthHeaderWorks(tokenURL string) bool {
for _, s := range brokenAuthHeaderProviders {
if strings.HasPrefix(tokenURL, s) {
// Some sites fail to implement the OAuth2 spec fully.
return false
}
} }
authStyleCache.m[tokenURL] = v
if u, err := url.Parse(tokenURL); err == nil {
for _, s := range brokenAuthHeaderDomains {
if strings.HasSuffix(u.Host, s) {
return false
}
}
}
// Assume the provider implements the spec properly
// otherwise. We can add more exceptions as they're
// discovered. We will _not_ be adding configurable hooks
// to this package to let users select server bugs.
return true
} }
func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string, v url.Values) (*Token, error) { // newTokenRequest returns a new *http.Request to retrieve a new token
bustedAuth := !providerAuthHeaderWorks(tokenURL) // from tokenURL using the provided clientID, clientSecret, and POST
if bustedAuth { // body parameters.
//
// inParams is whether the clientID & clientSecret should be encoded
// as the POST body. An 'inParams' value of true means to send it in
// the POST body (along with any values in v); false means to send it
// in the Authorization header.
func newTokenRequest(tokenURL, clientID, clientSecret string, v url.Values, authStyle AuthStyle) (*http.Request, error) {
if authStyle == AuthStyleInParams {
v = cloneURLValues(v)
if clientID != "" { if clientID != "" {
v.Set("client_id", clientID) v.Set("client_id", clientID)
} }
@ -194,15 +171,70 @@ func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string,
return nil, err return nil, err
} }
req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
if !bustedAuth { if authStyle == AuthStyleInHeader {
req.SetBasicAuth(url.QueryEscape(clientID), url.QueryEscape(clientSecret)) req.SetBasicAuth(url.QueryEscape(clientID), url.QueryEscape(clientSecret))
} }
return req, nil
}
func cloneURLValues(v url.Values) url.Values {
v2 := make(url.Values, len(v))
for k, vv := range v {
v2[k] = append([]string(nil), vv...)
}
return v2
}
func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string, v url.Values, authStyle AuthStyle) (*Token, error) {
needsAuthStyleProbe := authStyle == 0
if needsAuthStyleProbe {
if style, ok := lookupAuthStyle(tokenURL); ok {
authStyle = style
needsAuthStyleProbe = false
} else {
authStyle = AuthStyleInHeader // the first way we'll try
}
}
req, err := newTokenRequest(tokenURL, clientID, clientSecret, v, authStyle)
if err != nil {
return nil, err
}
token, err := doTokenRoundTrip(ctx, req)
if err != nil && needsAuthStyleProbe {
// If we get an error, assume the server wants the
// clientID & clientSecret in a different form.
// See https://code.google.com/p/goauth2/issues/detail?id=31 for background.
// In summary:
// - Reddit only accepts client secret in the Authorization header
// - Dropbox accepts either it in URL param or Auth header, but not both.
// - Google only accepts URL param (not spec compliant?), not Auth header
// - Stripe only accepts client secret in Auth header with Bearer method, not Basic
//
// We used to maintain a big table in this code of all the sites and which way
// they went, but maintaining it didn't scale & got annoying.
// So just try both ways.
authStyle = AuthStyleInParams // the second way we'll try
req, _ = newTokenRequest(tokenURL, clientID, clientSecret, v, authStyle)
token, err = doTokenRoundTrip(ctx, req)
}
if needsAuthStyleProbe && err == nil {
setAuthStyle(tokenURL, authStyle)
}
// Don't overwrite `RefreshToken` with an empty value
// if this was a token refreshing request.
if token != nil && token.RefreshToken == "" {
token.RefreshToken = v.Get("refresh_token")
}
return token, err
}
func doTokenRoundTrip(ctx context.Context, req *http.Request) (*Token, error) {
r, err := ctxhttp.Do(ctx, ContextClient(ctx), req) r, err := ctxhttp.Do(ctx, ContextClient(ctx), req)
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer r.Body.Close()
body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1<<20)) body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1<<20))
r.Body.Close()
if err != nil { if err != nil {
return nil, fmt.Errorf("oauth2: cannot fetch token: %v", err) return nil, fmt.Errorf("oauth2: cannot fetch token: %v", err)
} }
@ -228,7 +260,7 @@ func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string,
Raw: vals, Raw: vals,
} }
e := vals.Get("expires_in") e := vals.Get("expires_in")
if e == "" { if e == "" || e == "null" {
// TODO(jbd): Facebook's OAuth2 implementation is broken and // TODO(jbd): Facebook's OAuth2 implementation is broken and
// returns expires_in field in expires. Remove the fallback to expires, // returns expires_in field in expires. Remove the fallback to expires,
// when Facebook fixes their implementation. // when Facebook fixes their implementation.
@ -252,13 +284,8 @@ func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string,
} }
json.Unmarshal(body, &token.Raw) // no error checks for optional fields json.Unmarshal(body, &token.Raw) // no error checks for optional fields
} }
// Don't overwrite `RefreshToken` with an empty value
// if this was a token refreshing request.
if token.RefreshToken == "" {
token.RefreshToken = v.Get("refresh_token")
}
if token.AccessToken == "" { if token.AccessToken == "" {
return token, errors.New("oauth2: server response missing access_token") return nil, errors.New("oauth2: server response missing access_token")
} }
return token, nil return token, nil
} }

View File

@ -5,9 +5,8 @@
package internal package internal
import ( import (
"context"
"net/http" "net/http"
"golang.org/x/net/context"
) )
// HTTPClient is the context key to use with golang.org/x/net/context's // HTTPClient is the context key to use with golang.org/x/net/context's

View File

@ -9,6 +9,7 @@
package jwt package jwt
import ( import (
"context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
@ -18,7 +19,6 @@ import (
"strings" "strings"
"time" "time"
"golang.org/x/net/context"
"golang.org/x/oauth2" "golang.org/x/oauth2"
"golang.org/x/oauth2/internal" "golang.org/x/oauth2/internal"
"golang.org/x/oauth2/jws" "golang.org/x/oauth2/jws"
@ -61,6 +61,11 @@ type Config struct {
// Expires optionally specifies how long the token is valid for. // Expires optionally specifies how long the token is valid for.
Expires time.Duration Expires time.Duration
// Audience optionally specifies the intended audience of the
// request. If empty, the value of TokenURL is used as the
// intended audience.
Audience string
} }
// TokenSource returns a JWT TokenSource using the configuration // TokenSource returns a JWT TokenSource using the configuration
@ -105,6 +110,9 @@ func (js jwtSource) Token() (*oauth2.Token, error) {
if t := js.conf.Expires; t > 0 { if t := js.conf.Expires; t > 0 {
claimSet.Exp = time.Now().Add(t).Unix() claimSet.Exp = time.Now().Add(t).Unix()
} }
if aud := js.conf.Audience; aud != "" {
claimSet.Aud = aud
}
h := *defaultHeader h := *defaultHeader
h.KeyID = js.conf.PrivateKeyID h.KeyID = js.conf.PrivateKeyID
payload, err := jws.Encode(&h, claimSet, pk) payload, err := jws.Encode(&h, claimSet, pk)

55
vendor/golang.org/x/oauth2/oauth2.go generated vendored
View File

@ -10,13 +10,13 @@ package oauth2 // import "golang.org/x/oauth2"
import ( import (
"bytes" "bytes"
"context"
"errors" "errors"
"net/http" "net/http"
"net/url" "net/url"
"strings" "strings"
"sync" "sync"
"golang.org/x/net/context"
"golang.org/x/oauth2/internal" "golang.org/x/oauth2/internal"
) )
@ -26,17 +26,13 @@ import (
// Deprecated: Use context.Background() or context.TODO() instead. // Deprecated: Use context.Background() or context.TODO() instead.
var NoContext = context.TODO() var NoContext = context.TODO()
// RegisterBrokenAuthHeaderProvider registers an OAuth2 server // RegisterBrokenAuthHeaderProvider previously did something. It is now a no-op.
// identified by the tokenURL prefix as an OAuth2 implementation //
// which doesn't support the HTTP Basic authentication // Deprecated: this function no longer does anything. Caller code that
// scheme to authenticate with the authorization server. // wants to avoid potential extra HTTP requests made during
// Once a server is registered, credentials (client_id and client_secret) // auto-probing of the provider's auth style should set
// will be passed as query parameters rather than being present // Endpoint.AuthStyle.
// in the Authorization header. func RegisterBrokenAuthHeaderProvider(tokenURL string) {}
// See https://code.google.com/p/goauth2/issues/detail?id=31 for background.
func RegisterBrokenAuthHeaderProvider(tokenURL string) {
internal.RegisterBrokenAuthHeaderProvider(tokenURL)
}
// Config describes a typical 3-legged OAuth2 flow, with both the // Config describes a typical 3-legged OAuth2 flow, with both the
// client application information and the server's endpoint URLs. // client application information and the server's endpoint URLs.
@ -71,13 +67,38 @@ type TokenSource interface {
Token() (*Token, error) Token() (*Token, error)
} }
// Endpoint contains the OAuth 2.0 provider's authorization and token // Endpoint represents an OAuth 2.0 provider's authorization and token
// endpoint URLs. // endpoint URLs.
type Endpoint struct { type Endpoint struct {
AuthURL string AuthURL string
TokenURL string TokenURL string
// AuthStyle optionally specifies how the endpoint wants the
// client ID & client secret sent. The zero value means to
// auto-detect.
AuthStyle AuthStyle
} }
// AuthStyle represents how requests for tokens are authenticated
// to the server.
type AuthStyle int
const (
// AuthStyleAutoDetect means to auto-detect which authentication
// style the provider wants by trying both ways and caching
// the successful way for the future.
AuthStyleAutoDetect AuthStyle = 0
// AuthStyleInParams sends the "client_id" and "client_secret"
// in the POST body as application/x-www-form-urlencoded parameters.
AuthStyleInParams AuthStyle = 1
// AuthStyleInHeader sends the client_id and client_password
// using HTTP Basic Authorization. This is an optional style
// described in the OAuth2 RFC 6749 section 2.3.1.
AuthStyleInHeader AuthStyle = 2
)
var ( var (
// AccessTypeOnline and AccessTypeOffline are options passed // AccessTypeOnline and AccessTypeOffline are options passed
// to the Options.AuthCodeURL method. They modify the // to the Options.AuthCodeURL method. They modify the
@ -124,7 +145,7 @@ func SetAuthURLParam(key, value string) AuthCodeOption {
// //
// Opts may include AccessTypeOnline or AccessTypeOffline, as well // Opts may include AccessTypeOnline or AccessTypeOffline, as well
// as ApprovalForce. // as ApprovalForce.
// It can also be used to pass the PKCE challange. // It can also be used to pass the PKCE challenge.
// See https://www.oauth.com/oauth2-servers/pkce/ for more info. // See https://www.oauth.com/oauth2-servers/pkce/ for more info.
func (c *Config) AuthCodeURL(state string, opts ...AuthCodeOption) string { func (c *Config) AuthCodeURL(state string, opts ...AuthCodeOption) string {
var buf bytes.Buffer var buf bytes.Buffer
@ -164,8 +185,7 @@ func (c *Config) AuthCodeURL(state string, opts ...AuthCodeOption) string {
// and when other authorization grant types are not available." // and when other authorization grant types are not available."
// See https://tools.ietf.org/html/rfc6749#section-4.3 for more info. // See https://tools.ietf.org/html/rfc6749#section-4.3 for more info.
// //
// The HTTP client to use is derived from the context. // The provided context optionally controls which HTTP client is used. See the HTTPClient variable.
// If nil, http.DefaultClient is used.
func (c *Config) PasswordCredentialsToken(ctx context.Context, username, password string) (*Token, error) { func (c *Config) PasswordCredentialsToken(ctx context.Context, username, password string) (*Token, error) {
v := url.Values{ v := url.Values{
"grant_type": {"password"}, "grant_type": {"password"},
@ -183,8 +203,7 @@ func (c *Config) PasswordCredentialsToken(ctx context.Context, username, passwor
// It is used after a resource provider redirects the user back // It is used after a resource provider redirects the user back
// to the Redirect URI (the URL obtained from AuthCodeURL). // to the Redirect URI (the URL obtained from AuthCodeURL).
// //
// The HTTP client to use is derived from the context. // The provided context optionally controls which HTTP client is used. See the HTTPClient variable.
// If a client is not provided via the context, http.DefaultClient is used.
// //
// The code will be in the *http.Request.FormValue("code"). Before // The code will be in the *http.Request.FormValue("code"). Before
// calling Exchange, be sure to validate FormValue("state"). // calling Exchange, be sure to validate FormValue("state").

View File

@ -5,6 +5,7 @@
package oauth2 package oauth2
import ( import (
"context"
"fmt" "fmt"
"net/http" "net/http"
"net/url" "net/url"
@ -12,7 +13,6 @@ import (
"strings" "strings"
"time" "time"
"golang.org/x/net/context"
"golang.org/x/oauth2/internal" "golang.org/x/oauth2/internal"
) )
@ -118,13 +118,16 @@ func (t *Token) Extra(key string) interface{} {
return v return v
} }
// timeNow is time.Now but pulled out as a variable for tests.
var timeNow = time.Now
// expired reports whether the token is expired. // expired reports whether the token is expired.
// t must be non-nil. // t must be non-nil.
func (t *Token) expired() bool { func (t *Token) expired() bool {
if t.Expiry.IsZero() { if t.Expiry.IsZero() {
return false return false
} }
return t.Expiry.Round(0).Add(-expiryDelta).Before(time.Now()) return t.Expiry.Round(0).Add(-expiryDelta).Before(timeNow())
} }
// Valid reports whether t is non-nil, has an AccessToken, and is not expired. // Valid reports whether t is non-nil, has an AccessToken, and is not expired.
@ -151,7 +154,7 @@ func tokenFromInternal(t *internal.Token) *Token {
// This token is then mapped from *internal.Token into an *oauth2.Token which is returned along // This token is then mapped from *internal.Token into an *oauth2.Token which is returned along
// with an error.. // with an error..
func retrieveToken(ctx context.Context, c *Config, v url.Values) (*Token, error) { func retrieveToken(ctx context.Context, c *Config, v url.Values) (*Token, error) {
tk, err := internal.RetrieveToken(ctx, c.ClientID, c.ClientSecret, c.Endpoint.TokenURL, v) tk, err := internal.RetrieveToken(ctx, c.ClientID, c.ClientSecret, c.Endpoint.TokenURL, v, internal.AuthStyle(c.Endpoint.AuthStyle))
if err != nil { if err != nil {
if rErr, ok := err.(*internal.RetrieveError); ok { if rErr, ok := err.(*internal.RetrieveError); ok {
return nil, (*RetrieveError)(rErr) return nil, (*RetrieveError)(rErr)

View File

@ -124,7 +124,7 @@ func (e *Encoder) Writer(w io.Writer) io.Writer {
} }
// ASCIISub is the ASCII substitute character, as recommended by // ASCIISub is the ASCII substitute character, as recommended by
// http://unicode.org/reports/tr36/#Text_Comparison // https://unicode.org/reports/tr36/#Text_Comparison
const ASCIISub = '\x1a' const ASCIISub = '\x1a'
// Nop is the nop encoding. Its transformed bytes are the same as the source // Nop is the nop encoding. Its transformed bytes are the same as the source

View File

@ -306,6 +306,7 @@ var nameMap = map[string]htmlEncoding{
"iso-2022-cn": replacement, "iso-2022-cn": replacement,
"iso-2022-cn-ext": replacement, "iso-2022-cn-ext": replacement,
"iso-2022-kr": replacement, "iso-2022-kr": replacement,
"replacement": replacement,
"utf-16be": utf16be, "utf-16be": utf16be,
"utf-16": utf16le, "utf-16": utf16le,
"utf-16le": utf16le, "utf-16le": utf16le,

View File

@ -34,7 +34,7 @@ package identifier
// - http://www.iana.org/assignments/character-sets/character-sets.xhtml // - http://www.iana.org/assignments/character-sets/character-sets.xhtml
// - http://www.iana.org/assignments/ianacharset-mib/ianacharset-mib // - http://www.iana.org/assignments/ianacharset-mib/ianacharset-mib
// - http://www.ietf.org/rfc/rfc2978.txt // - http://www.ietf.org/rfc/rfc2978.txt
// - http://www.unicode.org/reports/tr22/ // - https://www.unicode.org/reports/tr22/
// - http://www.w3.org/TR/encoding/ // - http://www.w3.org/TR/encoding/
// - https://encoding.spec.whatwg.org/ // - https://encoding.spec.whatwg.org/
// - https://encoding.spec.whatwg.org/encodings.json // - https://encoding.spec.whatwg.org/encodings.json

View File

@ -884,27 +884,27 @@ const (
// CESU8 is the MIB identifier with IANA name CESU-8. // CESU8 is the MIB identifier with IANA name CESU-8.
// //
// http://www.unicode.org/unicode/reports/tr26 // https://www.unicode.org/unicode/reports/tr26
CESU8 MIB = 1016 CESU8 MIB = 1016
// UTF32 is the MIB identifier with IANA name UTF-32. // UTF32 is the MIB identifier with IANA name UTF-32.
// //
// http://www.unicode.org/unicode/reports/tr19/ // https://www.unicode.org/unicode/reports/tr19/
UTF32 MIB = 1017 UTF32 MIB = 1017
// UTF32BE is the MIB identifier with IANA name UTF-32BE. // UTF32BE is the MIB identifier with IANA name UTF-32BE.
// //
// http://www.unicode.org/unicode/reports/tr19/ // https://www.unicode.org/unicode/reports/tr19/
UTF32BE MIB = 1018 UTF32BE MIB = 1018
// UTF32LE is the MIB identifier with IANA name UTF-32LE. // UTF32LE is the MIB identifier with IANA name UTF-32LE.
// //
// http://www.unicode.org/unicode/reports/tr19/ // https://www.unicode.org/unicode/reports/tr19/
UTF32LE MIB = 1019 UTF32LE MIB = 1019
// BOCU1 is the MIB identifier with IANA name BOCU-1. // BOCU1 is the MIB identifier with IANA name BOCU-1.
// //
// http://www.unicode.org/notes/tn6/ // https://www.unicode.org/notes/tn6/
BOCU1 MIB = 1020 BOCU1 MIB = 1020
// Windows30Latin1 is the MIB identifier with IANA name ISO-8859-1-Windows-3.0-Latin-1. // Windows30Latin1 is the MIB identifier with IANA name ISO-8859-1-Windows-3.0-Latin-1.

View File

@ -10,8 +10,8 @@ package main
// go run maketables.go | gofmt > tables.go // go run maketables.go | gofmt > tables.go
// TODO: Emoji extensions? // TODO: Emoji extensions?
// http://www.unicode.org/faq/emoji_dingbats.html // https://www.unicode.org/faq/emoji_dingbats.html
// http://www.unicode.org/Public/UNIDATA/EmojiSources.txt // https://www.unicode.org/Public/UNIDATA/EmojiSources.txt
import ( import (
"bufio" "bufio"

View File

@ -145,7 +145,7 @@ func (utf8Decoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err e
// and consumed in a greater context that implies a certain endianness, use // and consumed in a greater context that implies a certain endianness, use
// IgnoreBOM. Otherwise, use ExpectBOM and always produce and consume a BOM. // IgnoreBOM. Otherwise, use ExpectBOM and always produce and consume a BOM.
// //
// In the language of http://www.unicode.org/faq/utf_bom.html#bom10, IgnoreBOM // In the language of https://www.unicode.org/faq/utf_bom.html#bom10, IgnoreBOM
// corresponds to "Where the precise type of the data stream is known... the // corresponds to "Where the precise type of the data stream is known... the
// BOM should not be used" and ExpectBOM corresponds to "A particular // BOM should not be used" and ExpectBOM corresponds to "A particular
// protocol... may require use of the BOM". // protocol... may require use of the BOM".

View File

@ -4,13 +4,13 @@ package language
// This file contains code common to the maketables.go and the package code. // This file contains code common to the maketables.go and the package code.
// langAliasType is the type of an alias in langAliasMap. // AliasType is the type of an alias in AliasMap.
type langAliasType int8 type AliasType int8
const ( const (
langDeprecated langAliasType = iota Deprecated AliasType = iota
langMacro Macro
langLegacy Legacy
langAliasTypeUnknown langAliasType = -1 AliasTypeUnknown AliasType = -1
) )

29
vendor/golang.org/x/text/internal/language/compact.go generated vendored Normal file
View File

@ -0,0 +1,29 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package language
// CompactCoreInfo is a compact integer with the three core tags encoded.
type CompactCoreInfo uint32
// GetCompactCore generates a uint32 value that is guaranteed to be unique for
// different language, region, and script values.
func GetCompactCore(t Tag) (cci CompactCoreInfo, ok bool) {
if t.LangID > langNoIndexOffset {
return 0, false
}
cci |= CompactCoreInfo(t.LangID) << (8 + 12)
cci |= CompactCoreInfo(t.ScriptID) << 12
cci |= CompactCoreInfo(t.RegionID)
return cci, true
}
// Tag generates a tag from c.
func (c CompactCoreInfo) Tag() Tag {
return Tag{
LangID: Language(c >> 20),
RegionID: Region(c & 0x3ff),
ScriptID: Script(c>>12) & 0xff,
}
}

View File

@ -0,0 +1,61 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package compact defines a compact representation of language tags.
//
// Common language tags (at least all for which locale information is defined
// in CLDR) are assigned a unique index. Each Tag is associated with such an
// ID for selecting language-related resources (such as translations) as well
// as one for selecting regional defaults (currency, number formatting, etc.)
//
// It may want to export this functionality at some point, but at this point
// this is only available for use within x/text.
package compact // import "golang.org/x/text/internal/language/compact"
import (
"sort"
"strings"
"golang.org/x/text/internal/language"
)
// ID is an integer identifying a single tag.
type ID uint16
func getCoreIndex(t language.Tag) (id ID, ok bool) {
cci, ok := language.GetCompactCore(t)
if !ok {
return 0, false
}
i := sort.Search(len(coreTags), func(i int) bool {
return cci <= coreTags[i]
})
if i == len(coreTags) || coreTags[i] != cci {
return 0, false
}
return ID(i), true
}
// Parent returns the ID of the parent or the root ID if id is already the root.
func (id ID) Parent() ID {
return parents[id]
}
// Tag converts id to an internal language Tag.
func (id ID) Tag() language.Tag {
if int(id) >= len(coreTags) {
return specialTags[int(id)-len(coreTags)]
}
return coreTags[id].Tag()
}
var specialTags []language.Tag
func init() {
tags := strings.Split(specialTagsStr, " ")
specialTags = make([]language.Tag, len(tags))
for i, t := range tags {
specialTags[i] = language.MustParse(t)
}
}

View File

@ -0,0 +1,64 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ignore
// Language tag table generator.
// Data read from the web.
package main
import (
"flag"
"fmt"
"log"
"golang.org/x/text/internal/gen"
"golang.org/x/text/unicode/cldr"
)
var (
test = flag.Bool("test",
false,
"test existing tables; can be used to compare web data with package data.")
outputFile = flag.String("output",
"tables.go",
"output file for generated tables")
)
func main() {
gen.Init()
w := gen.NewCodeWriter()
defer w.WriteGoFile("tables.go", "compact")
fmt.Fprintln(w, `import "golang.org/x/text/internal/language"`)
b := newBuilder(w)
gen.WriteCLDRVersion(w)
b.writeCompactIndex()
}
type builder struct {
w *gen.CodeWriter
data *cldr.CLDR
supp *cldr.SupplementalData
}
func newBuilder(w *gen.CodeWriter) *builder {
r := gen.OpenCLDRCoreZip()
defer r.Close()
d := &cldr.Decoder{}
data, err := d.DecodeZip(r)
if err != nil {
log.Fatal(err)
}
b := builder{
w: w,
data: data,
supp: data.Supplemental(),
}
return &b
}

View File

@ -0,0 +1,113 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ignore
package main
// This file generates derivative tables based on the language package itself.
import (
"fmt"
"log"
"sort"
"strings"
"golang.org/x/text/internal/language"
)
// Compact indices:
// Note -va-X variants only apply to localization variants.
// BCP variants only ever apply to language.
// The only ambiguity between tags is with regions.
func (b *builder) writeCompactIndex() {
// Collect all language tags for which we have any data in CLDR.
m := map[language.Tag]bool{}
for _, lang := range b.data.Locales() {
// We include all locales unconditionally to be consistent with en_US.
// We want en_US, even though it has no data associated with it.
// TODO: put any of the languages for which no data exists at the end
// of the index. This allows all components based on ICU to use that
// as the cutoff point.
// if x := data.RawLDML(lang); false ||
// x.LocaleDisplayNames != nil ||
// x.Characters != nil ||
// x.Delimiters != nil ||
// x.Measurement != nil ||
// x.Dates != nil ||
// x.Numbers != nil ||
// x.Units != nil ||
// x.ListPatterns != nil ||
// x.Collations != nil ||
// x.Segmentations != nil ||
// x.Rbnf != nil ||
// x.Annotations != nil ||
// x.Metadata != nil {
// TODO: support POSIX natively, albeit non-standard.
tag := language.Make(strings.Replace(lang, "_POSIX", "-u-va-posix", 1))
m[tag] = true
// }
}
// TODO: plural rules are also defined for the deprecated tags:
// iw mo sh tl
// Consider removing these as compact tags.
// Include locales for plural rules, which uses a different structure.
for _, plurals := range b.supp.Plurals {
for _, rules := range plurals.PluralRules {
for _, lang := range strings.Split(rules.Locales, " ") {
m[language.Make(lang)] = true
}
}
}
var coreTags []language.CompactCoreInfo
var special []string
for t := range m {
if x := t.Extensions(); len(x) != 0 && fmt.Sprint(x) != "[u-va-posix]" {
log.Fatalf("Unexpected extension %v in %v", x, t)
}
if len(t.Variants()) == 0 && len(t.Extensions()) == 0 {
cci, ok := language.GetCompactCore(t)
if !ok {
log.Fatalf("Locale for non-basic language %q", t)
}
coreTags = append(coreTags, cci)
} else {
special = append(special, t.String())
}
}
w := b.w
sort.Slice(coreTags, func(i, j int) bool { return coreTags[i] < coreTags[j] })
sort.Strings(special)
w.WriteComment(`
NumCompactTags is the number of common tags. The maximum tag is
NumCompactTags-1.`)
w.WriteConst("NumCompactTags", len(m))
fmt.Fprintln(w, "const (")
for i, t := range coreTags {
fmt.Fprintf(w, "%s ID = %d\n", ident(t.Tag().String()), i)
}
for i, t := range special {
fmt.Fprintf(w, "%s ID = %d\n", ident(t), i+len(coreTags))
}
fmt.Fprintln(w, ")")
w.WriteVar("coreTags", coreTags)
w.WriteConst("specialTagsStr", strings.Join(special, " "))
}
func ident(s string) string {
return strings.Replace(s, "-", "", -1) + "Index"
}

View File

@ -0,0 +1,54 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ignore
package main
import (
"log"
"golang.org/x/text/internal/gen"
"golang.org/x/text/internal/language"
"golang.org/x/text/internal/language/compact"
"golang.org/x/text/unicode/cldr"
)
func main() {
r := gen.OpenCLDRCoreZip()
defer r.Close()
d := &cldr.Decoder{}
data, err := d.DecodeZip(r)
if err != nil {
log.Fatalf("DecodeZip: %v", err)
}
w := gen.NewCodeWriter()
defer w.WriteGoFile("parents.go", "compact")
// Create parents table.
type ID uint16
parents := make([]ID, compact.NumCompactTags)
for _, loc := range data.Locales() {
tag := language.MustParse(loc)
index, ok := compact.FromTag(tag)
if !ok {
continue
}
parentIndex := compact.ID(0) // und
for p := tag.Parent(); p != language.Und; p = p.Parent() {
if x, ok := compact.FromTag(p); ok {
parentIndex = x
break
}
}
parents[index] = ID(parentIndex)
}
w.WriteComment(`
parents maps a compact index of a tag to the compact index of the parent of
this tag.`)
w.WriteVar("parents", parents)
}

Some files were not shown because too many files have changed in this diff Show More