vendor: cloud.google.com/go@v0.36.0
go get cloud.google.com/go@v0.36.0 go mod tidy go mod vendor
This commit is contained in:
parent
5ede0bf925
commit
df089ee2fb
14
go.mod
14
go.mod
|
@ -1,7 +1,7 @@
|
|||
module github.com/hashicorp/terraform
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.26.0
|
||||
cloud.google.com/go v0.36.0
|
||||
github.com/Azure/azure-sdk-for-go v21.3.0+incompatible
|
||||
github.com/Azure/go-autorest v10.15.4+incompatible
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20170803034930-c92175d54006 // indirect
|
||||
|
@ -28,26 +28,20 @@ require (
|
|||
github.com/coreos/bbolt v1.3.0 // indirect
|
||||
github.com/coreos/etcd v3.3.10+incompatible
|
||||
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/davecgh/go-spew v1.1.1
|
||||
github.com/dnaeon/go-vcr v0.0.0-20180920040454-5637cf3d8a31 // indirect
|
||||
github.com/dylanmei/iso8601 v0.1.0 // indirect
|
||||
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/gogo/protobuf v1.2.0 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20180513044358-24b0969c4cb7 // indirect
|
||||
github.com/golang/mock v1.2.0
|
||||
github.com/golang/protobuf v1.2.0
|
||||
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/martian v2.1.0+incompatible // indirect
|
||||
github.com/googleapis/gax-go v0.0.0-20161107002406-da06d194a00e // indirect
|
||||
github.com/gophercloud/gophercloud v0.0.0-20190208042652-bc37892e1968
|
||||
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/grpc-ecosystem/go-grpc-middleware v1.0.0 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
|
||||
|
@ -126,15 +120,13 @@ require (
|
|||
github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18 // indirect
|
||||
github.com/xlab/treeprint v0.0.0-20161029104018-1d6e34225557
|
||||
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/multierr v1.1.0 // indirect
|
||||
go.uber.org/zap v1.9.1 // indirect
|
||||
golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd
|
||||
golang.org/x/oauth2 v0.0.0-20181003184128-c57b0facaced
|
||||
google.golang.org/api v0.0.0-20181015145326-625cd1887957
|
||||
google.golang.org/appengine v1.3.0 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890
|
||||
google.golang.org/api v0.1.0
|
||||
google.golang.org/grpc v1.18.0
|
||||
gopkg.in/vmihailenco/msgpack.v2 v2.9.1 // indirect
|
||||
labix.org/v2/mgo v0.0.0-20140701140051-000000000287 // indirect
|
||||
|
|
99
go.sum
99
go.sum
|
@ -1,5 +1,12 @@
|
|||
cloud.google.com/go v0.26.0 h1:e0WKqKTd5BnrG8aKH3J3h+QvEIQtSUcf2n5UZ5ZgLtQ=
|
||||
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.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=
|
||||
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=
|
||||
|
@ -7,6 +14,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-ntlmssp v0.0.0-20170803034930-c92175d54006 h1:dVyNL14dq1500JomYVzJTVi0XEcZFCYwwiNpDeCfoes=
|
||||
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/go.mod h1:nuWgzSkT5PnyOd+272uUmV0dnAnAn42Mk7PiQC5VzN4=
|
||||
github.com/Unknwon/com v0.0.0-20151008135407-28b053d5a292 h1:tuQ7w+my8a8mkwN7x2TSd7OzTjkZ7rAeSyH4xncuAMI=
|
||||
|
@ -17,6 +25,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/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/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/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk=
|
||||
github.com/antchfx/xquery v0.0.0-20170730121040-eb8c3c172607 h1:BFFG6KP8ASFBg2ptWsJn8p8RDufBjBDKIxLU7BTYGOM=
|
||||
|
@ -45,6 +54,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/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4=
|
||||
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/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
|
@ -72,21 +82,26 @@ github.com/dimchansky/utfbom v1.0.0 h1:fGC2kkf4qOoKqZ4q7iIh+Vef4ubC1c38UDsEyZynZ
|
|||
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/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/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/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/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
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/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/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/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/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/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
|
@ -99,24 +114,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/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
||||
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/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/googleapis/gax-go v0.0.0-20161107002406-da06d194a00e h1:CYRpN206UTHUinz3VJoLaBdy1gEGeJNsqT0mvswDcMw=
|
||||
github.com/googleapis/gax-go v0.0.0-20161107002406-da06d194a00e/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
|
||||
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/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/go.mod h1:wjDF8z83zTeg5eMLml5EBSlAhbF7G8DobyI1YsMuyzw=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181004151105-1babbf986f6f h1:JJ2EP5vV3LAD2U1CxQtD7PTOO15Y96kXmKDz7TjxGHs=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181004151105-1babbf986f6f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
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/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/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/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/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
|
||||
github.com/hashicorp/aws-sdk-go-base v0.2.0 h1:5bjZnWCvQg9Im5CHZr9t90IaFC4uvVlMl2fTh23IoCk=
|
||||
|
@ -184,6 +205,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/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
|
||||
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/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
|
@ -203,6 +225,7 @@ github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f26
|
|||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/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/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 h1:MtvEpTB6LX3vkb4ax0b5D2DHbNAUsen0Gx5wZoq3lV4=
|
||||
|
@ -225,6 +248,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/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/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/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/mitchellh/cli v0.0.0-20171129193617-33edc47170b5 h1:OYr3N2fY3e3kP/x/d81CJXlcZrIV2hH8gPnuRLpiME4=
|
||||
|
@ -252,6 +276,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/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
|
||||
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/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U=
|
||||
github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
|
||||
|
@ -278,12 +304,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/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/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/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/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
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/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/go.mod h1:zrgwTnHtNr00buQ1vSptGe8m1f/BbgsPukg8qsT7A+A=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||
|
@ -292,6 +341,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/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E=
|
||||
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/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/pflag v1.0.2 h1:Fy0orTDgHdbnzHcsOgfCN4LtHf0ec3wwtiwJqwvf3Gc=
|
||||
|
@ -302,6 +353,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/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/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/go.mod h1:2aQ6n/BtChAl1y2S60vebhyJyZXBsuAI5G4+lHrT1Ew=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20171017195756-830351dc03c6 h1:lYIiVDtZnyTWlNwiAxLj0bbpTcx1BWCFhXjfsvmPdNc=
|
||||
|
@ -324,31 +376,40 @@ 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-20190201220620-4ca19710f056 h1:C6LhH3JHz2k6tnw5sYXBc8rD8SD/qFp6EhiZAcVyalk=
|
||||
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.17.0/go.mod h1:mp1VrMQxhlqqDpKvH4UcQUa4YwlzNmymAjPrDdfxNpI=
|
||||
go.opencensus.io v0.18.0 h1:Mk5rgZcggtbvtAun5aJzAtjKKN/t0R3jJPlWILlv938=
|
||||
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/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
|
||||
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/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-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-20181127143415-eb0de9b17e85 h1:et7+NAX3lLIk5qUCTA9QelBjGE/NkhzYw/mhnr0s7nI=
|
||||
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-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-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/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/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181003184128-c57b0facaced h1:4oqSq7eft7MdPKBGQK11X9WYUxmj6ZLgGTqYIbY1kyw=
|
||||
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/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-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
|
||||
|
@ -356,39 +417,57 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-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/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.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/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-20181015145326-625cd1887957 h1:jwCmWUTrTFfjsobRuGurnCQeW4NZKijaIf6yAXwLR0E=
|
||||
google.golang.org/api v0.0.0-20181015145326-625cd1887957/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/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.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/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-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw=
|
||||
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/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 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/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/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/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/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=
|
||||
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=
|
||||
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=
|
||||
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=
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
package metadata // import "cloud.google.com/go/compute/metadata"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
@ -31,9 +32,6 @@ import (
|
|||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/net/context/ctxhttp"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -139,11 +137,11 @@ func testOnGCE() bool {
|
|||
resc := make(chan bool, 2)
|
||||
|
||||
// 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() {
|
||||
req, _ := http.NewRequest("GET", "http://"+metadataIP, nil)
|
||||
req.Header.Set("User-Agent", userAgent)
|
||||
res, err := ctxhttp.Do(ctx, defaultClient.hc, req)
|
||||
res, err := defaultClient.hc.Do(req.WithContext(ctx))
|
||||
if err != nil {
|
||||
resc <- false
|
||||
return
|
||||
|
@ -302,8 +300,8 @@ func (c *Client) getETag(suffix string) (value, etag string, err error) {
|
|||
// being stable anyway.
|
||||
host = metadataIP
|
||||
}
|
||||
url := "http://" + host + "/computeMetadata/v1/" + suffix
|
||||
req, _ := http.NewRequest("GET", url, nil)
|
||||
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)
|
||||
|
@ -314,13 +312,13 @@ func (c *Client) getETag(suffix string) (value, etag string, err error) {
|
|||
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
|
||||
}
|
||||
if res.StatusCode != 200 {
|
||||
return "", "", &Error{Code: res.StatusCode, Message: string(all)}
|
||||
}
|
||||
return string(all), res.Header.Get("Etag"), nil
|
||||
}
|
||||
|
||||
|
@ -501,3 +499,15 @@ func (c *Client) Subscribe(suffix string, fn func(v string, ok bool) error) erro
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Error contains an error response from the server.
|
||||
type Error struct {
|
||||
// Code is the HTTP response status code.
|
||||
Code int
|
||||
// Message is the server response message.
|
||||
Message string
|
||||
}
|
||||
|
||||
func (e *Error) Error() string {
|
||||
return fmt.Sprintf("compute: Received %d `%s`", e.Code, e.Message)
|
||||
}
|
||||
|
|
|
@ -22,13 +22,15 @@
|
|||
package iam
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
gax "github.com/googleapis/gax-go"
|
||||
"golang.org/x/net/context"
|
||||
gax "github.com/googleapis/gax-go/v2"
|
||||
pb "google.golang.org/genproto/googleapis/iam/v1"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/metadata"
|
||||
)
|
||||
|
||||
// client abstracts the IAMPolicy API to allow multiple implementations.
|
||||
|
@ -56,6 +58,9 @@ var withRetry = gax.WithRetry(func() gax.Retryer {
|
|||
|
||||
func (g *grpcClient) Get(ctx context.Context, resource string) (*pb.Policy, error) {
|
||||
var proto *pb.Policy
|
||||
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", resource))
|
||||
ctx = insertMetadata(ctx, md)
|
||||
|
||||
err := gax.Invoke(ctx, func(ctx context.Context, _ gax.CallSettings) error {
|
||||
var err error
|
||||
proto, err = g.c.GetIamPolicy(ctx, &pb.GetIamPolicyRequest{Resource: resource})
|
||||
|
@ -68,6 +73,9 @@ func (g *grpcClient) Get(ctx context.Context, resource string) (*pb.Policy, erro
|
|||
}
|
||||
|
||||
func (g *grpcClient) Set(ctx context.Context, resource string, p *pb.Policy) error {
|
||||
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", resource))
|
||||
ctx = insertMetadata(ctx, md)
|
||||
|
||||
return gax.Invoke(ctx, func(ctx context.Context, _ gax.CallSettings) error {
|
||||
_, err := g.c.SetIamPolicy(ctx, &pb.SetIamPolicyRequest{
|
||||
Resource: resource,
|
||||
|
@ -79,6 +87,9 @@ func (g *grpcClient) Set(ctx context.Context, resource string, p *pb.Policy) err
|
|||
|
||||
func (g *grpcClient) Test(ctx context.Context, resource string, perms []string) ([]string, error) {
|
||||
var res *pb.TestIamPermissionsResponse
|
||||
md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", resource))
|
||||
ctx = insertMetadata(ctx, md)
|
||||
|
||||
err := gax.Invoke(ctx, func(ctx context.Context, _ gax.CallSettings) error {
|
||||
var err error
|
||||
res, err = g.c.TestIamPermissions(ctx, &pb.TestIamPermissionsRequest{
|
||||
|
@ -290,3 +301,15 @@ func memberIndex(m string, b *pb.Binding) int {
|
|||
}
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -15,11 +15,10 @@
|
|||
package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
gax "github.com/googleapis/gax-go"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
gax "github.com/googleapis/gax-go/v2"
|
||||
)
|
||||
|
||||
// Retry calls the supplied function f repeatedly according to the provided
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
// 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.
|
||||
|
||||
// +build !go1.8
|
||||
|
||||
package trace
|
||||
|
||||
import (
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// OpenCensus only supports go 1.8 and higher.
|
||||
|
||||
func StartSpan(ctx context.Context, _ string) context.Context {
|
||||
return ctx
|
||||
}
|
||||
|
||||
func EndSpan(context.Context, error) {
|
||||
}
|
|
@ -12,23 +12,24 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build go1.8
|
||||
|
||||
package trace
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.opencensus.io/trace"
|
||||
"golang.org/x/net/context"
|
||||
"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 {
|
|
@ -67,5 +67,5 @@ func goVer(s string) string {
|
|||
}
|
||||
|
||||
func notSemverRune(r rune) bool {
|
||||
return strings.IndexRune("0123456789.", r) < 0
|
||||
return !strings.ContainsRune("0123456789.", r)
|
||||
}
|
||||
|
|
|
@ -15,11 +15,11 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"reflect"
|
||||
|
||||
"cloud.google.com/go/internal/trace"
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/api/googleapi"
|
||||
raw "google.golang.org/api/storage/v1"
|
||||
)
|
||||
|
@ -121,7 +121,7 @@ func (a *ACLHandle) bucketDefaultList(ctx context.Context) ([]ACLRule, error) {
|
|||
var err error
|
||||
err = runWithRetry(ctx, func() error {
|
||||
req := a.c.raw.DefaultObjectAccessControls.List(a.bucket)
|
||||
a.configureCall(req, ctx)
|
||||
a.configureCall(ctx, req)
|
||||
acls, err = req.Do()
|
||||
return err
|
||||
})
|
||||
|
@ -134,7 +134,7 @@ func (a *ACLHandle) bucketDefaultList(ctx context.Context) ([]ACLRule, error) {
|
|||
func (a *ACLHandle) bucketDefaultDelete(ctx context.Context, entity ACLEntity) error {
|
||||
return runWithRetry(ctx, func() error {
|
||||
req := a.c.raw.DefaultObjectAccessControls.Delete(a.bucket, string(entity))
|
||||
a.configureCall(req, ctx)
|
||||
a.configureCall(ctx, req)
|
||||
return req.Do()
|
||||
})
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ func (a *ACLHandle) bucketList(ctx context.Context) ([]ACLRule, error) {
|
|||
var err error
|
||||
err = runWithRetry(ctx, func() error {
|
||||
req := a.c.raw.BucketAccessControls.List(a.bucket)
|
||||
a.configureCall(req, ctx)
|
||||
a.configureCall(ctx, req)
|
||||
acls, err = req.Do()
|
||||
return err
|
||||
})
|
||||
|
@ -162,7 +162,7 @@ func (a *ACLHandle) bucketSet(ctx context.Context, entity ACLEntity, role ACLRol
|
|||
}
|
||||
err := runWithRetry(ctx, func() error {
|
||||
req := a.c.raw.BucketAccessControls.Update(a.bucket, string(entity), acl)
|
||||
a.configureCall(req, ctx)
|
||||
a.configureCall(ctx, req)
|
||||
_, err := req.Do()
|
||||
return err
|
||||
})
|
||||
|
@ -175,7 +175,7 @@ func (a *ACLHandle) bucketSet(ctx context.Context, entity ACLEntity, role ACLRol
|
|||
func (a *ACLHandle) bucketDelete(ctx context.Context, entity ACLEntity) error {
|
||||
return runWithRetry(ctx, func() error {
|
||||
req := a.c.raw.BucketAccessControls.Delete(a.bucket, string(entity))
|
||||
a.configureCall(req, ctx)
|
||||
a.configureCall(ctx, req)
|
||||
return req.Do()
|
||||
})
|
||||
}
|
||||
|
@ -185,7 +185,7 @@ func (a *ACLHandle) objectList(ctx context.Context) ([]ACLRule, error) {
|
|||
var err error
|
||||
err = runWithRetry(ctx, func() error {
|
||||
req := a.c.raw.ObjectAccessControls.List(a.bucket, a.object)
|
||||
a.configureCall(req, ctx)
|
||||
a.configureCall(ctx, req)
|
||||
acls, err = req.Do()
|
||||
return err
|
||||
})
|
||||
|
@ -212,7 +212,7 @@ func (a *ACLHandle) objectSet(ctx context.Context, entity ACLEntity, role ACLRol
|
|||
} else {
|
||||
req = a.c.raw.ObjectAccessControls.Update(a.bucket, a.object, string(entity), acl)
|
||||
}
|
||||
a.configureCall(req, ctx)
|
||||
a.configureCall(ctx, req)
|
||||
return runWithRetry(ctx, func() error {
|
||||
_, err := req.Do()
|
||||
return err
|
||||
|
@ -222,12 +222,12 @@ func (a *ACLHandle) objectSet(ctx context.Context, entity ACLEntity, role ACLRol
|
|||
func (a *ACLHandle) objectDelete(ctx context.Context, entity ACLEntity) error {
|
||||
return runWithRetry(ctx, func() error {
|
||||
req := a.c.raw.ObjectAccessControls.Delete(a.bucket, a.object, string(entity))
|
||||
a.configureCall(req, ctx)
|
||||
a.configureCall(ctx, req)
|
||||
return req.Do()
|
||||
})
|
||||
}
|
||||
|
||||
func (a *ACLHandle) configureCall(call interface{ Header() http.Header }, ctx context.Context) {
|
||||
func (a *ACLHandle) configureCall(ctx context.Context, call interface{ Header() http.Header }) {
|
||||
vc := reflect.ValueOf(call)
|
||||
vc.MethodByName("Context").Call([]reflect.Value{reflect.ValueOf(ctx)})
|
||||
if a.userProject != "" {
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"reflect"
|
||||
|
@ -22,7 +23,6 @@ import (
|
|||
|
||||
"cloud.google.com/go/internal/optional"
|
||||
"cloud.google.com/go/internal/trace"
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/api/googleapi"
|
||||
"google.golang.org/api/iterator"
|
||||
raw "google.golang.org/api/storage/v1"
|
||||
|
@ -186,6 +186,7 @@ func (b *BucketHandle) newGetCall() (*raw.BucketsGetCall, error) {
|
|||
return req, nil
|
||||
}
|
||||
|
||||
// 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) }()
|
||||
|
@ -231,10 +232,18 @@ type BucketAttrs struct {
|
|||
// ACL is the list of access control rules on the bucket.
|
||||
ACL []ACLRule
|
||||
|
||||
// BucketPolicyOnly configures access checks to use only bucket-level IAM
|
||||
// policies.
|
||||
BucketPolicyOnly BucketPolicyOnly
|
||||
|
||||
// DefaultObjectACL is the list of access controls to
|
||||
// apply to new objects when no object ACL is provided.
|
||||
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.
|
||||
|
@ -306,12 +315,23 @@ type BucketAttrs struct {
|
|||
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.
|
||||
type Lifecycle struct {
|
||||
Rules []LifecycleRule
|
||||
}
|
||||
|
||||
// Retention policy enforces a minimum retention time for all objects
|
||||
// RetentionPolicy enforces a minimum retention time for all objects
|
||||
// contained in the bucket.
|
||||
//
|
||||
// Any attempt to overwrite or delete objects younger than the retention
|
||||
|
@ -334,6 +354,11 @@ type RetentionPolicy struct {
|
|||
// 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 (
|
||||
|
@ -433,7 +458,7 @@ type BucketLogging struct {
|
|||
LogObjectPrefix string
|
||||
}
|
||||
|
||||
// Website holds the bucket's website configuration, controlling how the
|
||||
// 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 {
|
||||
|
@ -458,22 +483,24 @@ func newBucket(b *raw.Bucket) (*BucketAttrs, error) {
|
|||
return nil, err
|
||||
}
|
||||
return &BucketAttrs{
|
||||
Name: b.Name,
|
||||
Location: b.Location,
|
||||
MetaGeneration: b.Metageneration,
|
||||
StorageClass: b.StorageClass,
|
||||
Created: convertTime(b.TimeCreated),
|
||||
VersioningEnabled: b.Versioning != nil && b.Versioning.Enabled,
|
||||
ACL: toBucketACLRules(b.Acl),
|
||||
DefaultObjectACL: toObjectACLRules(b.DefaultObjectAcl),
|
||||
Labels: b.Labels,
|
||||
RequesterPays: b.Billing != nil && b.Billing.RequesterPays,
|
||||
Lifecycle: toLifecycle(b.Lifecycle),
|
||||
RetentionPolicy: rp,
|
||||
CORS: toCORS(b.Cors),
|
||||
Encryption: toBucketEncryption(b.Encryption),
|
||||
Logging: toBucketLogging(b.Logging),
|
||||
Website: toBucketWebsite(b.Website),
|
||||
Name: b.Name,
|
||||
Location: b.Location,
|
||||
MetaGeneration: b.Metageneration,
|
||||
DefaultEventBasedHold: b.DefaultEventBasedHold,
|
||||
StorageClass: b.StorageClass,
|
||||
Created: convertTime(b.TimeCreated),
|
||||
VersioningEnabled: b.Versioning != nil && b.Versioning.Enabled,
|
||||
ACL: toBucketACLRules(b.Acl),
|
||||
DefaultObjectACL: toObjectACLRules(b.DefaultObjectAcl),
|
||||
Labels: b.Labels,
|
||||
RequesterPays: b.Billing != nil && b.Billing.RequesterPays,
|
||||
Lifecycle: toLifecycle(b.Lifecycle),
|
||||
RetentionPolicy: rp,
|
||||
CORS: toCORS(b.Cors),
|
||||
Encryption: toBucketEncryption(b.Encryption),
|
||||
Logging: toBucketLogging(b.Logging),
|
||||
Website: toBucketWebsite(b.Website),
|
||||
BucketPolicyOnly: toBucketPolicyOnly(b.IamConfiguration),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -498,6 +525,14 @@ func (b *BucketAttrs) toRawBucket() *raw.Bucket {
|
|||
if b.RequesterPays {
|
||||
bb = &raw.BucketBilling{RequesterPays: true}
|
||||
}
|
||||
var bktIAM *raw.BucketIamConfiguration
|
||||
if b.BucketPolicyOnly.Enabled {
|
||||
bktIAM = &raw.BucketIamConfiguration{
|
||||
BucketPolicyOnly: &raw.BucketIamConfigurationBucketPolicyOnly{
|
||||
Enabled: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
return &raw.Bucket{
|
||||
Name: b.Name,
|
||||
Location: b.Location,
|
||||
|
@ -513,6 +548,7 @@ func (b *BucketAttrs) toRawBucket() *raw.Bucket {
|
|||
Encryption: b.Encryption.toRawBucketEncryption(),
|
||||
Logging: b.Logging.toRawBucketLogging(),
|
||||
Website: b.Website.toRawBucketWebsite(),
|
||||
IamConfiguration: bktIAM,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -547,6 +583,7 @@ type BucketEncryption struct {
|
|||
DefaultKMSKeyName string
|
||||
}
|
||||
|
||||
// BucketAttrsToUpdate define the attributes to update during an Update call.
|
||||
type BucketAttrsToUpdate struct {
|
||||
// If set, updates whether the bucket uses versioning.
|
||||
VersioningEnabled optional.Bool
|
||||
|
@ -554,6 +591,14 @@ type BucketAttrsToUpdate struct {
|
|||
// If set, updates whether the bucket is a Requester Pays bucket.
|
||||
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.
|
||||
//
|
||||
|
@ -616,6 +661,10 @@ func (ua *BucketAttrsToUpdate) toRawBucket() *raw.Bucket {
|
|||
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")
|
||||
|
@ -636,6 +685,13 @@ func (ua *BucketAttrsToUpdate) toRawBucket() *raw.Bucket {
|
|||
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")
|
||||
|
@ -799,6 +855,7 @@ func toRetentionPolicy(rp *raw.BucketRetentionPolicy) (*RetentionPolicy, error)
|
|||
return &RetentionPolicy{
|
||||
RetentionPeriod: time.Duration(rp.RetentionPeriod) * time.Second,
|
||||
EffectiveTime: t,
|
||||
IsLocked: rp.IsLocked,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -954,6 +1011,22 @@ func toBucketWebsite(w *raw.BucketWebsite) *BucketWebsite {
|
|||
}
|
||||
}
|
||||
|
||||
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.
|
||||
// If q is nil, no filtering is done.
|
||||
func (b *BucketHandle) Objects(ctx context.Context, q *Query) *ObjectIterator {
|
||||
|
|
|
@ -15,11 +15,11 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"cloud.google.com/go/internal/trace"
|
||||
"golang.org/x/net/context"
|
||||
raw "google.golang.org/api/storage/v1"
|
||||
)
|
||||
|
||||
|
|
|
@ -163,5 +163,14 @@ SignedURL for details.
|
|||
// TODO: Handle error.
|
||||
}
|
||||
fmt.Println(url)
|
||||
|
||||
Errors
|
||||
|
||||
Errors returned by this client are often of the type [`googleapi.Error`](https://godoc.org/google.golang.org/api/googleapi#Error).
|
||||
These errors can be introspected for more information by type asserting to the richer `googleapi.Error` type. For example:
|
||||
|
||||
if e, ok := err.(*googleapi.Error); ok {
|
||||
if e.Code == 409 { ... }
|
||||
}
|
||||
*/
|
||||
package storage // import "cloud.google.com/go/storage"
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
// Copyright 2017 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build go1.7
|
||||
|
||||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func withContext(r *http.Request, ctx context.Context) *http.Request {
|
||||
return r.WithContext(ctx)
|
||||
}
|
||||
|
||||
func goHTTPUncompressed(res *http.Response) bool {
|
||||
return res.Uncompressed
|
||||
}
|
|
@ -15,9 +15,10 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"cloud.google.com/go/iam"
|
||||
"cloud.google.com/go/internal/trace"
|
||||
"golang.org/x/net/context"
|
||||
raw "google.golang.org/api/storage/v1"
|
||||
iampb "google.golang.org/genproto/googleapis/iam/v1"
|
||||
)
|
||||
|
|
|
@ -15,9 +15,10 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"cloud.google.com/go/internal"
|
||||
gax "github.com/googleapis/gax-go"
|
||||
"golang.org/x/net/context"
|
||||
gax "github.com/googleapis/gax-go/v2"
|
||||
)
|
||||
|
||||
// runWithRetry calls the function until it returns nil or a non-retryable error, or
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
// Copyright 2017 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build !go1.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
|
||||
}
|
||||
|
||||
// Go 1.6 doesn't have http.Response.Uncompressed, so we can't know whether the Go
|
||||
// HTTP stack uncompressed a gzip file. As a good approximation, assume that
|
||||
// the lack of a Content-Length header means that it did uncompress.
|
||||
func goHTTPUncompressed(res *http.Response) bool {
|
||||
return res.Header.Get("Content-Length") == ""
|
||||
}
|
|
@ -15,12 +15,12 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
"cloud.google.com/go/internal/trace"
|
||||
"golang.org/x/net/context"
|
||||
raw "google.golang.org/api/storage/v1"
|
||||
)
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash/crc32"
|
||||
|
@ -25,14 +26,47 @@ import (
|
|||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"cloud.google.com/go/internal/trace"
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/api/googleapi"
|
||||
)
|
||||
|
||||
var crc32cTable = crc32.MakeTable(crc32.Castagnoli)
|
||||
|
||||
// ReaderObjectAttrs are attributes about the object being read. These are populated
|
||||
// during the New call. This struct only holds a subset of object attributes: to
|
||||
// get the full set of attributes, use ObjectHandle.Attrs.
|
||||
//
|
||||
// Each field is read-only.
|
||||
type ReaderObjectAttrs struct {
|
||||
// Size is the length of the object's content.
|
||||
Size int64
|
||||
|
||||
// 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.
|
||||
|
@ -61,10 +95,9 @@ func (o *ObjectHandle) NewRangeReader(ctx context.Context, offset, length int64)
|
|||
}
|
||||
}
|
||||
u := &url.URL{
|
||||
Scheme: "https",
|
||||
Host: "storage.googleapis.com",
|
||||
Path: fmt.Sprintf("/%s/%s", o.bucket, o.object),
|
||||
RawQuery: conditionsQuery(o.gen, o.conds),
|
||||
Scheme: "https",
|
||||
Host: "storage.googleapis.com",
|
||||
Path: fmt.Sprintf("/%s/%s", o.bucket, o.object),
|
||||
}
|
||||
verb := "GET"
|
||||
if length == 0 {
|
||||
|
@ -74,7 +107,7 @@ func (o *ObjectHandle) NewRangeReader(ctx context.Context, offset, length int64)
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req = withContext(req, ctx)
|
||||
req = req.WithContext(ctx)
|
||||
if o.userProject != "" {
|
||||
req.Header.Set("X-Goog-User-Project", o.userProject)
|
||||
}
|
||||
|
@ -85,6 +118,8 @@ func (o *ObjectHandle) NewRangeReader(ctx context.Context, offset, length int64)
|
|||
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) {
|
||||
|
@ -95,6 +130,8 @@ func (o *ObjectHandle) NewRangeReader(ctx context.Context, offset, length int64)
|
|||
// 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)
|
||||
|
@ -118,6 +155,15 @@ func (o *ObjectHandle) NewRangeReader(ctx context.Context, offset, length int64)
|
|||
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 {
|
||||
|
@ -156,7 +202,7 @@ func (o *ObjectHandle) NewRangeReader(ctx context.Context, offset, length int64)
|
|||
// 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 && !goHTTPUncompressed(res) && !uncompressedByServer(res) {
|
||||
if length != 0 && !res.Uncompressed && !uncompressedByServer(res) {
|
||||
crc, checkCRC = parseCRC32c(res)
|
||||
}
|
||||
}
|
||||
|
@ -168,16 +214,39 @@ func (o *ObjectHandle) NewRangeReader(ctx context.Context, offset, length int64)
|
|||
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{
|
||||
body: body,
|
||||
size: size,
|
||||
remain: remain,
|
||||
contentType: res.Header.Get("Content-Type"),
|
||||
contentEncoding: res.Header.Get("Content-Encoding"),
|
||||
cacheControl: res.Header.Get("Cache-Control"),
|
||||
wantCRC: crc,
|
||||
checkCRC: checkCRC,
|
||||
reopen: reopen,
|
||||
Attrs: attrs,
|
||||
body: body,
|
||||
size: size,
|
||||
remain: remain,
|
||||
wantCRC: crc,
|
||||
checkCRC: checkCRC,
|
||||
reopen: reopen,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -210,11 +279,9 @@ var emptyBody = ioutil.NopCloser(strings.NewReader(""))
|
|||
// the stored CRC, returning an error from Read if there is a mismatch. This integrity check
|
||||
// is skipped if transcoding occurs. See https://cloud.google.com/storage/docs/transcoding.
|
||||
type Reader struct {
|
||||
Attrs ReaderObjectAttrs
|
||||
body io.ReadCloser
|
||||
seen, remain, size int64
|
||||
contentType string
|
||||
contentEncoding string
|
||||
cacheControl string
|
||||
checkCRC bool // should we check the CRC?
|
||||
wantCRC uint32 // the CRC32c value the server sent in the header
|
||||
gotCRC uint32 // running crc
|
||||
|
@ -278,8 +345,10 @@ func shouldRetryRead(err error) bool {
|
|||
// Size returns the size of the object in bytes.
|
||||
// The returned value is always the same and is not affected by
|
||||
// calls to Read or Close.
|
||||
//
|
||||
// Deprecated: use Reader.Attrs.Size.
|
||||
func (r *Reader) Size() int64 {
|
||||
return r.size
|
||||
return r.Attrs.Size
|
||||
}
|
||||
|
||||
// Remain returns the number of bytes left to read, or -1 if unknown.
|
||||
|
@ -288,16 +357,29 @@ func (r *Reader) Remain() int64 {
|
|||
}
|
||||
|
||||
// ContentType returns the content type of the object.
|
||||
//
|
||||
// Deprecated: use Reader.Attrs.ContentType.
|
||||
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.contentEncoding
|
||||
return r.Attrs.ContentEncoding
|
||||
}
|
||||
|
||||
// CacheControl returns the cache control of the object.
|
||||
//
|
||||
// Deprecated: use Reader.Attrs.CacheControl.
|
||||
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
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ package storage
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
|
@ -25,7 +26,6 @@ import (
|
|||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
|
@ -36,19 +36,19 @@ import (
|
|||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
"cloud.google.com/go/internal/trace"
|
||||
"google.golang.org/api/option"
|
||||
htransport "google.golang.org/api/transport/http"
|
||||
|
||||
"cloud.google.com/go/internal/optional"
|
||||
"cloud.google.com/go/internal/trace"
|
||||
"cloud.google.com/go/internal/version"
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/api/googleapi"
|
||||
"google.golang.org/api/option"
|
||||
raw "google.golang.org/api/storage/v1"
|
||||
htransport "google.golang.org/api/transport/http"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrBucketNotExist indicates that the bucket does not 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")
|
||||
)
|
||||
|
||||
|
@ -112,8 +112,7 @@ func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error
|
|||
//
|
||||
// Close need not be called at program exit.
|
||||
func (c *Client) Close() error {
|
||||
// Set fields to nil so that subsequent uses
|
||||
// will panic.
|
||||
// Set fields to nil so that subsequent uses will panic.
|
||||
c.hc = nil
|
||||
c.raw = nil
|
||||
return nil
|
||||
|
@ -442,6 +441,14 @@ func (o *ObjectHandle) Update(ctx context.Context, uattrs ObjectAttrsToUpdate) (
|
|||
attrs.CacheControl = optional.ToString(uattrs.CacheControl)
|
||||
forceSendFields = append(forceSendFields, "CacheControl")
|
||||
}
|
||||
if uattrs.EventBasedHold != nil {
|
||||
attrs.EventBasedHold = optional.ToBool(uattrs.EventBasedHold)
|
||||
forceSendFields = append(forceSendFields, "EventBasedHold")
|
||||
}
|
||||
if uattrs.TemporaryHold != nil {
|
||||
attrs.TemporaryHold = optional.ToBool(uattrs.TemporaryHold)
|
||||
forceSendFields = append(forceSendFields, "TemporaryHold")
|
||||
}
|
||||
if uattrs.Metadata != nil {
|
||||
attrs.Metadata = uattrs.Metadata
|
||||
if len(attrs.Metadata) == 0 {
|
||||
|
@ -485,6 +492,16 @@ func (o *ObjectHandle) Update(ctx context.Context, uattrs ObjectAttrsToUpdate) (
|
|||
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.
|
||||
// Only fields set to non-nil values will be updated.
|
||||
// Set a field to its zero value to delete it.
|
||||
|
@ -497,6 +514,8 @@ func (o *ObjectHandle) Update(ctx context.Context, uattrs ObjectAttrsToUpdate) (
|
|||
// Metadata: map[string]string{},
|
||||
// }
|
||||
type ObjectAttrsToUpdate struct {
|
||||
EventBasedHold optional.Bool
|
||||
TemporaryHold optional.Bool
|
||||
ContentType optional.String
|
||||
ContentLanguage optional.String
|
||||
ContentEncoding optional.String
|
||||
|
@ -556,7 +575,8 @@ func (o *ObjectHandle) ReadCompressed(compressed bool) *ObjectHandle {
|
|||
// attribute is specified, the content type will be automatically sniffed
|
||||
// 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 {
|
||||
return &Writer{
|
||||
ctx: ctx,
|
||||
|
@ -604,17 +624,24 @@ func parseKey(key []byte) (*rsa.PrivateKey, error) {
|
|||
|
||||
// toRawObject copies the editable attributes from o to the raw library's Object type.
|
||||
func (o *ObjectAttrs) toRawObject(bucket string) *raw.Object {
|
||||
var ret string
|
||||
if !o.RetentionExpirationTime.IsZero() {
|
||||
ret = o.RetentionExpirationTime.Format(time.RFC3339)
|
||||
}
|
||||
return &raw.Object{
|
||||
Bucket: bucket,
|
||||
Name: o.Name,
|
||||
ContentType: o.ContentType,
|
||||
ContentEncoding: o.ContentEncoding,
|
||||
ContentLanguage: o.ContentLanguage,
|
||||
CacheControl: o.CacheControl,
|
||||
ContentDisposition: o.ContentDisposition,
|
||||
StorageClass: o.StorageClass,
|
||||
Acl: toRawObjectACL(o.ACL),
|
||||
Metadata: o.Metadata,
|
||||
Bucket: bucket,
|
||||
Name: o.Name,
|
||||
EventBasedHold: o.EventBasedHold,
|
||||
TemporaryHold: o.TemporaryHold,
|
||||
RetentionExpirationTime: ret,
|
||||
ContentType: o.ContentType,
|
||||
ContentEncoding: o.ContentEncoding,
|
||||
ContentLanguage: o.ContentLanguage,
|
||||
CacheControl: o.CacheControl,
|
||||
ContentDisposition: o.ContentDisposition,
|
||||
StorageClass: o.StorageClass,
|
||||
Acl: toRawObjectACL(o.ACL),
|
||||
Metadata: o.Metadata,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -638,6 +665,21 @@ type ObjectAttrs struct {
|
|||
// headers when serving the object data.
|
||||
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 []ACLRule
|
||||
|
||||
|
@ -762,28 +804,31 @@ func newObject(o *raw.Object) *ObjectAttrs {
|
|||
sha256 = o.CustomerEncryption.KeySha256
|
||||
}
|
||||
return &ObjectAttrs{
|
||||
Bucket: o.Bucket,
|
||||
Name: o.Name,
|
||||
ContentType: o.ContentType,
|
||||
ContentLanguage: o.ContentLanguage,
|
||||
CacheControl: o.CacheControl,
|
||||
ACL: toObjectACLRules(o.Acl),
|
||||
Owner: owner,
|
||||
ContentEncoding: o.ContentEncoding,
|
||||
ContentDisposition: o.ContentDisposition,
|
||||
Size: int64(o.Size),
|
||||
MD5: md5,
|
||||
CRC32C: crc32c,
|
||||
MediaLink: o.MediaLink,
|
||||
Metadata: o.Metadata,
|
||||
Generation: o.Generation,
|
||||
Metageneration: o.Metageneration,
|
||||
StorageClass: o.StorageClass,
|
||||
CustomerKeySHA256: sha256,
|
||||
KMSKeyName: o.KmsKeyName,
|
||||
Created: convertTime(o.TimeCreated),
|
||||
Deleted: convertTime(o.TimeDeleted),
|
||||
Updated: convertTime(o.Updated),
|
||||
Bucket: o.Bucket,
|
||||
Name: o.Name,
|
||||
ContentType: o.ContentType,
|
||||
ContentLanguage: o.ContentLanguage,
|
||||
CacheControl: o.CacheControl,
|
||||
EventBasedHold: o.EventBasedHold,
|
||||
TemporaryHold: o.TemporaryHold,
|
||||
RetentionExpirationTime: convertTime(o.RetentionExpirationTime),
|
||||
ACL: toObjectACLRules(o.Acl),
|
||||
Owner: owner,
|
||||
ContentEncoding: o.ContentEncoding,
|
||||
ContentDisposition: o.ContentDisposition,
|
||||
Size: int64(o.Size),
|
||||
MD5: md5,
|
||||
CRC32C: crc32c,
|
||||
MediaLink: o.MediaLink,
|
||||
Metadata: o.Metadata,
|
||||
Generation: o.Generation,
|
||||
Metageneration: o.Metageneration,
|
||||
StorageClass: o.StorageClass,
|
||||
CustomerKeySHA256: sha256,
|
||||
KMSKeyName: o.KmsKeyName,
|
||||
Created: convertTime(o.TimeCreated),
|
||||
Deleted: convertTime(o.TimeDeleted),
|
||||
Updated: convertTime(o.Updated),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -826,17 +871,6 @@ type Query struct {
|
|||
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
|
||||
// objects.
|
||||
//
|
||||
|
@ -1066,4 +1100,12 @@ func setEncryptionHeaders(headers http.Header, key []byte, copySource bool) erro
|
|||
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
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -15,6 +15,7 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
@ -22,7 +23,6 @@ import (
|
|||
"sync"
|
||||
"unicode/utf8"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/api/googleapi"
|
||||
raw "google.golang.org/api/storage/v1"
|
||||
)
|
||||
|
@ -95,6 +95,8 @@ func (w *Writer) open() error {
|
|||
w.pw = pw
|
||||
w.opened = true
|
||||
|
||||
go w.monitorCancel()
|
||||
|
||||
if w.ChunkSize < 0 {
|
||||
return errors.New("storage: Writer.ChunkSize must be non-negative")
|
||||
}
|
||||
|
@ -188,7 +190,19 @@ func (w *Writer) Write(p []byte) (n int, err error) {
|
|||
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.
|
||||
|
@ -200,15 +214,35 @@ func (w *Writer) Close() error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Closing either the read or write causes the entire pipe to close.
|
||||
if err := w.pw.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
<-w.donec
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
return w.err
|
||||
}
|
||||
|
||||
// monitorCancel is intended to be used as a background goroutine. It monitors the
|
||||
// the context, and when it observes that the context has been canceled, it manually
|
||||
// closes things that do not take a context.
|
||||
func (w *Writer) monitorCancel() {
|
||||
select {
|
||||
case <-w.ctx.Done():
|
||||
w.mu.Lock()
|
||||
werr := w.ctx.Err()
|
||||
w.err = werr
|
||||
w.mu.Unlock()
|
||||
|
||||
// Closing either the read or write causes the entire pipe to close.
|
||||
w.CloseWithError(werr)
|
||||
case <-w.donec:
|
||||
}
|
||||
}
|
||||
|
||||
// CloseWithError aborts the write operation with the provided error.
|
||||
// CloseWithError always returns nil.
|
||||
//
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
*.cover
|
|
@ -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)
|
|
@ -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).
|
|
@ -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.
|
|
@ -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
|
||||
}
|
|
@ -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--
|
||||
}
|
|
@ -35,6 +35,7 @@ import (
|
|||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// 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) {
|
||||
c := grpc.Code(err)
|
||||
st, ok := status.FromError(err)
|
||||
if !ok {
|
||||
return 0, false
|
||||
}
|
||||
c := st.Code()
|
||||
for _, rc := range r.codes {
|
||||
if c == rc {
|
||||
return r.backoff.Pause(), true
|
||||
|
@ -108,6 +113,7 @@ type Backoff struct {
|
|||
cur time.Duration
|
||||
}
|
||||
|
||||
// Pause returns the next time.Duration that the caller should use to backoff.
|
||||
func (bo *Backoff) Pause() time.Duration {
|
||||
if bo.Initial == 0 {
|
||||
bo.Initial = time.Second
|
||||
|
@ -121,7 +127,11 @@ func (bo *Backoff) Pause() time.Duration {
|
|||
if bo.Multiplier < 1 {
|
||||
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)
|
||||
if bo.cur > bo.Max {
|
||||
bo.cur = bo.Max
|
||||
|
@ -129,8 +139,23 @@ func (bo *Backoff) Pause() time.Duration {
|
|||
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 {
|
||||
// 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.
|
||||
Retry func() Retryer
|
||||
|
||||
// CallOptions to be forwarded to GRPC.
|
||||
GRPC []grpc.CallOption
|
||||
}
|
|
@ -33,8 +33,7 @@
|
|||
// Application code will rarely need to use this library directly.
|
||||
// However, code generated automatically from API definition files can use it
|
||||
// to simplify code generation and to provide more convenient and idiomatic API surfaces.
|
||||
//
|
||||
// This project is currently experimental and not supported.
|
||||
package gax
|
||||
|
||||
const Version = "0.1.0"
|
||||
// Version specifies the gax-go version being used.
|
||||
const Version = "2.0.3"
|
|
@ -0,0 +1,3 @@
|
|||
module github.com/googleapis/gax-go/v2
|
||||
|
||||
require google.golang.org/grpc v1.16.0
|
|
@ -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=
|
|
@ -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:]
|
||||
}
|
|
@ -30,13 +30,13 @@
|
|||
package gax
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// A user defined call stub.
|
||||
type APICall func(context.Context) error
|
||||
// APICall is a user defined call stub.
|
||||
type APICall func(context.Context, CallSettings) error
|
||||
|
||||
// Invoke calls the given APICall,
|
||||
// performing retries as specified by opts, if any.
|
||||
|
@ -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 {
|
||||
var retryer Retryer
|
||||
for {
|
||||
err := call(ctx)
|
||||
err := call(ctx, settings)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if settings.Retry == nil {
|
||||
return err
|
||||
}
|
||||
// Never retry permanent certificate errors. (e.x. if ca-certificates
|
||||
// are not installed). We should only make very few, targeted
|
||||
// exceptions: many (other) status=Unavailable should be retried, such
|
||||
// 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 r := settings.Retry(); r != nil {
|
||||
retryer = r
|
|
@ -2,7 +2,7 @@ language: go
|
|||
|
||||
go:
|
||||
# 1.8 is tested by AppVeyor
|
||||
- 1.10.x
|
||||
- 1.11.x
|
||||
|
||||
go_import_path: go.opencensus.io
|
||||
|
||||
|
@ -18,10 +18,10 @@ before_script:
|
|||
|
||||
script:
|
||||
- embedmd -d README.md # Ensure embedded code is up-to-date
|
||||
- dep ensure -v
|
||||
- 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
|
||||
- go vet ./...
|
||||
- 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'
|
||||
- go run internal/check/version.go
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
OpenCensus Go is a Go implementation of OpenCensus, a toolkit for
|
||||
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
|
||||
|
||||
|
@ -38,7 +38,7 @@ integration with your RPC framework:
|
|||
* [Redis goredis/redis](https://godoc.org/github.com/orijtech/redis)
|
||||
* [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.
|
||||
|
||||
## Exporters
|
||||
|
@ -56,6 +56,7 @@ can implement their own exporters by implementing the exporter interfaces
|
|||
* [AWS X-Ray][exporter-xray] for traces
|
||||
* [Datadog][exporter-datadog] for stats and traces
|
||||
* [Graphite][exporter-graphite] for stats
|
||||
* [Honeycomb][exporter-honeycomb] for traces
|
||||
|
||||
## 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`
|
||||
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)
|
||||
```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
|
||||
new child spans with the parent.
|
||||
|
||||
In the same process, context.Context is used to propagate spans.
|
||||
trace.StartSpan creates a new span as a root if the current context
|
||||
In the same process, `context.Context` is used to propagate spans.
|
||||
`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
|
||||
already in current context. The returned context can be used to keep
|
||||
propagating the newly created span in the current context.
|
||||
|
@ -194,8 +195,8 @@ defer span.End()
|
|||
Across the network, OpenCensus provides different propagation
|
||||
methods for different protocols.
|
||||
|
||||
* gRPC integrations uses 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)
|
||||
* gRPC integrations use the OpenCensus' [binary propagation format](https://godoc.org/go.opencensus.io/trace/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
|
||||
[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-datadog]: https://github.com/DataDog/opencensus-go-exporter-datadog
|
||||
[exporter-graphite]: https://github.com/census-ecosystem/opencensus-go-exporter-graphite
|
||||
|
||||
[exporter-honeycomb]: https://github.com/honeycombio/opencensus-exporter
|
||||
|
|
|
@ -5,8 +5,10 @@ platform: x64
|
|||
clone_folder: c:\gopath\src\go.opencensus.io
|
||||
|
||||
environment:
|
||||
GOPATH: c:\gopath
|
||||
GOVERSION: 1.8
|
||||
GOPATH: 'c:\gopath'
|
||||
GOVERSION: '1.11'
|
||||
GO111MODULE: 'on'
|
||||
CGO_ENABLED: '0' # See: https://github.com/appveyor/ci/issues/2613
|
||||
|
||||
install:
|
||||
- set PATH=%GOPATH%\bin;c:\go\bin;%PATH%
|
||||
|
@ -18,7 +20,5 @@ deploy: false
|
|||
|
||||
test_script:
|
||||
- cd %APPVEYOR_BUILD_FOLDER%
|
||||
- gofmt -w .
|
||||
- go get -v -t .\...
|
||||
- go test -race -v .\...
|
||||
- go vet .\...
|
||||
- go build -v .\...
|
||||
- go test -v .\... # No -race because cgo is disabled
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -3,7 +3,11 @@ module go.opencensus.io
|
|||
require (
|
||||
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999
|
||||
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/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/openzipkin/zipkin-go v0.1.1
|
||||
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/genproto v0.0.0-20180831171423-11092d34479b
|
||||
google.golang.org/grpc v1.14.0
|
||||
gopkg.in/yaml.v2 v2.2.1 // indirect
|
||||
)
|
||||
|
|
|
@ -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-20180902110319-2566ecd5d999 h1:sihTnRgTOUSCQz0iS0pjZuFQy/z7GXCJgSBg3+rZKHw=
|
||||
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/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/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/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/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_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/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/procfs v0.0.0-20180725123919-05ee40e3a273 h1:agujYaXJSxSo18YNX3jzl+4G6Bstwt+kqv47GS12uL0=
|
||||
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-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA=
|
||||
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/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/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
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-20180910000450-7ca32eb868bf h1:rjxqQmxjyqerRKEj+tZW+MCm4LgpFXu18bsEoCMgDsk=
|
||||
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-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw=
|
||||
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=
|
||||
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=
|
||||
|
|
|
@ -17,5 +17,5 @@ package opencensus // import "go.opencensus.io"
|
|||
|
||||
// Version is the current release version of OpenCensus in use.
|
||||
func Version() string {
|
||||
return "0.17.0"
|
||||
return "0.18.0"
|
||||
}
|
||||
|
|
|
@ -47,6 +47,10 @@ type Transport struct {
|
|||
// for spans started by this transport.
|
||||
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
|
||||
// from the information found in the outgoing HTTP Request. By default the
|
||||
// name equals the URL Path.
|
||||
|
@ -75,11 +79,17 @@ func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
|
|||
if spanNameFormatter == nil {
|
||||
spanNameFormatter = spanNameFromURL
|
||||
}
|
||||
|
||||
startOpts := t.StartOptions
|
||||
if t.GetStartOptions != nil {
|
||||
startOpts = t.GetStartOptions(req)
|
||||
}
|
||||
|
||||
rt = &traceTransport{
|
||||
base: rt,
|
||||
format: format,
|
||||
startOptions: trace.StartOptions{
|
||||
Sampler: t.StartOptions.Sampler,
|
||||
Sampler: startOpts.Sampler,
|
||||
SpanKind: trace.SpanKindClient,
|
||||
},
|
||||
formatSpanName: spanNameFormatter,
|
||||
|
|
|
@ -34,8 +34,11 @@ type statsTransport struct {
|
|||
// RoundTrip implements http.RoundTripper, delegating to Base and recording stats for the request.
|
||||
func (t statsTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
ctx, _ := tag.New(req.Context(),
|
||||
tag.Upsert(KeyClientHost, req.URL.Host),
|
||||
tag.Upsert(Host, req.URL.Host),
|
||||
tag.Upsert(KeyClientPath, req.URL.Path),
|
||||
tag.Upsert(Path, req.URL.Path),
|
||||
tag.Upsert(KeyClientMethod, req.Method),
|
||||
tag.Upsert(Method, req.Method))
|
||||
req = req.WithContext(ctx)
|
||||
track := &tracker{
|
||||
|
@ -92,15 +95,22 @@ var _ io.ReadCloser = (*tracker)(nil)
|
|||
|
||||
func (t *tracker) end() {
|
||||
t.endOnce.Do(func() {
|
||||
latencyMs := float64(time.Since(t.start)) / float64(time.Millisecond)
|
||||
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),
|
||||
}
|
||||
if t.reqSize >= 0 {
|
||||
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...)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -56,6 +56,10 @@ type Handler struct {
|
|||
// for spans started by this transport.
|
||||
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)
|
||||
// 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
|
||||
|
@ -93,15 +97,21 @@ func (h *Handler) startTrace(w http.ResponseWriter, r *http.Request) (*http.Requ
|
|||
name = h.FormatSpanName(r)
|
||||
}
|
||||
ctx := r.Context()
|
||||
|
||||
startOpts := h.StartOptions
|
||||
if h.GetStartOptions != nil {
|
||||
startOpts = h.GetStartOptions(r)
|
||||
}
|
||||
|
||||
var span *trace.Span
|
||||
sc, ok := h.extractSpanContext(r)
|
||||
if ok && !h.IsPublicEndpoint {
|
||||
ctx, span = trace.StartSpanWithRemoteParent(ctx, name, sc,
|
||||
trace.WithSampler(h.StartOptions.Sampler),
|
||||
trace.WithSampler(startOpts.Sampler),
|
||||
trace.WithSpanKind(trace.SpanKindServer))
|
||||
} else {
|
||||
ctx, span = trace.StartSpan(ctx, name,
|
||||
trace.WithSampler(h.StartOptions.Sampler),
|
||||
trace.WithSampler(startOpts.Sampler),
|
||||
trace.WithSpanKind(trace.SpanKindServer),
|
||||
)
|
||||
if ok {
|
||||
|
@ -168,6 +178,7 @@ func (t *trackingResponseWriter) end(tags *addedTags) {
|
|||
|
||||
span := trace.FromContext(t.ctx)
|
||||
span.SetStatus(TraceStatus(t.statusCode, t.statusLine))
|
||||
span.AddAttributes(trace.Int64Attribute(StatusCodeAttribute, int64(t.statusCode)))
|
||||
|
||||
m := []stats.Measurement{
|
||||
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[0] = tag.Upsert(StatusCode, strconv.Itoa(t.statusCode))
|
||||
copy(allTags[1:], tags.t)
|
||||
ctx, _ := tag.New(t.ctx, allTags...)
|
||||
stats.Record(ctx, m...)
|
||||
stats.RecordWithTags(t.ctx, allTags, m...)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,8 @@ type spanAnnotator struct {
|
|||
|
||||
// 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
|
||||
func NewSpanAnnotator(r *http.Request, s *trace.Span) *httptrace.ClientTrace {
|
||||
return NewSpanAnnotatingClientTrace(r, s)
|
||||
|
|
|
@ -22,10 +22,33 @@ import (
|
|||
|
||||
// The following client HTTP measures are supported for use in custom views.
|
||||
var (
|
||||
ClientRequestCount = stats.Int64("opencensus.io/http/client/request_count", "Number of HTTP requests started", stats.UnitDimensionless)
|
||||
ClientRequestBytes = stats.Int64("opencensus.io/http/client/request_bytes", "HTTP request body size if set as ContentLength (uncompressed)", stats.UnitBytes)
|
||||
// Deprecated: Use a Count aggregation over one of the other client measures to achieve the same effect.
|
||||
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)
|
||||
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:
|
||||
|
@ -67,6 +90,18 @@ var (
|
|||
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.
|
||||
var (
|
||||
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.
|
||||
// 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 (
|
||||
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{
|
||||
Name: "opencensus.io/http/client/request_count",
|
||||
Description: "Count of HTTP requests started",
|
||||
|
@ -83,43 +153,50 @@ var (
|
|||
Aggregation: view.Count(),
|
||||
}
|
||||
|
||||
// Deprecated: Use ClientSentBytesDistribution.
|
||||
ClientRequestBytesView = &view.View{
|
||||
Name: "opencensus.io/http/client/request_bytes",
|
||||
Description: "Size distribution of HTTP request body",
|
||||
Measure: ClientRequestBytes,
|
||||
Measure: ClientSentBytes,
|
||||
Aggregation: DefaultSizeDistribution,
|
||||
}
|
||||
|
||||
// Deprecated: Use ClientReceivedBytesDistribution.
|
||||
ClientResponseBytesView = &view.View{
|
||||
Name: "opencensus.io/http/client/response_bytes",
|
||||
Description: "Size distribution of HTTP response body",
|
||||
Measure: ClientResponseBytes,
|
||||
Measure: ClientReceivedBytes,
|
||||
Aggregation: DefaultSizeDistribution,
|
||||
}
|
||||
|
||||
// Deprecated: Use ClientRoundtripLatencyDistribution.
|
||||
ClientLatencyView = &view.View{
|
||||
Name: "opencensus.io/http/client/latency",
|
||||
Description: "Latency distribution of HTTP requests",
|
||||
Measure: ClientLatency,
|
||||
Measure: ClientRoundtripLatency,
|
||||
Aggregation: DefaultLatencyDistribution,
|
||||
}
|
||||
|
||||
// Deprecated: Use ClientCompletedCount.
|
||||
ClientRequestCountByMethod = &view.View{
|
||||
Name: "opencensus.io/http/client/request_count_by_method",
|
||||
Description: "Client request count by HTTP method",
|
||||
TagKeys: []tag.Key{Method},
|
||||
Measure: ClientRequestCount,
|
||||
Measure: ClientSentBytes,
|
||||
Aggregation: view.Count(),
|
||||
}
|
||||
|
||||
// Deprecated: Use ClientCompletedCount.
|
||||
ClientResponseCountByStatusCode = &view.View{
|
||||
Name: "opencensus.io/http/client/response_count_by_status_code",
|
||||
Description: "Client response count by status code",
|
||||
TagKeys: []tag.Key{StatusCode},
|
||||
Measure: ClientLatency,
|
||||
Measure: ClientRoundtripLatency,
|
||||
Aggregation: view.Count(),
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
ServerRequestCountView = &view.View{
|
||||
Name: "opencensus.io/http/server/request_count",
|
||||
Description: "Count of HTTP requests started",
|
||||
|
@ -166,6 +243,7 @@ var (
|
|||
)
|
||||
|
||||
// DefaultClientViews are the default client views provided by this package.
|
||||
// Deprecated: No replacement. Register the views you would like individually.
|
||||
var DefaultClientViews = []*view.View{
|
||||
ClientRequestCountView,
|
||||
ClientRequestBytesView,
|
||||
|
@ -176,6 +254,7 @@ var DefaultClientViews = []*view.View{
|
|||
}
|
||||
|
||||
// DefaultServerViews are the default server views provided by this package.
|
||||
// Deprecated: No replacement. Register the views you would like individually.
|
||||
var DefaultServerViews = []*view.View{
|
||||
ServerRequestCountView,
|
||||
ServerRequestBytesView,
|
||||
|
|
|
@ -21,35 +21,49 @@ aggregate the collected data, and export the aggregated data.
|
|||
|
||||
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
|
||||
to collect from a server.
|
||||
|
||||
Each measure needs to be registered before being used. Measure
|
||||
constructors such as Int64 and Float64 automatically
|
||||
Measure constructors such as Int64 and Float64 automatically
|
||||
register the measure by the given name. Each registered measure needs
|
||||
to be unique by name. Measures also have a description and a unit.
|
||||
|
||||
Libraries can define and export measures for their end users to
|
||||
create views and collect instrumentation data.
|
||||
Libraries can define and export measures. Application authors can then
|
||||
create views and collect and break down measures by the tags they are
|
||||
interested in.
|
||||
|
||||
Recording measurements
|
||||
|
||||
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
|
||||
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
|
||||
measurements if they are any.
|
||||
|
||||
Recorded measurements are dropped immediately if user is not aggregating
|
||||
them via views. Users don't necessarily need to conditionally enable/disable
|
||||
Recorded measurements are dropped immediately if no views are registered for them.
|
||||
There is usually no need to conditionally enable and disable
|
||||
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
|
||||
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"
|
||||
|
||||
// TODO(acetechnologist): Add a link to the language independent OpenCensus
|
||||
// spec when it is available.
|
||||
|
|
|
@ -19,7 +19,7 @@ import (
|
|||
)
|
||||
|
||||
// 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.
|
||||
var SubscriptionReporter func(measure string)
|
||||
|
|
|
@ -68,6 +68,21 @@ func (m *measureDescriptor) subscribed() bool {
|
|||
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 (
|
||||
mu sync.RWMutex
|
||||
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.
|
||||
type Measurement struct {
|
||||
v float64
|
||||
m Measure
|
||||
m *measureDescriptor
|
||||
}
|
||||
|
||||
// Value returns the value of the Measurement as a float64.
|
||||
|
|
|
@ -17,31 +17,13 @@ package stats
|
|||
|
||||
// Float64Measure is a measure for float64 values.
|
||||
type Float64Measure struct {
|
||||
md *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
|
||||
*measureDescriptor
|
||||
}
|
||||
|
||||
// M creates a new float64 measurement.
|
||||
// Use Record to record measurements.
|
||||
func (m *Float64Measure) M(v float64) Measurement {
|
||||
if !m.md.subscribed() {
|
||||
return Measurement{}
|
||||
}
|
||||
return Measurement{m: m, v: v}
|
||||
return Measurement{m: m.measureDescriptor, v: v}
|
||||
}
|
||||
|
||||
// Float64 creates a new measure for float64 values.
|
||||
|
|
|
@ -17,31 +17,13 @@ package stats
|
|||
|
||||
// Int64Measure is a measure for int64 values.
|
||||
type Int64Measure struct {
|
||||
md *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
|
||||
*measureDescriptor
|
||||
}
|
||||
|
||||
// M creates a new int64 measurement.
|
||||
// Use Record to record measurements.
|
||||
func (m *Int64Measure) M(v int64) Measurement {
|
||||
if !m.md.subscribed() {
|
||||
return Measurement{}
|
||||
}
|
||||
return Measurement{m: m, v: float64(v)}
|
||||
return Measurement{m: m.measureDescriptor, v: float64(v)}
|
||||
}
|
||||
|
||||
// Int64 creates a new measure for int64 values.
|
||||
|
|
|
@ -18,6 +18,7 @@ package stats
|
|||
import (
|
||||
"context"
|
||||
|
||||
"go.opencensus.io/exemplar"
|
||||
"go.opencensus.io/stats/internal"
|
||||
"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.
|
||||
func Record(ctx context.Context, ms ...Measurement) {
|
||||
recorder := internal.DefaultRecorder
|
||||
if recorder == nil {
|
||||
return
|
||||
}
|
||||
if len(ms) == 0 {
|
||||
return
|
||||
}
|
||||
var record bool
|
||||
record := false
|
||||
for _, m := range ms {
|
||||
if (m != Measurement{}) {
|
||||
if m.m.subscribed() {
|
||||
record = true
|
||||
break
|
||||
}
|
||||
|
@ -46,7 +51,19 @@ func Record(ctx context.Context, ms ...Measurement) {
|
|||
if !record {
|
||||
return
|
||||
}
|
||||
if internal.DefaultRecorder != nil {
|
||||
internal.DefaultRecorder(tag.FromContext(ctx), ms)
|
||||
}
|
||||
recorder(tag.FromContext(ctx), ms, exemplar.AttachmentsFromContext(ctx))
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@ package view
|
|||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"go.opencensus.io/exemplar"
|
||||
)
|
||||
|
||||
// AggregationData represents an aggregated value from a collection.
|
||||
|
@ -24,7 +26,7 @@ import (
|
|||
// Mosts users won't directly access aggregration data.
|
||||
type AggregationData interface {
|
||||
isAggregationData() bool
|
||||
addSample(v float64)
|
||||
addSample(e *exemplar.Exemplar)
|
||||
clone() AggregationData
|
||||
equal(other AggregationData) bool
|
||||
}
|
||||
|
@ -41,7 +43,7 @@ type CountData struct {
|
|||
|
||||
func (a *CountData) isAggregationData() bool { return true }
|
||||
|
||||
func (a *CountData) addSample(v float64) {
|
||||
func (a *CountData) addSample(_ *exemplar.Exemplar) {
|
||||
a.Value = a.Value + 1
|
||||
}
|
||||
|
||||
|
@ -68,8 +70,8 @@ type SumData struct {
|
|||
|
||||
func (a *SumData) isAggregationData() bool { return true }
|
||||
|
||||
func (a *SumData) addSample(f float64) {
|
||||
a.Value += f
|
||||
func (a *SumData) addSample(e *exemplar.Exemplar) {
|
||||
a.Value += e.Value
|
||||
}
|
||||
|
||||
func (a *SumData) clone() AggregationData {
|
||||
|
@ -88,22 +90,30 @@ func (a *SumData) equal(other AggregationData) bool {
|
|||
// Distribution aggregation.
|
||||
//
|
||||
// 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 {
|
||||
Count int64 // number of data points aggregated
|
||||
Min float64 // minimum value in the distribution
|
||||
Max float64 // max value in the distribution
|
||||
Mean float64 // mean of the distribution
|
||||
SumOfSquaredDev float64 // sum of the squared deviation from the mean
|
||||
CountPerBucket []int64 // number of occurrences per bucket
|
||||
bounds []float64 // histogram distribution of the values
|
||||
Count int64 // number of data points aggregated
|
||||
Min float64 // minimum value in the distribution
|
||||
Max float64 // max value in the distribution
|
||||
Mean float64 // mean of the distribution
|
||||
SumOfSquaredDev float64 // sum of the squared deviation from the mean
|
||||
CountPerBucket []int64 // number of occurrences per bucket
|
||||
// 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 {
|
||||
bucketCount := len(bounds) + 1
|
||||
return &DistributionData{
|
||||
CountPerBucket: make([]int64, len(bounds)+1),
|
||||
bounds: bounds,
|
||||
Min: math.MaxFloat64,
|
||||
Max: math.SmallestNonzeroFloat64,
|
||||
CountPerBucket: make([]int64, bucketCount),
|
||||
ExemplarsPerBucket: make([]*exemplar.Exemplar, bucketCount),
|
||||
bounds: bounds,
|
||||
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) addSample(f float64) {
|
||||
func (a *DistributionData) addSample(e *exemplar.Exemplar) {
|
||||
f := e.Value
|
||||
if f < a.Min {
|
||||
a.Min = f
|
||||
}
|
||||
|
@ -127,7 +138,7 @@ func (a *DistributionData) addSample(f float64) {
|
|||
a.Max = f
|
||||
}
|
||||
a.Count++
|
||||
a.incrementBucketCount(f)
|
||||
a.addToBucket(e)
|
||||
|
||||
if a.Count == 1 {
|
||||
a.Mean = f
|
||||
|
@ -139,26 +150,43 @@ func (a *DistributionData) addSample(f float64) {
|
|||
a.SumOfSquaredDev = a.SumOfSquaredDev + (f-oldMean)*(f-a.Mean)
|
||||
}
|
||||
|
||||
func (a *DistributionData) incrementBucketCount(f float64) {
|
||||
if len(a.bounds) == 0 {
|
||||
a.CountPerBucket[0]++
|
||||
return
|
||||
}
|
||||
|
||||
func (a *DistributionData) addToBucket(e *exemplar.Exemplar) {
|
||||
var count *int64
|
||||
var ex **exemplar.Exemplar
|
||||
for i, b := range a.bounds {
|
||||
if f < b {
|
||||
a.CountPerBucket[i]++
|
||||
return
|
||||
if e.Value < b {
|
||||
count = &a.CountPerBucket[i]
|
||||
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 {
|
||||
counts := make([]int64, len(a.CountPerBucket))
|
||||
copy(counts, a.CountPerBucket)
|
||||
c := *a
|
||||
c.CountPerBucket = counts
|
||||
c.CountPerBucket = append([]int64(nil), a.CountPerBucket...)
|
||||
c.ExemplarsPerBucket = append([]*exemplar.Exemplar(nil), a.ExemplarsPerBucket...)
|
||||
return &c
|
||||
}
|
||||
|
||||
|
@ -190,8 +218,8 @@ func (l *LastValueData) isAggregationData() bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func (l *LastValueData) addSample(v float64) {
|
||||
l.Value = v
|
||||
func (l *LastValueData) addSample(e *exemplar.Exemplar) {
|
||||
l.Value = e.Value
|
||||
}
|
||||
|
||||
func (l *LastValueData) clone() AggregationData {
|
||||
|
|
|
@ -18,6 +18,8 @@ package view
|
|||
import (
|
||||
"sort"
|
||||
|
||||
"go.opencensus.io/exemplar"
|
||||
|
||||
"go.opencensus.io/internal/tagencoding"
|
||||
"go.opencensus.io/tag"
|
||||
)
|
||||
|
@ -31,13 +33,13 @@ type collector struct {
|
|||
a *Aggregation
|
||||
}
|
||||
|
||||
func (c *collector) addSample(s string, v float64) {
|
||||
func (c *collector) addSample(s string, e *exemplar.Exemplar) {
|
||||
aggregator, ok := c.signatures[s]
|
||||
if !ok {
|
||||
aggregator = c.a.newData()
|
||||
c.signatures[s] = aggregator
|
||||
}
|
||||
aggregator.addSample(v)
|
||||
aggregator.addSample(e)
|
||||
}
|
||||
|
||||
// collectRows returns a snapshot of the collected Row values.
|
||||
|
|
|
@ -13,33 +13,34 @@
|
|||
// limitations under the License.
|
||||
//
|
||||
|
||||
/*
|
||||
Package view contains support for collecting and exposing aggregates over stats.
|
||||
|
||||
In order to collect measurements, views need to be defined and registered.
|
||||
A view allows recorded measurements to be filtered and aggregated over a time window.
|
||||
|
||||
All recorded measurements can be filtered by a list of tags.
|
||||
|
||||
OpenCensus provides several aggregation methods: count, distribution and sum.
|
||||
Count aggregation only counts the number of measurement points. Distribution
|
||||
aggregation provides statistical summary of the aggregated data. Sum distribution
|
||||
sums up the measurement points. Aggregations are cumulative.
|
||||
|
||||
Users can dynamically create and delete views.
|
||||
|
||||
Libraries can export their own views and claim the view names
|
||||
by registering them themselves.
|
||||
|
||||
Exporting
|
||||
|
||||
Collected and aggregated data can be exported to a metric collection
|
||||
backend by registering its exporter.
|
||||
|
||||
Multiple exporters can be registered to upload the data to various
|
||||
different backends. Users need to unregister the exporters once they
|
||||
no longer are needed.
|
||||
*/
|
||||
// Package view contains support for collecting and exposing aggregates over stats.
|
||||
//
|
||||
// In order to collect measurements, views need to be defined and registered.
|
||||
// A view allows recorded measurements to be filtered and aggregated.
|
||||
//
|
||||
// All recorded measurements can be grouped by a list of tags.
|
||||
//
|
||||
// OpenCensus provides several aggregation methods: Count, Distribution and Sum.
|
||||
//
|
||||
// Count only counts the number of measurement points recorded.
|
||||
// Distribution provides statistical summary of the aggregated data by counting
|
||||
// how many recorded measurements fall into each bucket.
|
||||
// Sum adds up the measurement values.
|
||||
// LastValue just keeps track of the most recently recorded measurement value.
|
||||
// All aggregations are cumulative.
|
||||
//
|
||||
// Views can be registerd and unregistered at any time during program execution.
|
||||
//
|
||||
// Libraries can define views but it is recommended that in most cases registering
|
||||
// views be left up to applications.
|
||||
//
|
||||
// Exporting
|
||||
//
|
||||
// Collected and aggregated data can be exported to a metric collection
|
||||
// backend by registering its exporter.
|
||||
//
|
||||
// Multiple exporters can be registered to upload the data to various
|
||||
// different back ends.
|
||||
package view // import "go.opencensus.io/stats/view"
|
||||
|
||||
// TODO(acetechnologist): Add a link to the language independent OpenCensus
|
||||
|
|
|
@ -23,6 +23,8 @@ import (
|
|||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"go.opencensus.io/exemplar"
|
||||
|
||||
"go.opencensus.io/stats"
|
||||
"go.opencensus.io/stats/internal"
|
||||
"go.opencensus.io/tag"
|
||||
|
@ -127,12 +129,12 @@ func (v *viewInternal) collectedRows() []*Row {
|
|||
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() {
|
||||
return
|
||||
}
|
||||
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
|
||||
|
|
|
@ -107,10 +107,12 @@ func RetrieveData(viewName string) ([]*Row, error) {
|
|||
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{
|
||||
tm: tags,
|
||||
ms: ms.([]stats.Measurement),
|
||||
tm: tags,
|
||||
ms: ms.([]stats.Measurement),
|
||||
attachments: attachments,
|
||||
t: time.Now(),
|
||||
}
|
||||
defaultWorker.c <- req
|
||||
}
|
||||
|
|
|
@ -21,6 +21,8 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"go.opencensus.io/exemplar"
|
||||
|
||||
"go.opencensus.io/stats"
|
||||
"go.opencensus.io/stats/internal"
|
||||
"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
|
||||
// at once.
|
||||
type recordReq struct {
|
||||
tm *tag.Map
|
||||
ms []stats.Measurement
|
||||
tm *tag.Map
|
||||
ms []stats.Measurement
|
||||
attachments map[string]string
|
||||
t time.Time
|
||||
}
|
||||
|
||||
func (cmd *recordReq) handleCommand(w *worker) {
|
||||
|
@ -151,7 +155,12 @@ func (cmd *recordReq) handleCommand(w *worker) {
|
|||
}
|
||||
ref := w.getMeasureRef(m.Measure().Name())
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,11 @@
|
|||
|
||||
package tag
|
||||
|
||||
import "context"
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.opencensus.io/exemplar"
|
||||
)
|
||||
|
||||
// FromContext returns the tag map stored in the context.
|
||||
func FromContext(ctx context.Context) *Map {
|
||||
|
@ -39,3 +43,25 @@ func NewContext(ctx context.Context, m *Map) context.Context {
|
|||
type ctxKey struct{}
|
||||
|
||||
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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -243,13 +243,16 @@ func startSpanInternal(name string, hasParent bool, parent SpanContext, remotePa
|
|||
|
||||
// End ends the span.
|
||||
func (s *Span) End() {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
if s.executionTracerTaskEnd != nil {
|
||||
s.executionTracerTaskEnd()
|
||||
}
|
||||
if !s.IsRecordingEvents() {
|
||||
return
|
||||
}
|
||||
s.endOnce.Do(func() {
|
||||
if s.executionTracerTaskEnd != nil {
|
||||
s.executionTracerTaskEnd()
|
||||
}
|
||||
exp, _ := exporters.Load().(exportersMap)
|
||||
mustExport := s.spanContext.IsSampled() && len(exp) > 0
|
||||
if s.spanStore != nil || mustExport {
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package tracestate implements support for the Tracestate header of the
|
||||
// W3C TraceContext propagation format.
|
||||
package tracestate
|
||||
|
||||
import (
|
||||
|
|
|
@ -24,7 +24,9 @@ See godoc for further documentation and examples.
|
|||
|
||||
In change 96e89be (March 2015), we removed the `oauth2.Context2` type in favor
|
||||
of the [`context.Context`](https://golang.org/x/net/context#Context) type from
|
||||
the `golang.org/x/net/context` package
|
||||
the `golang.org/x/net/context` package. Later replaced by the standard `context` package
|
||||
of the [`context.Context`](https://golang.org/pkg/context#Context) type.
|
||||
|
||||
|
||||
This means it's no longer possible to use the "Classic App Engine"
|
||||
`appengine.Context` type with the `oauth2` package. (You're using
|
||||
|
@ -44,7 +46,7 @@ with the `oauth2` package.
|
|||
|
||||
```go
|
||||
import (
|
||||
"golang.org/x/net/context"
|
||||
"context"
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/google"
|
||||
newappengine "google.golang.org/appengine"
|
||||
|
@ -68,6 +70,13 @@ func handler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
```
|
||||
|
||||
## Policy for new packages
|
||||
|
||||
We no longer accept new provider-specific packages in this repo. For
|
||||
defining provider endpoints and provider-specific OAuth2 behavior, we
|
||||
encourage you to create packages elsewhere. We'll keep the existing
|
||||
packages for compatibility.
|
||||
|
||||
## Report Issues / Send Patches
|
||||
|
||||
This repository uses Gerrit for code changes. To learn how to submit changes to
|
||||
|
|
|
@ -5,85 +5,34 @@
|
|||
package google
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
// appengineFlex is set at init time by appengineflex_hook.go. If true, we are on App Engine Flex.
|
||||
var appengineFlex bool
|
||||
|
||||
// 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 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
|
||||
|
||||
// AppEngineTokenSource returns a token source that fetches tokens
|
||||
// issued to the current App Engine application's service account.
|
||||
// If you are implementing a 3-legged OAuth 2.0 flow on App Engine
|
||||
// that involves user accounts, see oauth2.Config instead.
|
||||
// AppEngineTokenSource returns a token source that fetches tokens from either
|
||||
// the current application's service account or from the metadata server,
|
||||
// depending on the App Engine environment. See below for environment-specific
|
||||
// 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 {
|
||||
if appengineTokenFunc == nil {
|
||||
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
|
||||
return appEngineTokenSource(ctx, scope...)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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("")
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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.
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
package google
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
@ -14,10 +15,28 @@ import (
|
|||
"runtime"
|
||||
|
||||
"cloud.google.com/go/compute/metadata"
|
||||
"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
|
||||
|
||||
// DefaultClient returns an HTTP Client that uses the
|
||||
// DefaultTokenSource to obtain authentication credentials.
|
||||
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
|
||||
}
|
||||
|
||||
// Common implementation for FindDefaultCredentials.
|
||||
func findDefaultCredentials(ctx context.Context, scopes []string) (*DefaultCredentials, error) {
|
||||
// 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 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.
|
||||
const envVar = "GOOGLE_APPLICATION_CREDENTIALS"
|
||||
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)
|
||||
}
|
||||
|
||||
// Third, if we're on Google App Engine use those credentials.
|
||||
if appengineTokenFunc != nil && !appengineFlex {
|
||||
// Third, if we're on a Google App Engine standard first generation runtime (<= Go 1.9)
|
||||
// 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{
|
||||
ProjectID: appengineAppIDFunc(ctx),
|
||||
TokenSource: AppEngineTokenSource(ctx, scopes...),
|
||||
}, 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() {
|
||||
id, _ := metadata.ProjectID()
|
||||
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)
|
||||
}
|
||||
|
||||
// Common implementation for CredentialsFromJSON.
|
||||
func credentialsFromJSON(ctx context.Context, jsonData []byte, scopes []string) (*DefaultCredentials, error) {
|
||||
// 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) {
|
||||
var f credentialsFile
|
||||
if err := json.Unmarshal(jsonData, &f); err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// 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
|
|
@ -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"
|
|
@ -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)
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
package google
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
@ -12,7 +13,6 @@ import (
|
|||
"time"
|
||||
|
||||
"cloud.google.com/go/compute/metadata"
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/jwt"
|
||||
)
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -6,6 +6,7 @@ package google
|
|||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
@ -18,7 +19,6 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ func ParseKey(key []byte) (*rsa.PrivateKey, error) {
|
|||
if err != nil {
|
||||
parsedKey, err = x509.ParsePKCS1PrivateKey(key)
|
||||
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)
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
@ -17,7 +18,6 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/net/context/ctxhttp"
|
||||
)
|
||||
|
||||
|
@ -133,6 +133,10 @@ var brokenAuthHeaderProviders = []string{
|
|||
"https://whats.todaysplan.com.au/rest/oauth/access_token",
|
||||
"https://stackoverflow.com/oauth/access_token",
|
||||
"https://account.health.nokia.com",
|
||||
"https://accounts.zoho.com",
|
||||
"https://gitter.im/login/oauth/token",
|
||||
"https://openid-connect.onelogin.com/oidc",
|
||||
"https://api.dailymotion.com/oauth/token",
|
||||
}
|
||||
|
||||
// brokenAuthHeaderDomains lists broken providers that issue dynamic endpoints.
|
||||
|
|
|
@ -5,9 +5,8 @@
|
|||
package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// HTTPClient is the context key to use with golang.org/x/net/context's
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
package jwt
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
|
@ -18,7 +19,6 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/internal"
|
||||
"golang.org/x/oauth2/jws"
|
||||
|
|
|
@ -10,13 +10,13 @@ package oauth2 // import "golang.org/x/oauth2"
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/oauth2/internal"
|
||||
)
|
||||
|
||||
|
@ -164,8 +164,7 @@ func (c *Config) AuthCodeURL(state string, opts ...AuthCodeOption) string {
|
|||
// and when other authorization grant types are not available."
|
||||
// See https://tools.ietf.org/html/rfc6749#section-4.3 for more info.
|
||||
//
|
||||
// The HTTP client to use is derived from the context.
|
||||
// If nil, http.DefaultClient is used.
|
||||
// The provided context optionally controls which HTTP client is used. See the HTTPClient variable.
|
||||
func (c *Config) PasswordCredentialsToken(ctx context.Context, username, password string) (*Token, error) {
|
||||
v := url.Values{
|
||||
"grant_type": {"password"},
|
||||
|
@ -183,8 +182,7 @@ func (c *Config) PasswordCredentialsToken(ctx context.Context, username, passwor
|
|||
// It is used after a resource provider redirects the user back
|
||||
// to the Redirect URI (the URL obtained from AuthCodeURL).
|
||||
//
|
||||
// The HTTP client to use is derived from the context.
|
||||
// If a client is not provided via the context, http.DefaultClient is used.
|
||||
// The provided context optionally controls which HTTP client is used. See the HTTPClient variable.
|
||||
//
|
||||
// The code will be in the *http.Request.FormValue("code"). Before
|
||||
// calling Exchange, be sure to validate FormValue("state").
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
package oauth2
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
@ -12,7 +13,6 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/oauth2/internal"
|
||||
)
|
||||
|
||||
|
|
|
@ -124,7 +124,7 @@ func (e *Encoder) Writer(w io.Writer) io.Writer {
|
|||
}
|
||||
|
||||
// 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'
|
||||
|
||||
// Nop is the nop encoding. Its transformed bytes are the same as the source
|
||||
|
|
|
@ -306,6 +306,7 @@ var nameMap = map[string]htmlEncoding{
|
|||
"iso-2022-cn": replacement,
|
||||
"iso-2022-cn-ext": replacement,
|
||||
"iso-2022-kr": replacement,
|
||||
"replacement": replacement,
|
||||
"utf-16be": utf16be,
|
||||
"utf-16": utf16le,
|
||||
"utf-16le": utf16le,
|
||||
|
|
|
@ -34,7 +34,7 @@ package identifier
|
|||
// - http://www.iana.org/assignments/character-sets/character-sets.xhtml
|
||||
// - http://www.iana.org/assignments/ianacharset-mib/ianacharset-mib
|
||||
// - 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/
|
||||
// - https://encoding.spec.whatwg.org/
|
||||
// - https://encoding.spec.whatwg.org/encodings.json
|
||||
|
|
|
@ -884,27 +884,27 @@ const (
|
|||
|
||||
// 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
|
||||
|
||||
// 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
|
||||
|
||||
// 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
|
||||
|
||||
// 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
|
||||
|
||||
// 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
|
||||
|
||||
// Windows30Latin1 is the MIB identifier with IANA name ISO-8859-1-Windows-3.0-Latin-1.
|
||||
|
|
|
@ -10,8 +10,8 @@ package main
|
|||
// go run maketables.go | gofmt > tables.go
|
||||
|
||||
// TODO: Emoji extensions?
|
||||
// http://www.unicode.org/faq/emoji_dingbats.html
|
||||
// http://www.unicode.org/Public/UNIDATA/EmojiSources.txt
|
||||
// https://www.unicode.org/faq/emoji_dingbats.html
|
||||
// https://www.unicode.org/Public/UNIDATA/EmojiSources.txt
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
|
|
|
@ -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
|
||||
// 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
|
||||
// BOM should not be used" and ExpectBOM corresponds to "A particular
|
||||
// protocol... may require use of the BOM".
|
||||
|
|
|
@ -4,13 +4,13 @@ package language
|
|||
|
||||
// This file contains code common to the maketables.go and the package code.
|
||||
|
||||
// langAliasType is the type of an alias in langAliasMap.
|
||||
type langAliasType int8
|
||||
// AliasType is the type of an alias in AliasMap.
|
||||
type AliasType int8
|
||||
|
||||
const (
|
||||
langDeprecated langAliasType = iota
|
||||
langMacro
|
||||
langLegacy
|
||||
Deprecated AliasType = iota
|
||||
Macro
|
||||
Legacy
|
||||
|
||||
langAliasTypeUnknown langAliasType = -1
|
||||
AliasTypeUnknown AliasType = -1
|
||||
)
|
|
@ -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,
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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"
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -0,0 +1,260 @@
|
|||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:generate go run gen.go gen_index.go -output tables.go
|
||||
//go:generate go run gen_parents.go
|
||||
|
||||
package compact
|
||||
|
||||
// TODO: Remove above NOTE after:
|
||||
// - verifying that tables are dropped correctly (most notably matcher tables).
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"golang.org/x/text/internal/language"
|
||||
)
|
||||
|
||||
// Tag represents a BCP 47 language tag. It is used to specify an instance of a
|
||||
// specific language or locale. All language tag values are guaranteed to be
|
||||
// well-formed.
|
||||
type Tag struct {
|
||||
// NOTE: exported tags will become part of the public API.
|
||||
language ID
|
||||
locale ID
|
||||
full fullTag // always a language.Tag for now.
|
||||
}
|
||||
|
||||
const _und = 0
|
||||
|
||||
type fullTag interface {
|
||||
IsRoot() bool
|
||||
Parent() language.Tag
|
||||
}
|
||||
|
||||
// Make a compact Tag from a fully specified internal language Tag.
|
||||
func Make(t language.Tag) (tag Tag) {
|
||||
if region := t.TypeForKey("rg"); len(region) == 6 && region[2:] == "zzzz" {
|
||||
if r, err := language.ParseRegion(region[:2]); err == nil {
|
||||
tFull := t
|
||||
t, _ = t.SetTypeForKey("rg", "")
|
||||
// TODO: should we not consider "va" for the language tag?
|
||||
var exact1, exact2 bool
|
||||
tag.language, exact1 = FromTag(t)
|
||||
t.RegionID = r
|
||||
tag.locale, exact2 = FromTag(t)
|
||||
if !exact1 || !exact2 {
|
||||
tag.full = tFull
|
||||
}
|
||||
return tag
|
||||
}
|
||||
}
|
||||
lang, ok := FromTag(t)
|
||||
tag.language = lang
|
||||
tag.locale = lang
|
||||
if !ok {
|
||||
tag.full = t
|
||||
}
|
||||
return tag
|
||||
}
|
||||
|
||||
// Tag returns an internal language Tag version of this tag.
|
||||
func (t Tag) Tag() language.Tag {
|
||||
if t.full != nil {
|
||||
return t.full.(language.Tag)
|
||||
}
|
||||
tag := t.language.Tag()
|
||||
if t.language != t.locale {
|
||||
loc := t.locale.Tag()
|
||||
tag, _ = tag.SetTypeForKey("rg", strings.ToLower(loc.RegionID.String())+"zzzz")
|
||||
}
|
||||
return tag
|
||||
}
|
||||
|
||||
// IsCompact reports whether this tag is fully defined in terms of ID.
|
||||
func (t *Tag) IsCompact() bool {
|
||||
return t.full == nil
|
||||
}
|
||||
|
||||
// MayHaveVariants reports whether a tag may have variants. If it returns false
|
||||
// it is guaranteed the tag does not have variants.
|
||||
func (t Tag) MayHaveVariants() bool {
|
||||
return t.full != nil || int(t.language) >= len(coreTags)
|
||||
}
|
||||
|
||||
// MayHaveExtensions reports whether a tag may have extensions. If it returns
|
||||
// false it is guaranteed the tag does not have them.
|
||||
func (t Tag) MayHaveExtensions() bool {
|
||||
return t.full != nil ||
|
||||
int(t.language) >= len(coreTags) ||
|
||||
t.language != t.locale
|
||||
}
|
||||
|
||||
// IsRoot returns true if t is equal to language "und".
|
||||
func (t Tag) IsRoot() bool {
|
||||
if t.full != nil {
|
||||
return t.full.IsRoot()
|
||||
}
|
||||
return t.language == _und
|
||||
}
|
||||
|
||||
// Parent returns the CLDR parent of t. In CLDR, missing fields in data for a
|
||||
// specific language are substituted with fields from the parent language.
|
||||
// The parent for a language may change for newer versions of CLDR.
|
||||
func (t Tag) Parent() Tag {
|
||||
if t.full != nil {
|
||||
return Make(t.full.Parent())
|
||||
}
|
||||
if t.language != t.locale {
|
||||
// Simulate stripping -u-rg-xxxxxx
|
||||
return Tag{language: t.language, locale: t.language}
|
||||
}
|
||||
// TODO: use parent lookup table once cycle from internal package is
|
||||
// removed. Probably by internalizing the table and declaring this fast
|
||||
// enough.
|
||||
// lang := compactID(internal.Parent(uint16(t.language)))
|
||||
lang, _ := FromTag(t.language.Tag().Parent())
|
||||
return Tag{language: lang, locale: lang}
|
||||
}
|
||||
|
||||
// returns token t and the rest of the string.
|
||||
func nextToken(s string) (t, tail string) {
|
||||
p := strings.Index(s[1:], "-")
|
||||
if p == -1 {
|
||||
return s[1:], ""
|
||||
}
|
||||
p++
|
||||
return s[1:p], s[p:]
|
||||
}
|
||||
|
||||
// LanguageID returns an index, where 0 <= index < NumCompactTags, for tags
|
||||
// for which data exists in the text repository.The index will change over time
|
||||
// and should not be stored in persistent storage. If t does not match a compact
|
||||
// index, exact will be false and the compact index will be returned for the
|
||||
// first match after repeatedly taking the Parent of t.
|
||||
func LanguageID(t Tag) (id ID, exact bool) {
|
||||
return t.language, t.full == nil
|
||||
}
|
||||
|
||||
// RegionalID returns the ID for the regional variant of this tag. This index is
|
||||
// used to indicate region-specific overrides, such as default currency, default
|
||||
// calendar and week data, default time cycle, and default measurement system
|
||||
// and unit preferences.
|
||||
//
|
||||
// For instance, the tag en-GB-u-rg-uszzzz specifies British English with US
|
||||
// settings for currency, number formatting, etc. The CompactIndex for this tag
|
||||
// will be that for en-GB, while the RegionalID will be the one corresponding to
|
||||
// en-US.
|
||||
func RegionalID(t Tag) (id ID, exact bool) {
|
||||
return t.locale, t.full == nil
|
||||
}
|
||||
|
||||
// LanguageTag returns t stripped of regional variant indicators.
|
||||
//
|
||||
// At the moment this means it is stripped of a regional and variant subtag "rg"
|
||||
// and "va" in the "u" extension.
|
||||
func (t Tag) LanguageTag() Tag {
|
||||
if t.full == nil {
|
||||
return Tag{language: t.language, locale: t.language}
|
||||
}
|
||||
tt := t.Tag()
|
||||
tt.SetTypeForKey("rg", "")
|
||||
tt.SetTypeForKey("va", "")
|
||||
return Make(tt)
|
||||
}
|
||||
|
||||
// RegionalTag returns the regional variant of the tag.
|
||||
//
|
||||
// At the moment this means that the region is set from the regional subtag
|
||||
// "rg" in the "u" extension.
|
||||
func (t Tag) RegionalTag() Tag {
|
||||
rt := Tag{language: t.locale, locale: t.locale}
|
||||
if t.full == nil {
|
||||
return rt
|
||||
}
|
||||
b := language.Builder{}
|
||||
tag := t.Tag()
|
||||
// tag, _ = tag.SetTypeForKey("rg", "")
|
||||
b.SetTag(t.locale.Tag())
|
||||
if v := tag.Variants(); v != "" {
|
||||
for _, v := range strings.Split(v, "-") {
|
||||
b.AddVariant(v)
|
||||
}
|
||||
}
|
||||
for _, e := range tag.Extensions() {
|
||||
b.AddExt(e)
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// FromTag reports closest matching ID for an internal language Tag.
|
||||
func FromTag(t language.Tag) (id ID, exact bool) {
|
||||
// TODO: perhaps give more frequent tags a lower index.
|
||||
// TODO: we could make the indexes stable. This will excluded some
|
||||
// possibilities for optimization, so don't do this quite yet.
|
||||
exact = true
|
||||
|
||||
b, s, r := t.Raw()
|
||||
if t.HasString() {
|
||||
if t.IsPrivateUse() {
|
||||
// We have no entries for user-defined tags.
|
||||
return 0, false
|
||||
}
|
||||
hasExtra := false
|
||||
if t.HasVariants() {
|
||||
if t.HasExtensions() {
|
||||
build := language.Builder{}
|
||||
build.SetTag(language.Tag{LangID: b, ScriptID: s, RegionID: r})
|
||||
build.AddVariant(t.Variants())
|
||||
exact = false
|
||||
t = build.Make()
|
||||
}
|
||||
hasExtra = true
|
||||
} else if _, ok := t.Extension('u'); ok {
|
||||
// TODO: va may mean something else. Consider not considering it.
|
||||
// Strip all but the 'va' entry.
|
||||
old := t
|
||||
variant := t.TypeForKey("va")
|
||||
t = language.Tag{LangID: b, ScriptID: s, RegionID: r}
|
||||
if variant != "" {
|
||||
t, _ = t.SetTypeForKey("va", variant)
|
||||
hasExtra = true
|
||||
}
|
||||
exact = old == t
|
||||
} else {
|
||||
exact = false
|
||||
}
|
||||
if hasExtra {
|
||||
// We have some variants.
|
||||
for i, s := range specialTags {
|
||||
if s == t {
|
||||
return ID(i + len(coreTags)), exact
|
||||
}
|
||||
}
|
||||
exact = false
|
||||
}
|
||||
}
|
||||
if x, ok := getCoreIndex(t); ok {
|
||||
return x, exact
|
||||
}
|
||||
exact = false
|
||||
if r != 0 && s == 0 {
|
||||
// Deal with cases where an extra script is inserted for the region.
|
||||
t, _ := t.Maximize()
|
||||
if x, ok := getCoreIndex(t); ok {
|
||||
return x, exact
|
||||
}
|
||||
}
|
||||
for t = t.Parent(); t != root; t = t.Parent() {
|
||||
// No variants specified: just compare core components.
|
||||
// The key has the form lllssrrr, where l, s, and r are nibbles for
|
||||
// respectively the langID, scriptID, and regionID.
|
||||
if x, ok := getCoreIndex(t); ok {
|
||||
return x, exact
|
||||
}
|
||||
}
|
||||
return 0, exact
|
||||
}
|
||||
|
||||
var root = language.Tag{}
|
|
@ -0,0 +1,120 @@
|
|||
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
|
||||
|
||||
package compact
|
||||
|
||||
// parents maps a compact index of a tag to the compact index of the parent of
|
||||
// this tag.
|
||||
var parents = []ID{ // 775 elements
|
||||
// Entry 0 - 3F
|
||||
0x0000, 0x0000, 0x0001, 0x0001, 0x0000, 0x0004, 0x0000, 0x0006,
|
||||
0x0000, 0x0008, 0x0000, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a,
|
||||
0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a,
|
||||
0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a,
|
||||
0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x0000,
|
||||
0x0000, 0x0028, 0x0000, 0x002a, 0x0000, 0x002c, 0x0000, 0x0000,
|
||||
0x002f, 0x002e, 0x002e, 0x0000, 0x0033, 0x0000, 0x0035, 0x0000,
|
||||
0x0037, 0x0000, 0x0039, 0x0000, 0x003b, 0x0000, 0x0000, 0x003e,
|
||||
// Entry 40 - 7F
|
||||
0x0000, 0x0040, 0x0040, 0x0000, 0x0043, 0x0043, 0x0000, 0x0046,
|
||||
0x0000, 0x0048, 0x0000, 0x0000, 0x004b, 0x004a, 0x004a, 0x0000,
|
||||
0x004f, 0x004f, 0x004f, 0x004f, 0x0000, 0x0054, 0x0054, 0x0000,
|
||||
0x0057, 0x0000, 0x0059, 0x0000, 0x005b, 0x0000, 0x005d, 0x005d,
|
||||
0x0000, 0x0060, 0x0000, 0x0062, 0x0000, 0x0064, 0x0000, 0x0066,
|
||||
0x0066, 0x0000, 0x0069, 0x0000, 0x006b, 0x006b, 0x006b, 0x006b,
|
||||
0x006b, 0x006b, 0x006b, 0x0000, 0x0073, 0x0000, 0x0075, 0x0000,
|
||||
0x0077, 0x0000, 0x0000, 0x007a, 0x0000, 0x007c, 0x0000, 0x007e,
|
||||
// Entry 80 - BF
|
||||
0x0000, 0x0080, 0x0080, 0x0000, 0x0083, 0x0083, 0x0000, 0x0086,
|
||||
0x0087, 0x0087, 0x0087, 0x0086, 0x0088, 0x0087, 0x0087, 0x0087,
|
||||
0x0086, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0088,
|
||||
0x0087, 0x0087, 0x0087, 0x0087, 0x0088, 0x0087, 0x0088, 0x0087,
|
||||
0x0087, 0x0088, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087,
|
||||
0x0087, 0x0087, 0x0087, 0x0086, 0x0087, 0x0087, 0x0087, 0x0087,
|
||||
0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087,
|
||||
0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0086, 0x0087, 0x0086,
|
||||
// Entry C0 - FF
|
||||
0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087,
|
||||
0x0088, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087,
|
||||
0x0086, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0088, 0x0087,
|
||||
0x0087, 0x0088, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087,
|
||||
0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0086, 0x0086, 0x0087,
|
||||
0x0087, 0x0086, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0000,
|
||||
0x00ef, 0x0000, 0x00f1, 0x00f2, 0x00f2, 0x00f2, 0x00f2, 0x00f2,
|
||||
0x00f2, 0x00f2, 0x00f2, 0x00f2, 0x00f1, 0x00f2, 0x00f1, 0x00f1,
|
||||
// Entry 100 - 13F
|
||||
0x00f2, 0x00f2, 0x00f1, 0x00f2, 0x00f2, 0x00f2, 0x00f2, 0x00f1,
|
||||
0x00f2, 0x00f2, 0x00f2, 0x00f2, 0x00f2, 0x00f2, 0x0000, 0x010e,
|
||||
0x0000, 0x0110, 0x0000, 0x0112, 0x0000, 0x0114, 0x0114, 0x0000,
|
||||
0x0117, 0x0117, 0x0117, 0x0117, 0x0000, 0x011c, 0x0000, 0x011e,
|
||||
0x0000, 0x0120, 0x0120, 0x0000, 0x0123, 0x0123, 0x0123, 0x0123,
|
||||
0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123,
|
||||
0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123,
|
||||
0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123,
|
||||
// Entry 140 - 17F
|
||||
0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123,
|
||||
0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123,
|
||||
0x0123, 0x0123, 0x0000, 0x0152, 0x0000, 0x0154, 0x0000, 0x0156,
|
||||
0x0000, 0x0158, 0x0000, 0x015a, 0x0000, 0x015c, 0x015c, 0x015c,
|
||||
0x0000, 0x0160, 0x0000, 0x0000, 0x0163, 0x0000, 0x0165, 0x0000,
|
||||
0x0167, 0x0167, 0x0167, 0x0000, 0x016b, 0x0000, 0x016d, 0x0000,
|
||||
0x016f, 0x0000, 0x0171, 0x0171, 0x0000, 0x0174, 0x0000, 0x0176,
|
||||
0x0000, 0x0178, 0x0000, 0x017a, 0x0000, 0x017c, 0x0000, 0x017e,
|
||||
// Entry 180 - 1BF
|
||||
0x0000, 0x0000, 0x0000, 0x0182, 0x0000, 0x0184, 0x0184, 0x0184,
|
||||
0x0184, 0x0000, 0x0000, 0x0000, 0x018b, 0x0000, 0x0000, 0x018e,
|
||||
0x0000, 0x0000, 0x0191, 0x0000, 0x0000, 0x0000, 0x0195, 0x0000,
|
||||
0x0197, 0x0000, 0x0000, 0x019a, 0x0000, 0x0000, 0x019d, 0x0000,
|
||||
0x019f, 0x0000, 0x01a1, 0x0000, 0x01a3, 0x0000, 0x01a5, 0x0000,
|
||||
0x01a7, 0x0000, 0x01a9, 0x0000, 0x01ab, 0x0000, 0x01ad, 0x0000,
|
||||
0x01af, 0x0000, 0x01b1, 0x01b1, 0x0000, 0x01b4, 0x0000, 0x01b6,
|
||||
0x0000, 0x01b8, 0x0000, 0x01ba, 0x0000, 0x01bc, 0x0000, 0x0000,
|
||||
// Entry 1C0 - 1FF
|
||||
0x01bf, 0x0000, 0x01c1, 0x0000, 0x01c3, 0x0000, 0x01c5, 0x0000,
|
||||
0x01c7, 0x0000, 0x01c9, 0x0000, 0x01cb, 0x01cb, 0x01cb, 0x01cb,
|
||||
0x0000, 0x01d0, 0x0000, 0x01d2, 0x01d2, 0x0000, 0x01d5, 0x0000,
|
||||
0x01d7, 0x0000, 0x01d9, 0x0000, 0x01db, 0x0000, 0x01dd, 0x0000,
|
||||
0x01df, 0x01df, 0x0000, 0x01e2, 0x0000, 0x01e4, 0x0000, 0x01e6,
|
||||
0x0000, 0x01e8, 0x0000, 0x01ea, 0x0000, 0x01ec, 0x0000, 0x01ee,
|
||||
0x0000, 0x01f0, 0x0000, 0x0000, 0x01f3, 0x0000, 0x01f5, 0x01f5,
|
||||
0x01f5, 0x0000, 0x01f9, 0x0000, 0x01fb, 0x0000, 0x01fd, 0x0000,
|
||||
// Entry 200 - 23F
|
||||
0x01ff, 0x0000, 0x0000, 0x0202, 0x0000, 0x0204, 0x0204, 0x0000,
|
||||
0x0207, 0x0000, 0x0209, 0x0209, 0x0000, 0x020c, 0x020c, 0x0000,
|
||||
0x020f, 0x020f, 0x020f, 0x020f, 0x020f, 0x020f, 0x020f, 0x0000,
|
||||
0x0217, 0x0000, 0x0219, 0x0000, 0x021b, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0221, 0x0000, 0x0000, 0x0224, 0x0000, 0x0226,
|
||||
0x0226, 0x0000, 0x0229, 0x0000, 0x022b, 0x022b, 0x0000, 0x0000,
|
||||
0x022f, 0x022e, 0x022e, 0x0000, 0x0000, 0x0234, 0x0000, 0x0236,
|
||||
0x0000, 0x0238, 0x0000, 0x0244, 0x023a, 0x0244, 0x0244, 0x0244,
|
||||
// Entry 240 - 27F
|
||||
0x0244, 0x0244, 0x0244, 0x0244, 0x023a, 0x0244, 0x0244, 0x0000,
|
||||
0x0247, 0x0247, 0x0247, 0x0000, 0x024b, 0x0000, 0x024d, 0x0000,
|
||||
0x024f, 0x024f, 0x0000, 0x0252, 0x0000, 0x0254, 0x0254, 0x0254,
|
||||
0x0254, 0x0254, 0x0254, 0x0000, 0x025b, 0x0000, 0x025d, 0x0000,
|
||||
0x025f, 0x0000, 0x0261, 0x0000, 0x0263, 0x0000, 0x0265, 0x0000,
|
||||
0x0000, 0x0268, 0x0268, 0x0268, 0x0000, 0x026c, 0x0000, 0x026e,
|
||||
0x0000, 0x0270, 0x0000, 0x0000, 0x0000, 0x0274, 0x0273, 0x0273,
|
||||
0x0000, 0x0278, 0x0000, 0x027a, 0x0000, 0x027c, 0x0000, 0x0000,
|
||||
// Entry 280 - 2BF
|
||||
0x0000, 0x0000, 0x0281, 0x0000, 0x0000, 0x0284, 0x0000, 0x0286,
|
||||
0x0286, 0x0286, 0x0286, 0x0000, 0x028b, 0x028b, 0x028b, 0x0000,
|
||||
0x028f, 0x028f, 0x028f, 0x028f, 0x028f, 0x0000, 0x0295, 0x0295,
|
||||
0x0295, 0x0295, 0x0000, 0x0000, 0x0000, 0x0000, 0x029d, 0x029d,
|
||||
0x029d, 0x0000, 0x02a1, 0x02a1, 0x02a1, 0x02a1, 0x0000, 0x0000,
|
||||
0x02a7, 0x02a7, 0x02a7, 0x02a7, 0x0000, 0x02ac, 0x0000, 0x02ae,
|
||||
0x02ae, 0x0000, 0x02b1, 0x0000, 0x02b3, 0x0000, 0x02b5, 0x02b5,
|
||||
0x0000, 0x0000, 0x02b9, 0x0000, 0x0000, 0x0000, 0x02bd, 0x0000,
|
||||
// Entry 2C0 - 2FF
|
||||
0x02bf, 0x02bf, 0x0000, 0x0000, 0x02c3, 0x0000, 0x02c5, 0x0000,
|
||||
0x02c7, 0x0000, 0x02c9, 0x0000, 0x02cb, 0x0000, 0x02cd, 0x02cd,
|
||||
0x0000, 0x0000, 0x02d1, 0x0000, 0x02d3, 0x02d0, 0x02d0, 0x0000,
|
||||
0x0000, 0x02d8, 0x02d7, 0x02d7, 0x0000, 0x0000, 0x02dd, 0x0000,
|
||||
0x02df, 0x0000, 0x02e1, 0x0000, 0x0000, 0x02e4, 0x0000, 0x02e6,
|
||||
0x0000, 0x0000, 0x02e9, 0x0000, 0x02eb, 0x0000, 0x02ed, 0x0000,
|
||||
0x02ef, 0x02ef, 0x0000, 0x0000, 0x02f3, 0x02f2, 0x02f2, 0x0000,
|
||||
0x02f7, 0x0000, 0x02f9, 0x02f9, 0x02f9, 0x02f9, 0x02f9, 0x0000,
|
||||
// Entry 300 - 33F
|
||||
0x02ff, 0x0300, 0x02ff, 0x0000, 0x0303, 0x0051, 0x00e6,
|
||||
} // Size: 1574 bytes
|
||||
|
||||
// Total table size 1574 bytes (1KiB); checksum: 895AAF0B
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,91 @@
|
|||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package compact
|
||||
|
||||
var (
|
||||
und = Tag{}
|
||||
|
||||
Und Tag = Tag{}
|
||||
|
||||
Afrikaans Tag = Tag{language: afIndex, locale: afIndex}
|
||||
Amharic Tag = Tag{language: amIndex, locale: amIndex}
|
||||
Arabic Tag = Tag{language: arIndex, locale: arIndex}
|
||||
ModernStandardArabic Tag = Tag{language: ar001Index, locale: ar001Index}
|
||||
Azerbaijani Tag = Tag{language: azIndex, locale: azIndex}
|
||||
Bulgarian Tag = Tag{language: bgIndex, locale: bgIndex}
|
||||
Bengali Tag = Tag{language: bnIndex, locale: bnIndex}
|
||||
Catalan Tag = Tag{language: caIndex, locale: caIndex}
|
||||
Czech Tag = Tag{language: csIndex, locale: csIndex}
|
||||
Danish Tag = Tag{language: daIndex, locale: daIndex}
|
||||
German Tag = Tag{language: deIndex, locale: deIndex}
|
||||
Greek Tag = Tag{language: elIndex, locale: elIndex}
|
||||
English Tag = Tag{language: enIndex, locale: enIndex}
|
||||
AmericanEnglish Tag = Tag{language: enUSIndex, locale: enUSIndex}
|
||||
BritishEnglish Tag = Tag{language: enGBIndex, locale: enGBIndex}
|
||||
Spanish Tag = Tag{language: esIndex, locale: esIndex}
|
||||
EuropeanSpanish Tag = Tag{language: esESIndex, locale: esESIndex}
|
||||
LatinAmericanSpanish Tag = Tag{language: es419Index, locale: es419Index}
|
||||
Estonian Tag = Tag{language: etIndex, locale: etIndex}
|
||||
Persian Tag = Tag{language: faIndex, locale: faIndex}
|
||||
Finnish Tag = Tag{language: fiIndex, locale: fiIndex}
|
||||
Filipino Tag = Tag{language: filIndex, locale: filIndex}
|
||||
French Tag = Tag{language: frIndex, locale: frIndex}
|
||||
CanadianFrench Tag = Tag{language: frCAIndex, locale: frCAIndex}
|
||||
Gujarati Tag = Tag{language: guIndex, locale: guIndex}
|
||||
Hebrew Tag = Tag{language: heIndex, locale: heIndex}
|
||||
Hindi Tag = Tag{language: hiIndex, locale: hiIndex}
|
||||
Croatian Tag = Tag{language: hrIndex, locale: hrIndex}
|
||||
Hungarian Tag = Tag{language: huIndex, locale: huIndex}
|
||||
Armenian Tag = Tag{language: hyIndex, locale: hyIndex}
|
||||
Indonesian Tag = Tag{language: idIndex, locale: idIndex}
|
||||
Icelandic Tag = Tag{language: isIndex, locale: isIndex}
|
||||
Italian Tag = Tag{language: itIndex, locale: itIndex}
|
||||
Japanese Tag = Tag{language: jaIndex, locale: jaIndex}
|
||||
Georgian Tag = Tag{language: kaIndex, locale: kaIndex}
|
||||
Kazakh Tag = Tag{language: kkIndex, locale: kkIndex}
|
||||
Khmer Tag = Tag{language: kmIndex, locale: kmIndex}
|
||||
Kannada Tag = Tag{language: knIndex, locale: knIndex}
|
||||
Korean Tag = Tag{language: koIndex, locale: koIndex}
|
||||
Kirghiz Tag = Tag{language: kyIndex, locale: kyIndex}
|
||||
Lao Tag = Tag{language: loIndex, locale: loIndex}
|
||||
Lithuanian Tag = Tag{language: ltIndex, locale: ltIndex}
|
||||
Latvian Tag = Tag{language: lvIndex, locale: lvIndex}
|
||||
Macedonian Tag = Tag{language: mkIndex, locale: mkIndex}
|
||||
Malayalam Tag = Tag{language: mlIndex, locale: mlIndex}
|
||||
Mongolian Tag = Tag{language: mnIndex, locale: mnIndex}
|
||||
Marathi Tag = Tag{language: mrIndex, locale: mrIndex}
|
||||
Malay Tag = Tag{language: msIndex, locale: msIndex}
|
||||
Burmese Tag = Tag{language: myIndex, locale: myIndex}
|
||||
Nepali Tag = Tag{language: neIndex, locale: neIndex}
|
||||
Dutch Tag = Tag{language: nlIndex, locale: nlIndex}
|
||||
Norwegian Tag = Tag{language: noIndex, locale: noIndex}
|
||||
Punjabi Tag = Tag{language: paIndex, locale: paIndex}
|
||||
Polish Tag = Tag{language: plIndex, locale: plIndex}
|
||||
Portuguese Tag = Tag{language: ptIndex, locale: ptIndex}
|
||||
BrazilianPortuguese Tag = Tag{language: ptBRIndex, locale: ptBRIndex}
|
||||
EuropeanPortuguese Tag = Tag{language: ptPTIndex, locale: ptPTIndex}
|
||||
Romanian Tag = Tag{language: roIndex, locale: roIndex}
|
||||
Russian Tag = Tag{language: ruIndex, locale: ruIndex}
|
||||
Sinhala Tag = Tag{language: siIndex, locale: siIndex}
|
||||
Slovak Tag = Tag{language: skIndex, locale: skIndex}
|
||||
Slovenian Tag = Tag{language: slIndex, locale: slIndex}
|
||||
Albanian Tag = Tag{language: sqIndex, locale: sqIndex}
|
||||
Serbian Tag = Tag{language: srIndex, locale: srIndex}
|
||||
SerbianLatin Tag = Tag{language: srLatnIndex, locale: srLatnIndex}
|
||||
Swedish Tag = Tag{language: svIndex, locale: svIndex}
|
||||
Swahili Tag = Tag{language: swIndex, locale: swIndex}
|
||||
Tamil Tag = Tag{language: taIndex, locale: taIndex}
|
||||
Telugu Tag = Tag{language: teIndex, locale: teIndex}
|
||||
Thai Tag = Tag{language: thIndex, locale: thIndex}
|
||||
Turkish Tag = Tag{language: trIndex, locale: trIndex}
|
||||
Ukrainian Tag = Tag{language: ukIndex, locale: ukIndex}
|
||||
Urdu Tag = Tag{language: urIndex, locale: urIndex}
|
||||
Uzbek Tag = Tag{language: uzIndex, locale: uzIndex}
|
||||
Vietnamese Tag = Tag{language: viIndex, locale: viIndex}
|
||||
Chinese Tag = Tag{language: zhIndex, locale: zhIndex}
|
||||
SimplifiedChinese Tag = Tag{language: zhHansIndex, locale: zhHansIndex}
|
||||
TraditionalChinese Tag = Tag{language: zhHantIndex, locale: zhHantIndex}
|
||||
Zulu Tag = Tag{language: zuIndex, locale: zuIndex}
|
||||
)
|
|
@ -0,0 +1,167 @@
|
|||
// 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
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// A Builder allows constructing a Tag from individual components.
|
||||
// Its main user is Compose in the top-level language package.
|
||||
type Builder struct {
|
||||
Tag Tag
|
||||
|
||||
private string // the x extension
|
||||
variants []string
|
||||
extensions []string
|
||||
}
|
||||
|
||||
// Make returns a new Tag from the current settings.
|
||||
func (b *Builder) Make() Tag {
|
||||
t := b.Tag
|
||||
|
||||
if len(b.extensions) > 0 || len(b.variants) > 0 {
|
||||
sort.Sort(sortVariants(b.variants))
|
||||
sort.Strings(b.extensions)
|
||||
|
||||
if b.private != "" {
|
||||
b.extensions = append(b.extensions, b.private)
|
||||
}
|
||||
n := maxCoreSize + tokenLen(b.variants...) + tokenLen(b.extensions...)
|
||||
buf := make([]byte, n)
|
||||
p := t.genCoreBytes(buf)
|
||||
t.pVariant = byte(p)
|
||||
p += appendTokens(buf[p:], b.variants...)
|
||||
t.pExt = uint16(p)
|
||||
p += appendTokens(buf[p:], b.extensions...)
|
||||
t.str = string(buf[:p])
|
||||
// We may not always need to remake the string, but when or when not
|
||||
// to do so is rather tricky.
|
||||
scan := makeScanner(buf[:p])
|
||||
t, _ = parse(&scan, "")
|
||||
return t
|
||||
|
||||
} else if b.private != "" {
|
||||
t.str = b.private
|
||||
t.RemakeString()
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// SetTag copies all the settings from a given Tag. Any previously set values
|
||||
// are discarded.
|
||||
func (b *Builder) SetTag(t Tag) {
|
||||
b.Tag.LangID = t.LangID
|
||||
b.Tag.RegionID = t.RegionID
|
||||
b.Tag.ScriptID = t.ScriptID
|
||||
// TODO: optimize
|
||||
b.variants = b.variants[:0]
|
||||
if variants := t.Variants(); variants != "" {
|
||||
for _, vr := range strings.Split(variants[1:], "-") {
|
||||
b.variants = append(b.variants, vr)
|
||||
}
|
||||
}
|
||||
b.extensions, b.private = b.extensions[:0], ""
|
||||
for _, e := range t.Extensions() {
|
||||
b.AddExt(e)
|
||||
}
|
||||
}
|
||||
|
||||
// AddExt adds extension e to the tag. e must be a valid extension as returned
|
||||
// by Tag.Extension. If the extension already exists, it will be discarded,
|
||||
// except for a -u extension, where non-existing key-type pairs will added.
|
||||
func (b *Builder) AddExt(e string) {
|
||||
if e[0] == 'x' {
|
||||
if b.private == "" {
|
||||
b.private = e
|
||||
}
|
||||
return
|
||||
}
|
||||
for i, s := range b.extensions {
|
||||
if s[0] == e[0] {
|
||||
if e[0] == 'u' {
|
||||
b.extensions[i] += e[1:]
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
b.extensions = append(b.extensions, e)
|
||||
}
|
||||
|
||||
// SetExt sets the extension e to the tag. e must be a valid extension as
|
||||
// returned by Tag.Extension. If the extension already exists, it will be
|
||||
// overwritten, except for a -u extension, where the individual key-type pairs
|
||||
// will be set.
|
||||
func (b *Builder) SetExt(e string) {
|
||||
if e[0] == 'x' {
|
||||
b.private = e
|
||||
return
|
||||
}
|
||||
for i, s := range b.extensions {
|
||||
if s[0] == e[0] {
|
||||
if e[0] == 'u' {
|
||||
b.extensions[i] = e + s[1:]
|
||||
} else {
|
||||
b.extensions[i] = e
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
b.extensions = append(b.extensions, e)
|
||||
}
|
||||
|
||||
// AddVariant adds any number of variants.
|
||||
func (b *Builder) AddVariant(v ...string) {
|
||||
for _, v := range v {
|
||||
if v != "" {
|
||||
b.variants = append(b.variants, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ClearVariants removes any variants previously added, including those
|
||||
// copied from a Tag in SetTag.
|
||||
func (b *Builder) ClearVariants() {
|
||||
b.variants = b.variants[:0]
|
||||
}
|
||||
|
||||
// ClearExtensions removes any extensions previously added, including those
|
||||
// copied from a Tag in SetTag.
|
||||
func (b *Builder) ClearExtensions() {
|
||||
b.private = ""
|
||||
b.extensions = b.extensions[:0]
|
||||
}
|
||||
|
||||
func tokenLen(token ...string) (n int) {
|
||||
for _, t := range token {
|
||||
n += len(t) + 1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func appendTokens(b []byte, token ...string) int {
|
||||
p := 0
|
||||
for _, t := range token {
|
||||
b[p] = '-'
|
||||
copy(b[p+1:], t)
|
||||
p += 1 + len(t)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
type sortVariants []string
|
||||
|
||||
func (s sortVariants) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func (s sortVariants) Swap(i, j int) {
|
||||
s[j], s[i] = s[i], s[j]
|
||||
}
|
||||
|
||||
func (s sortVariants) Less(i, j int) bool {
|
||||
return variantIndex[s[i]] < variantIndex[s[j]]
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright 2014 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
|
||||
|
||||
// BaseLanguages returns the list of all supported base languages. It generates
|
||||
// the list by traversing the internal structures.
|
||||
func BaseLanguages() []Language {
|
||||
base := make([]Language, 0, NumLanguages)
|
||||
for i := 0; i < langNoIndexOffset; i++ {
|
||||
// We included "und" already for the value 0.
|
||||
if i != nonCanonicalUnd {
|
||||
base = append(base, Language(i))
|
||||
}
|
||||
}
|
||||
i := langNoIndexOffset
|
||||
for _, v := range langNoIndex {
|
||||
for k := 0; k < 8; k++ {
|
||||
if v&1 == 1 {
|
||||
base = append(base, Language(i))
|
||||
}
|
||||
v >>= 1
|
||||
i++
|
||||
}
|
||||
}
|
||||
return base
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue