forked from mirrors/statsd_exporter
commit
0151d93b46
751 changed files with 31 additions and 264620 deletions
|
@ -2,7 +2,7 @@
|
||||||
version: 2.1
|
version: 2.1
|
||||||
|
|
||||||
orbs:
|
orbs:
|
||||||
prometheus: prometheus/prometheus@0.5.0
|
prometheus: prometheus/prometheus@0.10.0
|
||||||
|
|
||||||
executors:
|
executors:
|
||||||
# Whenever the Go version is updated here, .promu.yml should also be updated.
|
# Whenever the Go version is updated here, .promu.yml should also be updated.
|
||||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -5,3 +5,4 @@ dependencies-stamp
|
||||||
/.release
|
/.release
|
||||||
/.tarballs
|
/.tarballs
|
||||||
*~
|
*~
|
||||||
|
/vendor
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
run:
|
|
||||||
modules-download-mode: vendor
|
|
||||||
|
|
||||||
# Run only staticcheck for now. Additional linters will be enabled one-by-one.
|
# Run only staticcheck for now. Additional linters will be enabled one-by-one.
|
||||||
linters:
|
linters:
|
||||||
enable:
|
enable:
|
||||||
|
|
|
@ -5,7 +5,7 @@ go:
|
||||||
repository:
|
repository:
|
||||||
path: github.com/prometheus/statsd_exporter
|
path: github.com/prometheus/statsd_exporter
|
||||||
build:
|
build:
|
||||||
flags: -mod=vendor -a -tags 'netgo static_build'
|
flags: -a -tags 'netgo static_build'
|
||||||
ldflags: |
|
ldflags: |
|
||||||
-X github.com/prometheus/common/version.Version={{.Version}}
|
-X github.com/prometheus/common/version.Version={{.Version}}
|
||||||
-X github.com/prometheus/common/version.Revision={{.Revision}}
|
-X github.com/prometheus/common/version.Revision={{.Revision}}
|
||||||
|
|
12
go.mod
12
go.mod
|
@ -1,19 +1,13 @@
|
||||||
module github.com/prometheus/statsd_exporter
|
module github.com/prometheus/statsd_exporter
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect
|
|
||||||
github.com/go-kit/kit v0.10.0
|
github.com/go-kit/kit v0.10.0
|
||||||
github.com/golang/protobuf v1.4.2 // indirect
|
|
||||||
github.com/hashicorp/golang-lru v0.5.4
|
github.com/hashicorp/golang-lru v0.5.4
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/prometheus/client_golang v1.9.0
|
||||||
github.com/prometheus/client_golang v1.6.0
|
|
||||||
github.com/prometheus/client_model v0.2.0
|
github.com/prometheus/client_model v0.2.0
|
||||||
github.com/prometheus/common v0.10.0
|
github.com/prometheus/common v0.19.0
|
||||||
github.com/sirupsen/logrus v1.6.0 // indirect
|
|
||||||
golang.org/x/sys v0.0.0-20200523222454-059865788121 // indirect
|
|
||||||
google.golang.org/protobuf v1.24.0 // indirect
|
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6
|
||||||
gopkg.in/yaml.v2 v2.3.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
)
|
)
|
||||||
|
|
||||||
go 1.13
|
go 1.13
|
||||||
|
|
44
go.sum
44
go.sum
|
@ -85,9 +85,9 @@ github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:x
|
||||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
|
||||||
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
|
|
||||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
|
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
|
||||||
|
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
|
@ -135,12 +135,14 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt
|
||||||
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
|
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
|
||||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||||
|
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
|
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
|
@ -174,6 +176,7 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
|
||||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
|
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
|
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
|
||||||
github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
|
github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
|
||||||
github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
|
github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
|
||||||
|
@ -214,8 +217,9 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP
|
||||||
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
||||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||||
github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
|
github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
|
||||||
github.com/prometheus/client_golang v1.6.0 h1:YVPodQOcK15POxhgARIvnDRVpLcuK8mglnMrWfyrw6A=
|
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||||
github.com/prometheus/client_golang v1.6.0/go.mod h1:ZLOG9ck3JLRdB5MgO8f+lLTe83AXG6ro35rLTxvnIl4=
|
github.com/prometheus/client_golang v1.9.0 h1:Rrch9mh17XcxvEu9D9DEpb4isxjGBtcevQjKvxPRQIU=
|
||||||
|
github.com/prometheus/client_golang v1.9.0/go.mod h1:FqZLKOZnGdFAhOK4nqGHa7D66IdsO+O441Eve7ptJDU=
|
||||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
@ -226,15 +230,17 @@ github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6T
|
||||||
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
|
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
|
||||||
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
|
|
||||||
github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc=
|
|
||||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||||
|
github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
|
||||||
|
github.com/prometheus/common v0.19.0 h1:Itb4+NjG9wRdkAWgVucbM/adyIXxEhbw0866e0uZE6A=
|
||||||
|
github.com/prometheus/common v0.19.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
|
||||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
||||||
github.com/prometheus/procfs v0.0.11 h1:DhHlBtkHWPYi8O2y31JkK0TF+DGM+51OopZjH/Ia5qI=
|
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||||
github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
github.com/prometheus/procfs v0.2.0 h1:wH4vA7pcjKuZzjF7lM8awk4fnuJO6idemZXoKnULUx4=
|
||||||
|
github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
|
@ -284,6 +290,7 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
|
@ -308,6 +315,7 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR
|
||||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
@ -332,9 +340,11 @@ golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200523222454-059865788121 h1:rITEj+UZHYC927n8GT97eC3zrpzXdb/voyeOuVKS46o=
|
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e h1:AyodaIpKjppX+cBfTASF2E1US3H2JFBj920Ot3rtDjs=
|
||||||
|
golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
@ -365,7 +375,6 @@ google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRn
|
||||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
|
google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
|
||||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
|
||||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
|
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
|
||||||
|
@ -375,17 +384,13 @@ google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac
|
||||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
|
||||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
|
||||||
google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA=
|
|
||||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
@ -404,8 +409,9 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
|
||||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
|
27
vendor/github.com/alecthomas/template/LICENSE
generated
vendored
27
vendor/github.com/alecthomas/template/LICENSE
generated
vendored
|
@ -1,27 +0,0 @@
|
||||||
Copyright (c) 2012 The Go Authors. All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are
|
|
||||||
met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above
|
|
||||||
copyright notice, this list of conditions and the following disclaimer
|
|
||||||
in the documentation and/or other materials provided with the
|
|
||||||
distribution.
|
|
||||||
* Neither the name of Google Inc. nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived from
|
|
||||||
this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
25
vendor/github.com/alecthomas/template/README.md
generated
vendored
25
vendor/github.com/alecthomas/template/README.md
generated
vendored
|
@ -1,25 +0,0 @@
|
||||||
# Go's `text/template` package with newline elision
|
|
||||||
|
|
||||||
This is a fork of Go 1.4's [text/template](http://golang.org/pkg/text/template/) package with one addition: a backslash immediately after a closing delimiter will delete all subsequent newlines until a non-newline.
|
|
||||||
|
|
||||||
eg.
|
|
||||||
|
|
||||||
```
|
|
||||||
{{if true}}\
|
|
||||||
hello
|
|
||||||
{{end}}\
|
|
||||||
```
|
|
||||||
|
|
||||||
Will result in:
|
|
||||||
|
|
||||||
```
|
|
||||||
hello\n
|
|
||||||
```
|
|
||||||
|
|
||||||
Rather than:
|
|
||||||
|
|
||||||
```
|
|
||||||
\n
|
|
||||||
hello\n
|
|
||||||
\n
|
|
||||||
```
|
|
406
vendor/github.com/alecthomas/template/doc.go
generated
vendored
406
vendor/github.com/alecthomas/template/doc.go
generated
vendored
|
@ -1,406 +0,0 @@
|
||||||
// Copyright 2011 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
/*
|
|
||||||
Package template implements data-driven templates for generating textual output.
|
|
||||||
|
|
||||||
To generate HTML output, see package html/template, which has the same interface
|
|
||||||
as this package but automatically secures HTML output against certain attacks.
|
|
||||||
|
|
||||||
Templates are executed by applying them to a data structure. Annotations in the
|
|
||||||
template refer to elements of the data structure (typically a field of a struct
|
|
||||||
or a key in a map) to control execution and derive values to be displayed.
|
|
||||||
Execution of the template walks the structure and sets the cursor, represented
|
|
||||||
by a period '.' and called "dot", to the value at the current location in the
|
|
||||||
structure as execution proceeds.
|
|
||||||
|
|
||||||
The input text for a template is UTF-8-encoded text in any format.
|
|
||||||
"Actions"--data evaluations or control structures--are delimited by
|
|
||||||
"{{" and "}}"; all text outside actions is copied to the output unchanged.
|
|
||||||
Actions may not span newlines, although comments can.
|
|
||||||
|
|
||||||
Once parsed, a template may be executed safely in parallel.
|
|
||||||
|
|
||||||
Here is a trivial example that prints "17 items are made of wool".
|
|
||||||
|
|
||||||
type Inventory struct {
|
|
||||||
Material string
|
|
||||||
Count uint
|
|
||||||
}
|
|
||||||
sweaters := Inventory{"wool", 17}
|
|
||||||
tmpl, err := template.New("test").Parse("{{.Count}} items are made of {{.Material}}")
|
|
||||||
if err != nil { panic(err) }
|
|
||||||
err = tmpl.Execute(os.Stdout, sweaters)
|
|
||||||
if err != nil { panic(err) }
|
|
||||||
|
|
||||||
More intricate examples appear below.
|
|
||||||
|
|
||||||
Actions
|
|
||||||
|
|
||||||
Here is the list of actions. "Arguments" and "pipelines" are evaluations of
|
|
||||||
data, defined in detail below.
|
|
||||||
|
|
||||||
*/
|
|
||||||
// {{/* a comment */}}
|
|
||||||
// A comment; discarded. May contain newlines.
|
|
||||||
// Comments do not nest and must start and end at the
|
|
||||||
// delimiters, as shown here.
|
|
||||||
/*
|
|
||||||
|
|
||||||
{{pipeline}}
|
|
||||||
The default textual representation of the value of the pipeline
|
|
||||||
is copied to the output.
|
|
||||||
|
|
||||||
{{if pipeline}} T1 {{end}}
|
|
||||||
If the value of the pipeline is empty, no output is generated;
|
|
||||||
otherwise, T1 is executed. The empty values are false, 0, any
|
|
||||||
nil pointer or interface value, and any array, slice, map, or
|
|
||||||
string of length zero.
|
|
||||||
Dot is unaffected.
|
|
||||||
|
|
||||||
{{if pipeline}} T1 {{else}} T0 {{end}}
|
|
||||||
If the value of the pipeline is empty, T0 is executed;
|
|
||||||
otherwise, T1 is executed. Dot is unaffected.
|
|
||||||
|
|
||||||
{{if pipeline}} T1 {{else if pipeline}} T0 {{end}}
|
|
||||||
To simplify the appearance of if-else chains, the else action
|
|
||||||
of an if may include another if directly; the effect is exactly
|
|
||||||
the same as writing
|
|
||||||
{{if pipeline}} T1 {{else}}{{if pipeline}} T0 {{end}}{{end}}
|
|
||||||
|
|
||||||
{{range pipeline}} T1 {{end}}
|
|
||||||
The value of the pipeline must be an array, slice, map, or channel.
|
|
||||||
If the value of the pipeline has length zero, nothing is output;
|
|
||||||
otherwise, dot is set to the successive elements of the array,
|
|
||||||
slice, or map and T1 is executed. If the value is a map and the
|
|
||||||
keys are of basic type with a defined order ("comparable"), the
|
|
||||||
elements will be visited in sorted key order.
|
|
||||||
|
|
||||||
{{range pipeline}} T1 {{else}} T0 {{end}}
|
|
||||||
The value of the pipeline must be an array, slice, map, or channel.
|
|
||||||
If the value of the pipeline has length zero, dot is unaffected and
|
|
||||||
T0 is executed; otherwise, dot is set to the successive elements
|
|
||||||
of the array, slice, or map and T1 is executed.
|
|
||||||
|
|
||||||
{{template "name"}}
|
|
||||||
The template with the specified name is executed with nil data.
|
|
||||||
|
|
||||||
{{template "name" pipeline}}
|
|
||||||
The template with the specified name is executed with dot set
|
|
||||||
to the value of the pipeline.
|
|
||||||
|
|
||||||
{{with pipeline}} T1 {{end}}
|
|
||||||
If the value of the pipeline is empty, no output is generated;
|
|
||||||
otherwise, dot is set to the value of the pipeline and T1 is
|
|
||||||
executed.
|
|
||||||
|
|
||||||
{{with pipeline}} T1 {{else}} T0 {{end}}
|
|
||||||
If the value of the pipeline is empty, dot is unaffected and T0
|
|
||||||
is executed; otherwise, dot is set to the value of the pipeline
|
|
||||||
and T1 is executed.
|
|
||||||
|
|
||||||
Arguments
|
|
||||||
|
|
||||||
An argument is a simple value, denoted by one of the following.
|
|
||||||
|
|
||||||
- A boolean, string, character, integer, floating-point, imaginary
|
|
||||||
or complex constant in Go syntax. These behave like Go's untyped
|
|
||||||
constants, although raw strings may not span newlines.
|
|
||||||
- The keyword nil, representing an untyped Go nil.
|
|
||||||
- The character '.' (period):
|
|
||||||
.
|
|
||||||
The result is the value of dot.
|
|
||||||
- A variable name, which is a (possibly empty) alphanumeric string
|
|
||||||
preceded by a dollar sign, such as
|
|
||||||
$piOver2
|
|
||||||
or
|
|
||||||
$
|
|
||||||
The result is the value of the variable.
|
|
||||||
Variables are described below.
|
|
||||||
- The name of a field of the data, which must be a struct, preceded
|
|
||||||
by a period, such as
|
|
||||||
.Field
|
|
||||||
The result is the value of the field. Field invocations may be
|
|
||||||
chained:
|
|
||||||
.Field1.Field2
|
|
||||||
Fields can also be evaluated on variables, including chaining:
|
|
||||||
$x.Field1.Field2
|
|
||||||
- The name of a key of the data, which must be a map, preceded
|
|
||||||
by a period, such as
|
|
||||||
.Key
|
|
||||||
The result is the map element value indexed by the key.
|
|
||||||
Key invocations may be chained and combined with fields to any
|
|
||||||
depth:
|
|
||||||
.Field1.Key1.Field2.Key2
|
|
||||||
Although the key must be an alphanumeric identifier, unlike with
|
|
||||||
field names they do not need to start with an upper case letter.
|
|
||||||
Keys can also be evaluated on variables, including chaining:
|
|
||||||
$x.key1.key2
|
|
||||||
- The name of a niladic method of the data, preceded by a period,
|
|
||||||
such as
|
|
||||||
.Method
|
|
||||||
The result is the value of invoking the method with dot as the
|
|
||||||
receiver, dot.Method(). Such a method must have one return value (of
|
|
||||||
any type) or two return values, the second of which is an error.
|
|
||||||
If it has two and the returned error is non-nil, execution terminates
|
|
||||||
and an error is returned to the caller as the value of Execute.
|
|
||||||
Method invocations may be chained and combined with fields and keys
|
|
||||||
to any depth:
|
|
||||||
.Field1.Key1.Method1.Field2.Key2.Method2
|
|
||||||
Methods can also be evaluated on variables, including chaining:
|
|
||||||
$x.Method1.Field
|
|
||||||
- The name of a niladic function, such as
|
|
||||||
fun
|
|
||||||
The result is the value of invoking the function, fun(). The return
|
|
||||||
types and values behave as in methods. Functions and function
|
|
||||||
names are described below.
|
|
||||||
- A parenthesized instance of one the above, for grouping. The result
|
|
||||||
may be accessed by a field or map key invocation.
|
|
||||||
print (.F1 arg1) (.F2 arg2)
|
|
||||||
(.StructValuedMethod "arg").Field
|
|
||||||
|
|
||||||
Arguments may evaluate to any type; if they are pointers the implementation
|
|
||||||
automatically indirects to the base type when required.
|
|
||||||
If an evaluation yields a function value, such as a function-valued
|
|
||||||
field of a struct, the function is not invoked automatically, but it
|
|
||||||
can be used as a truth value for an if action and the like. To invoke
|
|
||||||
it, use the call function, defined below.
|
|
||||||
|
|
||||||
A pipeline is a possibly chained sequence of "commands". A command is a simple
|
|
||||||
value (argument) or a function or method call, possibly with multiple arguments:
|
|
||||||
|
|
||||||
Argument
|
|
||||||
The result is the value of evaluating the argument.
|
|
||||||
.Method [Argument...]
|
|
||||||
The method can be alone or the last element of a chain but,
|
|
||||||
unlike methods in the middle of a chain, it can take arguments.
|
|
||||||
The result is the value of calling the method with the
|
|
||||||
arguments:
|
|
||||||
dot.Method(Argument1, etc.)
|
|
||||||
functionName [Argument...]
|
|
||||||
The result is the value of calling the function associated
|
|
||||||
with the name:
|
|
||||||
function(Argument1, etc.)
|
|
||||||
Functions and function names are described below.
|
|
||||||
|
|
||||||
Pipelines
|
|
||||||
|
|
||||||
A pipeline may be "chained" by separating a sequence of commands with pipeline
|
|
||||||
characters '|'. In a chained pipeline, the result of the each command is
|
|
||||||
passed as the last argument of the following command. The output of the final
|
|
||||||
command in the pipeline is the value of the pipeline.
|
|
||||||
|
|
||||||
The output of a command will be either one value or two values, the second of
|
|
||||||
which has type error. If that second value is present and evaluates to
|
|
||||||
non-nil, execution terminates and the error is returned to the caller of
|
|
||||||
Execute.
|
|
||||||
|
|
||||||
Variables
|
|
||||||
|
|
||||||
A pipeline inside an action may initialize a variable to capture the result.
|
|
||||||
The initialization has syntax
|
|
||||||
|
|
||||||
$variable := pipeline
|
|
||||||
|
|
||||||
where $variable is the name of the variable. An action that declares a
|
|
||||||
variable produces no output.
|
|
||||||
|
|
||||||
If a "range" action initializes a variable, the variable is set to the
|
|
||||||
successive elements of the iteration. Also, a "range" may declare two
|
|
||||||
variables, separated by a comma:
|
|
||||||
|
|
||||||
range $index, $element := pipeline
|
|
||||||
|
|
||||||
in which case $index and $element are set to the successive values of the
|
|
||||||
array/slice index or map key and element, respectively. Note that if there is
|
|
||||||
only one variable, it is assigned the element; this is opposite to the
|
|
||||||
convention in Go range clauses.
|
|
||||||
|
|
||||||
A variable's scope extends to the "end" action of the control structure ("if",
|
|
||||||
"with", or "range") in which it is declared, or to the end of the template if
|
|
||||||
there is no such control structure. A template invocation does not inherit
|
|
||||||
variables from the point of its invocation.
|
|
||||||
|
|
||||||
When execution begins, $ is set to the data argument passed to Execute, that is,
|
|
||||||
to the starting value of dot.
|
|
||||||
|
|
||||||
Examples
|
|
||||||
|
|
||||||
Here are some example one-line templates demonstrating pipelines and variables.
|
|
||||||
All produce the quoted word "output":
|
|
||||||
|
|
||||||
{{"\"output\""}}
|
|
||||||
A string constant.
|
|
||||||
{{`"output"`}}
|
|
||||||
A raw string constant.
|
|
||||||
{{printf "%q" "output"}}
|
|
||||||
A function call.
|
|
||||||
{{"output" | printf "%q"}}
|
|
||||||
A function call whose final argument comes from the previous
|
|
||||||
command.
|
|
||||||
{{printf "%q" (print "out" "put")}}
|
|
||||||
A parenthesized argument.
|
|
||||||
{{"put" | printf "%s%s" "out" | printf "%q"}}
|
|
||||||
A more elaborate call.
|
|
||||||
{{"output" | printf "%s" | printf "%q"}}
|
|
||||||
A longer chain.
|
|
||||||
{{with "output"}}{{printf "%q" .}}{{end}}
|
|
||||||
A with action using dot.
|
|
||||||
{{with $x := "output" | printf "%q"}}{{$x}}{{end}}
|
|
||||||
A with action that creates and uses a variable.
|
|
||||||
{{with $x := "output"}}{{printf "%q" $x}}{{end}}
|
|
||||||
A with action that uses the variable in another action.
|
|
||||||
{{with $x := "output"}}{{$x | printf "%q"}}{{end}}
|
|
||||||
The same, but pipelined.
|
|
||||||
|
|
||||||
Functions
|
|
||||||
|
|
||||||
During execution functions are found in two function maps: first in the
|
|
||||||
template, then in the global function map. By default, no functions are defined
|
|
||||||
in the template but the Funcs method can be used to add them.
|
|
||||||
|
|
||||||
Predefined global functions are named as follows.
|
|
||||||
|
|
||||||
and
|
|
||||||
Returns the boolean AND of its arguments by returning the
|
|
||||||
first empty argument or the last argument, that is,
|
|
||||||
"and x y" behaves as "if x then y else x". All the
|
|
||||||
arguments are evaluated.
|
|
||||||
call
|
|
||||||
Returns the result of calling the first argument, which
|
|
||||||
must be a function, with the remaining arguments as parameters.
|
|
||||||
Thus "call .X.Y 1 2" is, in Go notation, dot.X.Y(1, 2) where
|
|
||||||
Y is a func-valued field, map entry, or the like.
|
|
||||||
The first argument must be the result of an evaluation
|
|
||||||
that yields a value of function type (as distinct from
|
|
||||||
a predefined function such as print). The function must
|
|
||||||
return either one or two result values, the second of which
|
|
||||||
is of type error. If the arguments don't match the function
|
|
||||||
or the returned error value is non-nil, execution stops.
|
|
||||||
html
|
|
||||||
Returns the escaped HTML equivalent of the textual
|
|
||||||
representation of its arguments.
|
|
||||||
index
|
|
||||||
Returns the result of indexing its first argument by the
|
|
||||||
following arguments. Thus "index x 1 2 3" is, in Go syntax,
|
|
||||||
x[1][2][3]. Each indexed item must be a map, slice, or array.
|
|
||||||
js
|
|
||||||
Returns the escaped JavaScript equivalent of the textual
|
|
||||||
representation of its arguments.
|
|
||||||
len
|
|
||||||
Returns the integer length of its argument.
|
|
||||||
not
|
|
||||||
Returns the boolean negation of its single argument.
|
|
||||||
or
|
|
||||||
Returns the boolean OR of its arguments by returning the
|
|
||||||
first non-empty argument or the last argument, that is,
|
|
||||||
"or x y" behaves as "if x then x else y". All the
|
|
||||||
arguments are evaluated.
|
|
||||||
print
|
|
||||||
An alias for fmt.Sprint
|
|
||||||
printf
|
|
||||||
An alias for fmt.Sprintf
|
|
||||||
println
|
|
||||||
An alias for fmt.Sprintln
|
|
||||||
urlquery
|
|
||||||
Returns the escaped value of the textual representation of
|
|
||||||
its arguments in a form suitable for embedding in a URL query.
|
|
||||||
|
|
||||||
The boolean functions take any zero value to be false and a non-zero
|
|
||||||
value to be true.
|
|
||||||
|
|
||||||
There is also a set of binary comparison operators defined as
|
|
||||||
functions:
|
|
||||||
|
|
||||||
eq
|
|
||||||
Returns the boolean truth of arg1 == arg2
|
|
||||||
ne
|
|
||||||
Returns the boolean truth of arg1 != arg2
|
|
||||||
lt
|
|
||||||
Returns the boolean truth of arg1 < arg2
|
|
||||||
le
|
|
||||||
Returns the boolean truth of arg1 <= arg2
|
|
||||||
gt
|
|
||||||
Returns the boolean truth of arg1 > arg2
|
|
||||||
ge
|
|
||||||
Returns the boolean truth of arg1 >= arg2
|
|
||||||
|
|
||||||
For simpler multi-way equality tests, eq (only) accepts two or more
|
|
||||||
arguments and compares the second and subsequent to the first,
|
|
||||||
returning in effect
|
|
||||||
|
|
||||||
arg1==arg2 || arg1==arg3 || arg1==arg4 ...
|
|
||||||
|
|
||||||
(Unlike with || in Go, however, eq is a function call and all the
|
|
||||||
arguments will be evaluated.)
|
|
||||||
|
|
||||||
The comparison functions work on basic types only (or named basic
|
|
||||||
types, such as "type Celsius float32"). They implement the Go rules
|
|
||||||
for comparison of values, except that size and exact type are
|
|
||||||
ignored, so any integer value, signed or unsigned, may be compared
|
|
||||||
with any other integer value. (The arithmetic value is compared,
|
|
||||||
not the bit pattern, so all negative integers are less than all
|
|
||||||
unsigned integers.) However, as usual, one may not compare an int
|
|
||||||
with a float32 and so on.
|
|
||||||
|
|
||||||
Associated templates
|
|
||||||
|
|
||||||
Each template is named by a string specified when it is created. Also, each
|
|
||||||
template is associated with zero or more other templates that it may invoke by
|
|
||||||
name; such associations are transitive and form a name space of templates.
|
|
||||||
|
|
||||||
A template may use a template invocation to instantiate another associated
|
|
||||||
template; see the explanation of the "template" action above. The name must be
|
|
||||||
that of a template associated with the template that contains the invocation.
|
|
||||||
|
|
||||||
Nested template definitions
|
|
||||||
|
|
||||||
When parsing a template, another template may be defined and associated with the
|
|
||||||
template being parsed. Template definitions must appear at the top level of the
|
|
||||||
template, much like global variables in a Go program.
|
|
||||||
|
|
||||||
The syntax of such definitions is to surround each template declaration with a
|
|
||||||
"define" and "end" action.
|
|
||||||
|
|
||||||
The define action names the template being created by providing a string
|
|
||||||
constant. Here is a simple example:
|
|
||||||
|
|
||||||
`{{define "T1"}}ONE{{end}}
|
|
||||||
{{define "T2"}}TWO{{end}}
|
|
||||||
{{define "T3"}}{{template "T1"}} {{template "T2"}}{{end}}
|
|
||||||
{{template "T3"}}`
|
|
||||||
|
|
||||||
This defines two templates, T1 and T2, and a third T3 that invokes the other two
|
|
||||||
when it is executed. Finally it invokes T3. If executed this template will
|
|
||||||
produce the text
|
|
||||||
|
|
||||||
ONE TWO
|
|
||||||
|
|
||||||
By construction, a template may reside in only one association. If it's
|
|
||||||
necessary to have a template addressable from multiple associations, the
|
|
||||||
template definition must be parsed multiple times to create distinct *Template
|
|
||||||
values, or must be copied with the Clone or AddParseTree method.
|
|
||||||
|
|
||||||
Parse may be called multiple times to assemble the various associated templates;
|
|
||||||
see the ParseFiles and ParseGlob functions and methods for simple ways to parse
|
|
||||||
related templates stored in files.
|
|
||||||
|
|
||||||
A template may be executed directly or through ExecuteTemplate, which executes
|
|
||||||
an associated template identified by name. To invoke our example above, we
|
|
||||||
might write,
|
|
||||||
|
|
||||||
err := tmpl.Execute(os.Stdout, "no data needed")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("execution failed: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
or to invoke a particular template explicitly by name,
|
|
||||||
|
|
||||||
err := tmpl.ExecuteTemplate(os.Stdout, "T2", "no data needed")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("execution failed: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
package template
|
|
845
vendor/github.com/alecthomas/template/exec.go
generated
vendored
845
vendor/github.com/alecthomas/template/exec.go
generated
vendored
|
@ -1,845 +0,0 @@
|
||||||
// Copyright 2011 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package template
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"reflect"
|
|
||||||
"runtime"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/alecthomas/template/parse"
|
|
||||||
)
|
|
||||||
|
|
||||||
// state represents the state of an execution. It's not part of the
|
|
||||||
// template so that multiple executions of the same template
|
|
||||||
// can execute in parallel.
|
|
||||||
type state struct {
|
|
||||||
tmpl *Template
|
|
||||||
wr io.Writer
|
|
||||||
node parse.Node // current node, for errors
|
|
||||||
vars []variable // push-down stack of variable values.
|
|
||||||
}
|
|
||||||
|
|
||||||
// variable holds the dynamic value of a variable such as $, $x etc.
|
|
||||||
type variable struct {
|
|
||||||
name string
|
|
||||||
value reflect.Value
|
|
||||||
}
|
|
||||||
|
|
||||||
// push pushes a new variable on the stack.
|
|
||||||
func (s *state) push(name string, value reflect.Value) {
|
|
||||||
s.vars = append(s.vars, variable{name, value})
|
|
||||||
}
|
|
||||||
|
|
||||||
// mark returns the length of the variable stack.
|
|
||||||
func (s *state) mark() int {
|
|
||||||
return len(s.vars)
|
|
||||||
}
|
|
||||||
|
|
||||||
// pop pops the variable stack up to the mark.
|
|
||||||
func (s *state) pop(mark int) {
|
|
||||||
s.vars = s.vars[0:mark]
|
|
||||||
}
|
|
||||||
|
|
||||||
// setVar overwrites the top-nth variable on the stack. Used by range iterations.
|
|
||||||
func (s *state) setVar(n int, value reflect.Value) {
|
|
||||||
s.vars[len(s.vars)-n].value = value
|
|
||||||
}
|
|
||||||
|
|
||||||
// varValue returns the value of the named variable.
|
|
||||||
func (s *state) varValue(name string) reflect.Value {
|
|
||||||
for i := s.mark() - 1; i >= 0; i-- {
|
|
||||||
if s.vars[i].name == name {
|
|
||||||
return s.vars[i].value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s.errorf("undefined variable: %s", name)
|
|
||||||
return zero
|
|
||||||
}
|
|
||||||
|
|
||||||
var zero reflect.Value
|
|
||||||
|
|
||||||
// at marks the state to be on node n, for error reporting.
|
|
||||||
func (s *state) at(node parse.Node) {
|
|
||||||
s.node = node
|
|
||||||
}
|
|
||||||
|
|
||||||
// doublePercent returns the string with %'s replaced by %%, if necessary,
|
|
||||||
// so it can be used safely inside a Printf format string.
|
|
||||||
func doublePercent(str string) string {
|
|
||||||
if strings.Contains(str, "%") {
|
|
||||||
str = strings.Replace(str, "%", "%%", -1)
|
|
||||||
}
|
|
||||||
return str
|
|
||||||
}
|
|
||||||
|
|
||||||
// errorf formats the error and terminates processing.
|
|
||||||
func (s *state) errorf(format string, args ...interface{}) {
|
|
||||||
name := doublePercent(s.tmpl.Name())
|
|
||||||
if s.node == nil {
|
|
||||||
format = fmt.Sprintf("template: %s: %s", name, format)
|
|
||||||
} else {
|
|
||||||
location, context := s.tmpl.ErrorContext(s.node)
|
|
||||||
format = fmt.Sprintf("template: %s: executing %q at <%s>: %s", location, name, doublePercent(context), format)
|
|
||||||
}
|
|
||||||
panic(fmt.Errorf(format, args...))
|
|
||||||
}
|
|
||||||
|
|
||||||
// errRecover is the handler that turns panics into returns from the top
|
|
||||||
// level of Parse.
|
|
||||||
func errRecover(errp *error) {
|
|
||||||
e := recover()
|
|
||||||
if e != nil {
|
|
||||||
switch err := e.(type) {
|
|
||||||
case runtime.Error:
|
|
||||||
panic(e)
|
|
||||||
case error:
|
|
||||||
*errp = err
|
|
||||||
default:
|
|
||||||
panic(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExecuteTemplate applies the template associated with t that has the given name
|
|
||||||
// to the specified data object and writes the output to wr.
|
|
||||||
// If an error occurs executing the template or writing its output,
|
|
||||||
// execution stops, but partial results may already have been written to
|
|
||||||
// the output writer.
|
|
||||||
// A template may be executed safely in parallel.
|
|
||||||
func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error {
|
|
||||||
tmpl := t.tmpl[name]
|
|
||||||
if tmpl == nil {
|
|
||||||
return fmt.Errorf("template: no template %q associated with template %q", name, t.name)
|
|
||||||
}
|
|
||||||
return tmpl.Execute(wr, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Execute applies a parsed template to the specified data object,
|
|
||||||
// and writes the output to wr.
|
|
||||||
// If an error occurs executing the template or writing its output,
|
|
||||||
// execution stops, but partial results may already have been written to
|
|
||||||
// the output writer.
|
|
||||||
// A template may be executed safely in parallel.
|
|
||||||
func (t *Template) Execute(wr io.Writer, data interface{}) (err error) {
|
|
||||||
defer errRecover(&err)
|
|
||||||
value := reflect.ValueOf(data)
|
|
||||||
state := &state{
|
|
||||||
tmpl: t,
|
|
||||||
wr: wr,
|
|
||||||
vars: []variable{{"$", value}},
|
|
||||||
}
|
|
||||||
t.init()
|
|
||||||
if t.Tree == nil || t.Root == nil {
|
|
||||||
var b bytes.Buffer
|
|
||||||
for name, tmpl := range t.tmpl {
|
|
||||||
if tmpl.Tree == nil || tmpl.Root == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if b.Len() > 0 {
|
|
||||||
b.WriteString(", ")
|
|
||||||
}
|
|
||||||
fmt.Fprintf(&b, "%q", name)
|
|
||||||
}
|
|
||||||
var s string
|
|
||||||
if b.Len() > 0 {
|
|
||||||
s = "; defined templates are: " + b.String()
|
|
||||||
}
|
|
||||||
state.errorf("%q is an incomplete or empty template%s", t.Name(), s)
|
|
||||||
}
|
|
||||||
state.walk(value, t.Root)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Walk functions step through the major pieces of the template structure,
|
|
||||||
// generating output as they go.
|
|
||||||
func (s *state) walk(dot reflect.Value, node parse.Node) {
|
|
||||||
s.at(node)
|
|
||||||
switch node := node.(type) {
|
|
||||||
case *parse.ActionNode:
|
|
||||||
// Do not pop variables so they persist until next end.
|
|
||||||
// Also, if the action declares variables, don't print the result.
|
|
||||||
val := s.evalPipeline(dot, node.Pipe)
|
|
||||||
if len(node.Pipe.Decl) == 0 {
|
|
||||||
s.printValue(node, val)
|
|
||||||
}
|
|
||||||
case *parse.IfNode:
|
|
||||||
s.walkIfOrWith(parse.NodeIf, dot, node.Pipe, node.List, node.ElseList)
|
|
||||||
case *parse.ListNode:
|
|
||||||
for _, node := range node.Nodes {
|
|
||||||
s.walk(dot, node)
|
|
||||||
}
|
|
||||||
case *parse.RangeNode:
|
|
||||||
s.walkRange(dot, node)
|
|
||||||
case *parse.TemplateNode:
|
|
||||||
s.walkTemplate(dot, node)
|
|
||||||
case *parse.TextNode:
|
|
||||||
if _, err := s.wr.Write(node.Text); err != nil {
|
|
||||||
s.errorf("%s", err)
|
|
||||||
}
|
|
||||||
case *parse.WithNode:
|
|
||||||
s.walkIfOrWith(parse.NodeWith, dot, node.Pipe, node.List, node.ElseList)
|
|
||||||
default:
|
|
||||||
s.errorf("unknown node: %s", node)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// walkIfOrWith walks an 'if' or 'with' node. The two control structures
|
|
||||||
// are identical in behavior except that 'with' sets dot.
|
|
||||||
func (s *state) walkIfOrWith(typ parse.NodeType, dot reflect.Value, pipe *parse.PipeNode, list, elseList *parse.ListNode) {
|
|
||||||
defer s.pop(s.mark())
|
|
||||||
val := s.evalPipeline(dot, pipe)
|
|
||||||
truth, ok := isTrue(val)
|
|
||||||
if !ok {
|
|
||||||
s.errorf("if/with can't use %v", val)
|
|
||||||
}
|
|
||||||
if truth {
|
|
||||||
if typ == parse.NodeWith {
|
|
||||||
s.walk(val, list)
|
|
||||||
} else {
|
|
||||||
s.walk(dot, list)
|
|
||||||
}
|
|
||||||
} else if elseList != nil {
|
|
||||||
s.walk(dot, elseList)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// isTrue reports whether the value is 'true', in the sense of not the zero of its type,
|
|
||||||
// and whether the value has a meaningful truth value.
|
|
||||||
func isTrue(val reflect.Value) (truth, ok bool) {
|
|
||||||
if !val.IsValid() {
|
|
||||||
// Something like var x interface{}, never set. It's a form of nil.
|
|
||||||
return false, true
|
|
||||||
}
|
|
||||||
switch val.Kind() {
|
|
||||||
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
|
|
||||||
truth = val.Len() > 0
|
|
||||||
case reflect.Bool:
|
|
||||||
truth = val.Bool()
|
|
||||||
case reflect.Complex64, reflect.Complex128:
|
|
||||||
truth = val.Complex() != 0
|
|
||||||
case reflect.Chan, reflect.Func, reflect.Ptr, reflect.Interface:
|
|
||||||
truth = !val.IsNil()
|
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
||||||
truth = val.Int() != 0
|
|
||||||
case reflect.Float32, reflect.Float64:
|
|
||||||
truth = val.Float() != 0
|
|
||||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
|
||||||
truth = val.Uint() != 0
|
|
||||||
case reflect.Struct:
|
|
||||||
truth = true // Struct values are always true.
|
|
||||||
default:
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return truth, true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) {
|
|
||||||
s.at(r)
|
|
||||||
defer s.pop(s.mark())
|
|
||||||
val, _ := indirect(s.evalPipeline(dot, r.Pipe))
|
|
||||||
// mark top of stack before any variables in the body are pushed.
|
|
||||||
mark := s.mark()
|
|
||||||
oneIteration := func(index, elem reflect.Value) {
|
|
||||||
// Set top var (lexically the second if there are two) to the element.
|
|
||||||
if len(r.Pipe.Decl) > 0 {
|
|
||||||
s.setVar(1, elem)
|
|
||||||
}
|
|
||||||
// Set next var (lexically the first if there are two) to the index.
|
|
||||||
if len(r.Pipe.Decl) > 1 {
|
|
||||||
s.setVar(2, index)
|
|
||||||
}
|
|
||||||
s.walk(elem, r.List)
|
|
||||||
s.pop(mark)
|
|
||||||
}
|
|
||||||
switch val.Kind() {
|
|
||||||
case reflect.Array, reflect.Slice:
|
|
||||||
if val.Len() == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
for i := 0; i < val.Len(); i++ {
|
|
||||||
oneIteration(reflect.ValueOf(i), val.Index(i))
|
|
||||||
}
|
|
||||||
return
|
|
||||||
case reflect.Map:
|
|
||||||
if val.Len() == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
for _, key := range sortKeys(val.MapKeys()) {
|
|
||||||
oneIteration(key, val.MapIndex(key))
|
|
||||||
}
|
|
||||||
return
|
|
||||||
case reflect.Chan:
|
|
||||||
if val.IsNil() {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
i := 0
|
|
||||||
for ; ; i++ {
|
|
||||||
elem, ok := val.Recv()
|
|
||||||
if !ok {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
oneIteration(reflect.ValueOf(i), elem)
|
|
||||||
}
|
|
||||||
if i == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
return
|
|
||||||
case reflect.Invalid:
|
|
||||||
break // An invalid value is likely a nil map, etc. and acts like an empty map.
|
|
||||||
default:
|
|
||||||
s.errorf("range can't iterate over %v", val)
|
|
||||||
}
|
|
||||||
if r.ElseList != nil {
|
|
||||||
s.walk(dot, r.ElseList)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *state) walkTemplate(dot reflect.Value, t *parse.TemplateNode) {
|
|
||||||
s.at(t)
|
|
||||||
tmpl := s.tmpl.tmpl[t.Name]
|
|
||||||
if tmpl == nil {
|
|
||||||
s.errorf("template %q not defined", t.Name)
|
|
||||||
}
|
|
||||||
// Variables declared by the pipeline persist.
|
|
||||||
dot = s.evalPipeline(dot, t.Pipe)
|
|
||||||
newState := *s
|
|
||||||
newState.tmpl = tmpl
|
|
||||||
// No dynamic scoping: template invocations inherit no variables.
|
|
||||||
newState.vars = []variable{{"$", dot}}
|
|
||||||
newState.walk(dot, tmpl.Root)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Eval functions evaluate pipelines, commands, and their elements and extract
|
|
||||||
// values from the data structure by examining fields, calling methods, and so on.
|
|
||||||
// The printing of those values happens only through walk functions.
|
|
||||||
|
|
||||||
// evalPipeline returns the value acquired by evaluating a pipeline. If the
|
|
||||||
// pipeline has a variable declaration, the variable will be pushed on the
|
|
||||||
// stack. Callers should therefore pop the stack after they are finished
|
|
||||||
// executing commands depending on the pipeline value.
|
|
||||||
func (s *state) evalPipeline(dot reflect.Value, pipe *parse.PipeNode) (value reflect.Value) {
|
|
||||||
if pipe == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.at(pipe)
|
|
||||||
for _, cmd := range pipe.Cmds {
|
|
||||||
value = s.evalCommand(dot, cmd, value) // previous value is this one's final arg.
|
|
||||||
// If the object has type interface{}, dig down one level to the thing inside.
|
|
||||||
if value.Kind() == reflect.Interface && value.Type().NumMethod() == 0 {
|
|
||||||
value = reflect.ValueOf(value.Interface()) // lovely!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, variable := range pipe.Decl {
|
|
||||||
s.push(variable.Ident[0], value)
|
|
||||||
}
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *state) notAFunction(args []parse.Node, final reflect.Value) {
|
|
||||||
if len(args) > 1 || final.IsValid() {
|
|
||||||
s.errorf("can't give argument to non-function %s", args[0])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *state) evalCommand(dot reflect.Value, cmd *parse.CommandNode, final reflect.Value) reflect.Value {
|
|
||||||
firstWord := cmd.Args[0]
|
|
||||||
switch n := firstWord.(type) {
|
|
||||||
case *parse.FieldNode:
|
|
||||||
return s.evalFieldNode(dot, n, cmd.Args, final)
|
|
||||||
case *parse.ChainNode:
|
|
||||||
return s.evalChainNode(dot, n, cmd.Args, final)
|
|
||||||
case *parse.IdentifierNode:
|
|
||||||
// Must be a function.
|
|
||||||
return s.evalFunction(dot, n, cmd, cmd.Args, final)
|
|
||||||
case *parse.PipeNode:
|
|
||||||
// Parenthesized pipeline. The arguments are all inside the pipeline; final is ignored.
|
|
||||||
return s.evalPipeline(dot, n)
|
|
||||||
case *parse.VariableNode:
|
|
||||||
return s.evalVariableNode(dot, n, cmd.Args, final)
|
|
||||||
}
|
|
||||||
s.at(firstWord)
|
|
||||||
s.notAFunction(cmd.Args, final)
|
|
||||||
switch word := firstWord.(type) {
|
|
||||||
case *parse.BoolNode:
|
|
||||||
return reflect.ValueOf(word.True)
|
|
||||||
case *parse.DotNode:
|
|
||||||
return dot
|
|
||||||
case *parse.NilNode:
|
|
||||||
s.errorf("nil is not a command")
|
|
||||||
case *parse.NumberNode:
|
|
||||||
return s.idealConstant(word)
|
|
||||||
case *parse.StringNode:
|
|
||||||
return reflect.ValueOf(word.Text)
|
|
||||||
}
|
|
||||||
s.errorf("can't evaluate command %q", firstWord)
|
|
||||||
panic("not reached")
|
|
||||||
}
|
|
||||||
|
|
||||||
// idealConstant is called to return the value of a number in a context where
|
|
||||||
// we don't know the type. In that case, the syntax of the number tells us
|
|
||||||
// its type, and we use Go rules to resolve. Note there is no such thing as
|
|
||||||
// a uint ideal constant in this situation - the value must be of int type.
|
|
||||||
func (s *state) idealConstant(constant *parse.NumberNode) reflect.Value {
|
|
||||||
// These are ideal constants but we don't know the type
|
|
||||||
// and we have no context. (If it was a method argument,
|
|
||||||
// we'd know what we need.) The syntax guides us to some extent.
|
|
||||||
s.at(constant)
|
|
||||||
switch {
|
|
||||||
case constant.IsComplex:
|
|
||||||
return reflect.ValueOf(constant.Complex128) // incontrovertible.
|
|
||||||
case constant.IsFloat && !isHexConstant(constant.Text) && strings.IndexAny(constant.Text, ".eE") >= 0:
|
|
||||||
return reflect.ValueOf(constant.Float64)
|
|
||||||
case constant.IsInt:
|
|
||||||
n := int(constant.Int64)
|
|
||||||
if int64(n) != constant.Int64 {
|
|
||||||
s.errorf("%s overflows int", constant.Text)
|
|
||||||
}
|
|
||||||
return reflect.ValueOf(n)
|
|
||||||
case constant.IsUint:
|
|
||||||
s.errorf("%s overflows int", constant.Text)
|
|
||||||
}
|
|
||||||
return zero
|
|
||||||
}
|
|
||||||
|
|
||||||
func isHexConstant(s string) bool {
|
|
||||||
return len(s) > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *state) evalFieldNode(dot reflect.Value, field *parse.FieldNode, args []parse.Node, final reflect.Value) reflect.Value {
|
|
||||||
s.at(field)
|
|
||||||
return s.evalFieldChain(dot, dot, field, field.Ident, args, final)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *state) evalChainNode(dot reflect.Value, chain *parse.ChainNode, args []parse.Node, final reflect.Value) reflect.Value {
|
|
||||||
s.at(chain)
|
|
||||||
// (pipe).Field1.Field2 has pipe as .Node, fields as .Field. Eval the pipeline, then the fields.
|
|
||||||
pipe := s.evalArg(dot, nil, chain.Node)
|
|
||||||
if len(chain.Field) == 0 {
|
|
||||||
s.errorf("internal error: no fields in evalChainNode")
|
|
||||||
}
|
|
||||||
return s.evalFieldChain(dot, pipe, chain, chain.Field, args, final)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *state) evalVariableNode(dot reflect.Value, variable *parse.VariableNode, args []parse.Node, final reflect.Value) reflect.Value {
|
|
||||||
// $x.Field has $x as the first ident, Field as the second. Eval the var, then the fields.
|
|
||||||
s.at(variable)
|
|
||||||
value := s.varValue(variable.Ident[0])
|
|
||||||
if len(variable.Ident) == 1 {
|
|
||||||
s.notAFunction(args, final)
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
return s.evalFieldChain(dot, value, variable, variable.Ident[1:], args, final)
|
|
||||||
}
|
|
||||||
|
|
||||||
// evalFieldChain evaluates .X.Y.Z possibly followed by arguments.
|
|
||||||
// dot is the environment in which to evaluate arguments, while
|
|
||||||
// receiver is the value being walked along the chain.
|
|
||||||
func (s *state) evalFieldChain(dot, receiver reflect.Value, node parse.Node, ident []string, args []parse.Node, final reflect.Value) reflect.Value {
|
|
||||||
n := len(ident)
|
|
||||||
for i := 0; i < n-1; i++ {
|
|
||||||
receiver = s.evalField(dot, ident[i], node, nil, zero, receiver)
|
|
||||||
}
|
|
||||||
// Now if it's a method, it gets the arguments.
|
|
||||||
return s.evalField(dot, ident[n-1], node, args, final, receiver)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *state) evalFunction(dot reflect.Value, node *parse.IdentifierNode, cmd parse.Node, args []parse.Node, final reflect.Value) reflect.Value {
|
|
||||||
s.at(node)
|
|
||||||
name := node.Ident
|
|
||||||
function, ok := findFunction(name, s.tmpl)
|
|
||||||
if !ok {
|
|
||||||
s.errorf("%q is not a defined function", name)
|
|
||||||
}
|
|
||||||
return s.evalCall(dot, function, cmd, name, args, final)
|
|
||||||
}
|
|
||||||
|
|
||||||
// evalField evaluates an expression like (.Field) or (.Field arg1 arg2).
|
|
||||||
// The 'final' argument represents the return value from the preceding
|
|
||||||
// value of the pipeline, if any.
|
|
||||||
func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node, args []parse.Node, final, receiver reflect.Value) reflect.Value {
|
|
||||||
if !receiver.IsValid() {
|
|
||||||
return zero
|
|
||||||
}
|
|
||||||
typ := receiver.Type()
|
|
||||||
receiver, _ = indirect(receiver)
|
|
||||||
// Unless it's an interface, need to get to a value of type *T to guarantee
|
|
||||||
// we see all methods of T and *T.
|
|
||||||
ptr := receiver
|
|
||||||
if ptr.Kind() != reflect.Interface && ptr.CanAddr() {
|
|
||||||
ptr = ptr.Addr()
|
|
||||||
}
|
|
||||||
if method := ptr.MethodByName(fieldName); method.IsValid() {
|
|
||||||
return s.evalCall(dot, method, node, fieldName, args, final)
|
|
||||||
}
|
|
||||||
hasArgs := len(args) > 1 || final.IsValid()
|
|
||||||
// It's not a method; must be a field of a struct or an element of a map. The receiver must not be nil.
|
|
||||||
receiver, isNil := indirect(receiver)
|
|
||||||
if isNil {
|
|
||||||
s.errorf("nil pointer evaluating %s.%s", typ, fieldName)
|
|
||||||
}
|
|
||||||
switch receiver.Kind() {
|
|
||||||
case reflect.Struct:
|
|
||||||
tField, ok := receiver.Type().FieldByName(fieldName)
|
|
||||||
if ok {
|
|
||||||
field := receiver.FieldByIndex(tField.Index)
|
|
||||||
if tField.PkgPath != "" { // field is unexported
|
|
||||||
s.errorf("%s is an unexported field of struct type %s", fieldName, typ)
|
|
||||||
}
|
|
||||||
// If it's a function, we must call it.
|
|
||||||
if hasArgs {
|
|
||||||
s.errorf("%s has arguments but cannot be invoked as function", fieldName)
|
|
||||||
}
|
|
||||||
return field
|
|
||||||
}
|
|
||||||
s.errorf("%s is not a field of struct type %s", fieldName, typ)
|
|
||||||
case reflect.Map:
|
|
||||||
// If it's a map, attempt to use the field name as a key.
|
|
||||||
nameVal := reflect.ValueOf(fieldName)
|
|
||||||
if nameVal.Type().AssignableTo(receiver.Type().Key()) {
|
|
||||||
if hasArgs {
|
|
||||||
s.errorf("%s is not a method but has arguments", fieldName)
|
|
||||||
}
|
|
||||||
return receiver.MapIndex(nameVal)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s.errorf("can't evaluate field %s in type %s", fieldName, typ)
|
|
||||||
panic("not reached")
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
errorType = reflect.TypeOf((*error)(nil)).Elem()
|
|
||||||
fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
|
|
||||||
)
|
|
||||||
|
|
||||||
// evalCall executes a function or method call. If it's a method, fun already has the receiver bound, so
|
|
||||||
// it looks just like a function call. The arg list, if non-nil, includes (in the manner of the shell), arg[0]
|
|
||||||
// as the function itself.
|
|
||||||
func (s *state) evalCall(dot, fun reflect.Value, node parse.Node, name string, args []parse.Node, final reflect.Value) reflect.Value {
|
|
||||||
if args != nil {
|
|
||||||
args = args[1:] // Zeroth arg is function name/node; not passed to function.
|
|
||||||
}
|
|
||||||
typ := fun.Type()
|
|
||||||
numIn := len(args)
|
|
||||||
if final.IsValid() {
|
|
||||||
numIn++
|
|
||||||
}
|
|
||||||
numFixed := len(args)
|
|
||||||
if typ.IsVariadic() {
|
|
||||||
numFixed = typ.NumIn() - 1 // last arg is the variadic one.
|
|
||||||
if numIn < numFixed {
|
|
||||||
s.errorf("wrong number of args for %s: want at least %d got %d", name, typ.NumIn()-1, len(args))
|
|
||||||
}
|
|
||||||
} else if numIn < typ.NumIn()-1 || !typ.IsVariadic() && numIn != typ.NumIn() {
|
|
||||||
s.errorf("wrong number of args for %s: want %d got %d", name, typ.NumIn(), len(args))
|
|
||||||
}
|
|
||||||
if !goodFunc(typ) {
|
|
||||||
// TODO: This could still be a confusing error; maybe goodFunc should provide info.
|
|
||||||
s.errorf("can't call method/function %q with %d results", name, typ.NumOut())
|
|
||||||
}
|
|
||||||
// Build the arg list.
|
|
||||||
argv := make([]reflect.Value, numIn)
|
|
||||||
// Args must be evaluated. Fixed args first.
|
|
||||||
i := 0
|
|
||||||
for ; i < numFixed && i < len(args); i++ {
|
|
||||||
argv[i] = s.evalArg(dot, typ.In(i), args[i])
|
|
||||||
}
|
|
||||||
// Now the ... args.
|
|
||||||
if typ.IsVariadic() {
|
|
||||||
argType := typ.In(typ.NumIn() - 1).Elem() // Argument is a slice.
|
|
||||||
for ; i < len(args); i++ {
|
|
||||||
argv[i] = s.evalArg(dot, argType, args[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Add final value if necessary.
|
|
||||||
if final.IsValid() {
|
|
||||||
t := typ.In(typ.NumIn() - 1)
|
|
||||||
if typ.IsVariadic() {
|
|
||||||
t = t.Elem()
|
|
||||||
}
|
|
||||||
argv[i] = s.validateType(final, t)
|
|
||||||
}
|
|
||||||
result := fun.Call(argv)
|
|
||||||
// If we have an error that is not nil, stop execution and return that error to the caller.
|
|
||||||
if len(result) == 2 && !result[1].IsNil() {
|
|
||||||
s.at(node)
|
|
||||||
s.errorf("error calling %s: %s", name, result[1].Interface().(error))
|
|
||||||
}
|
|
||||||
return result[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
// canBeNil reports whether an untyped nil can be assigned to the type. See reflect.Zero.
|
|
||||||
func canBeNil(typ reflect.Type) bool {
|
|
||||||
switch typ.Kind() {
|
|
||||||
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// validateType guarantees that the value is valid and assignable to the type.
|
|
||||||
func (s *state) validateType(value reflect.Value, typ reflect.Type) reflect.Value {
|
|
||||||
if !value.IsValid() {
|
|
||||||
if typ == nil || canBeNil(typ) {
|
|
||||||
// An untyped nil interface{}. Accept as a proper nil value.
|
|
||||||
return reflect.Zero(typ)
|
|
||||||
}
|
|
||||||
s.errorf("invalid value; expected %s", typ)
|
|
||||||
}
|
|
||||||
if typ != nil && !value.Type().AssignableTo(typ) {
|
|
||||||
if value.Kind() == reflect.Interface && !value.IsNil() {
|
|
||||||
value = value.Elem()
|
|
||||||
if value.Type().AssignableTo(typ) {
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
// fallthrough
|
|
||||||
}
|
|
||||||
// Does one dereference or indirection work? We could do more, as we
|
|
||||||
// do with method receivers, but that gets messy and method receivers
|
|
||||||
// are much more constrained, so it makes more sense there than here.
|
|
||||||
// Besides, one is almost always all you need.
|
|
||||||
switch {
|
|
||||||
case value.Kind() == reflect.Ptr && value.Type().Elem().AssignableTo(typ):
|
|
||||||
value = value.Elem()
|
|
||||||
if !value.IsValid() {
|
|
||||||
s.errorf("dereference of nil pointer of type %s", typ)
|
|
||||||
}
|
|
||||||
case reflect.PtrTo(value.Type()).AssignableTo(typ) && value.CanAddr():
|
|
||||||
value = value.Addr()
|
|
||||||
default:
|
|
||||||
s.errorf("wrong type for value; expected %s; got %s", typ, value.Type())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *state) evalArg(dot reflect.Value, typ reflect.Type, n parse.Node) reflect.Value {
|
|
||||||
s.at(n)
|
|
||||||
switch arg := n.(type) {
|
|
||||||
case *parse.DotNode:
|
|
||||||
return s.validateType(dot, typ)
|
|
||||||
case *parse.NilNode:
|
|
||||||
if canBeNil(typ) {
|
|
||||||
return reflect.Zero(typ)
|
|
||||||
}
|
|
||||||
s.errorf("cannot assign nil to %s", typ)
|
|
||||||
case *parse.FieldNode:
|
|
||||||
return s.validateType(s.evalFieldNode(dot, arg, []parse.Node{n}, zero), typ)
|
|
||||||
case *parse.VariableNode:
|
|
||||||
return s.validateType(s.evalVariableNode(dot, arg, nil, zero), typ)
|
|
||||||
case *parse.PipeNode:
|
|
||||||
return s.validateType(s.evalPipeline(dot, arg), typ)
|
|
||||||
case *parse.IdentifierNode:
|
|
||||||
return s.evalFunction(dot, arg, arg, nil, zero)
|
|
||||||
case *parse.ChainNode:
|
|
||||||
return s.validateType(s.evalChainNode(dot, arg, nil, zero), typ)
|
|
||||||
}
|
|
||||||
switch typ.Kind() {
|
|
||||||
case reflect.Bool:
|
|
||||||
return s.evalBool(typ, n)
|
|
||||||
case reflect.Complex64, reflect.Complex128:
|
|
||||||
return s.evalComplex(typ, n)
|
|
||||||
case reflect.Float32, reflect.Float64:
|
|
||||||
return s.evalFloat(typ, n)
|
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
||||||
return s.evalInteger(typ, n)
|
|
||||||
case reflect.Interface:
|
|
||||||
if typ.NumMethod() == 0 {
|
|
||||||
return s.evalEmptyInterface(dot, n)
|
|
||||||
}
|
|
||||||
case reflect.String:
|
|
||||||
return s.evalString(typ, n)
|
|
||||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
|
||||||
return s.evalUnsignedInteger(typ, n)
|
|
||||||
}
|
|
||||||
s.errorf("can't handle %s for arg of type %s", n, typ)
|
|
||||||
panic("not reached")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *state) evalBool(typ reflect.Type, n parse.Node) reflect.Value {
|
|
||||||
s.at(n)
|
|
||||||
if n, ok := n.(*parse.BoolNode); ok {
|
|
||||||
value := reflect.New(typ).Elem()
|
|
||||||
value.SetBool(n.True)
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
s.errorf("expected bool; found %s", n)
|
|
||||||
panic("not reached")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *state) evalString(typ reflect.Type, n parse.Node) reflect.Value {
|
|
||||||
s.at(n)
|
|
||||||
if n, ok := n.(*parse.StringNode); ok {
|
|
||||||
value := reflect.New(typ).Elem()
|
|
||||||
value.SetString(n.Text)
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
s.errorf("expected string; found %s", n)
|
|
||||||
panic("not reached")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *state) evalInteger(typ reflect.Type, n parse.Node) reflect.Value {
|
|
||||||
s.at(n)
|
|
||||||
if n, ok := n.(*parse.NumberNode); ok && n.IsInt {
|
|
||||||
value := reflect.New(typ).Elem()
|
|
||||||
value.SetInt(n.Int64)
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
s.errorf("expected integer; found %s", n)
|
|
||||||
panic("not reached")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *state) evalUnsignedInteger(typ reflect.Type, n parse.Node) reflect.Value {
|
|
||||||
s.at(n)
|
|
||||||
if n, ok := n.(*parse.NumberNode); ok && n.IsUint {
|
|
||||||
value := reflect.New(typ).Elem()
|
|
||||||
value.SetUint(n.Uint64)
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
s.errorf("expected unsigned integer; found %s", n)
|
|
||||||
panic("not reached")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *state) evalFloat(typ reflect.Type, n parse.Node) reflect.Value {
|
|
||||||
s.at(n)
|
|
||||||
if n, ok := n.(*parse.NumberNode); ok && n.IsFloat {
|
|
||||||
value := reflect.New(typ).Elem()
|
|
||||||
value.SetFloat(n.Float64)
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
s.errorf("expected float; found %s", n)
|
|
||||||
panic("not reached")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *state) evalComplex(typ reflect.Type, n parse.Node) reflect.Value {
|
|
||||||
if n, ok := n.(*parse.NumberNode); ok && n.IsComplex {
|
|
||||||
value := reflect.New(typ).Elem()
|
|
||||||
value.SetComplex(n.Complex128)
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
s.errorf("expected complex; found %s", n)
|
|
||||||
panic("not reached")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *state) evalEmptyInterface(dot reflect.Value, n parse.Node) reflect.Value {
|
|
||||||
s.at(n)
|
|
||||||
switch n := n.(type) {
|
|
||||||
case *parse.BoolNode:
|
|
||||||
return reflect.ValueOf(n.True)
|
|
||||||
case *parse.DotNode:
|
|
||||||
return dot
|
|
||||||
case *parse.FieldNode:
|
|
||||||
return s.evalFieldNode(dot, n, nil, zero)
|
|
||||||
case *parse.IdentifierNode:
|
|
||||||
return s.evalFunction(dot, n, n, nil, zero)
|
|
||||||
case *parse.NilNode:
|
|
||||||
// NilNode is handled in evalArg, the only place that calls here.
|
|
||||||
s.errorf("evalEmptyInterface: nil (can't happen)")
|
|
||||||
case *parse.NumberNode:
|
|
||||||
return s.idealConstant(n)
|
|
||||||
case *parse.StringNode:
|
|
||||||
return reflect.ValueOf(n.Text)
|
|
||||||
case *parse.VariableNode:
|
|
||||||
return s.evalVariableNode(dot, n, nil, zero)
|
|
||||||
case *parse.PipeNode:
|
|
||||||
return s.evalPipeline(dot, n)
|
|
||||||
}
|
|
||||||
s.errorf("can't handle assignment of %s to empty interface argument", n)
|
|
||||||
panic("not reached")
|
|
||||||
}
|
|
||||||
|
|
||||||
// indirect returns the item at the end of indirection, and a bool to indicate if it's nil.
|
|
||||||
// We indirect through pointers and empty interfaces (only) because
|
|
||||||
// non-empty interfaces have methods we might need.
|
|
||||||
func indirect(v reflect.Value) (rv reflect.Value, isNil bool) {
|
|
||||||
for ; v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface; v = v.Elem() {
|
|
||||||
if v.IsNil() {
|
|
||||||
return v, true
|
|
||||||
}
|
|
||||||
if v.Kind() == reflect.Interface && v.NumMethod() > 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return v, false
|
|
||||||
}
|
|
||||||
|
|
||||||
// printValue writes the textual representation of the value to the output of
|
|
||||||
// the template.
|
|
||||||
func (s *state) printValue(n parse.Node, v reflect.Value) {
|
|
||||||
s.at(n)
|
|
||||||
iface, ok := printableValue(v)
|
|
||||||
if !ok {
|
|
||||||
s.errorf("can't print %s of type %s", n, v.Type())
|
|
||||||
}
|
|
||||||
fmt.Fprint(s.wr, iface)
|
|
||||||
}
|
|
||||||
|
|
||||||
// printableValue returns the, possibly indirected, interface value inside v that
|
|
||||||
// is best for a call to formatted printer.
|
|
||||||
func printableValue(v reflect.Value) (interface{}, bool) {
|
|
||||||
if v.Kind() == reflect.Ptr {
|
|
||||||
v, _ = indirect(v) // fmt.Fprint handles nil.
|
|
||||||
}
|
|
||||||
if !v.IsValid() {
|
|
||||||
return "<no value>", true
|
|
||||||
}
|
|
||||||
|
|
||||||
if !v.Type().Implements(errorType) && !v.Type().Implements(fmtStringerType) {
|
|
||||||
if v.CanAddr() && (reflect.PtrTo(v.Type()).Implements(errorType) || reflect.PtrTo(v.Type()).Implements(fmtStringerType)) {
|
|
||||||
v = v.Addr()
|
|
||||||
} else {
|
|
||||||
switch v.Kind() {
|
|
||||||
case reflect.Chan, reflect.Func:
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return v.Interface(), true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Types to help sort the keys in a map for reproducible output.
|
|
||||||
|
|
||||||
type rvs []reflect.Value
|
|
||||||
|
|
||||||
func (x rvs) Len() int { return len(x) }
|
|
||||||
func (x rvs) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
|
|
||||||
|
|
||||||
type rvInts struct{ rvs }
|
|
||||||
|
|
||||||
func (x rvInts) Less(i, j int) bool { return x.rvs[i].Int() < x.rvs[j].Int() }
|
|
||||||
|
|
||||||
type rvUints struct{ rvs }
|
|
||||||
|
|
||||||
func (x rvUints) Less(i, j int) bool { return x.rvs[i].Uint() < x.rvs[j].Uint() }
|
|
||||||
|
|
||||||
type rvFloats struct{ rvs }
|
|
||||||
|
|
||||||
func (x rvFloats) Less(i, j int) bool { return x.rvs[i].Float() < x.rvs[j].Float() }
|
|
||||||
|
|
||||||
type rvStrings struct{ rvs }
|
|
||||||
|
|
||||||
func (x rvStrings) Less(i, j int) bool { return x.rvs[i].String() < x.rvs[j].String() }
|
|
||||||
|
|
||||||
// sortKeys sorts (if it can) the slice of reflect.Values, which is a slice of map keys.
|
|
||||||
func sortKeys(v []reflect.Value) []reflect.Value {
|
|
||||||
if len(v) <= 1 {
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
switch v[0].Kind() {
|
|
||||||
case reflect.Float32, reflect.Float64:
|
|
||||||
sort.Sort(rvFloats{v})
|
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
||||||
sort.Sort(rvInts{v})
|
|
||||||
case reflect.String:
|
|
||||||
sort.Sort(rvStrings{v})
|
|
||||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
|
||||||
sort.Sort(rvUints{v})
|
|
||||||
}
|
|
||||||
return v
|
|
||||||
}
|
|
598
vendor/github.com/alecthomas/template/funcs.go
generated
vendored
598
vendor/github.com/alecthomas/template/funcs.go
generated
vendored
|
@ -1,598 +0,0 @@
|
||||||
// Copyright 2011 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package template
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"net/url"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
"unicode"
|
|
||||||
"unicode/utf8"
|
|
||||||
)
|
|
||||||
|
|
||||||
// FuncMap is the type of the map defining the mapping from names to functions.
|
|
||||||
// Each function must have either a single return value, or two return values of
|
|
||||||
// which the second has type error. In that case, if the second (error)
|
|
||||||
// return value evaluates to non-nil during execution, execution terminates and
|
|
||||||
// Execute returns that error.
|
|
||||||
type FuncMap map[string]interface{}
|
|
||||||
|
|
||||||
var builtins = FuncMap{
|
|
||||||
"and": and,
|
|
||||||
"call": call,
|
|
||||||
"html": HTMLEscaper,
|
|
||||||
"index": index,
|
|
||||||
"js": JSEscaper,
|
|
||||||
"len": length,
|
|
||||||
"not": not,
|
|
||||||
"or": or,
|
|
||||||
"print": fmt.Sprint,
|
|
||||||
"printf": fmt.Sprintf,
|
|
||||||
"println": fmt.Sprintln,
|
|
||||||
"urlquery": URLQueryEscaper,
|
|
||||||
|
|
||||||
// Comparisons
|
|
||||||
"eq": eq, // ==
|
|
||||||
"ge": ge, // >=
|
|
||||||
"gt": gt, // >
|
|
||||||
"le": le, // <=
|
|
||||||
"lt": lt, // <
|
|
||||||
"ne": ne, // !=
|
|
||||||
}
|
|
||||||
|
|
||||||
var builtinFuncs = createValueFuncs(builtins)
|
|
||||||
|
|
||||||
// createValueFuncs turns a FuncMap into a map[string]reflect.Value
|
|
||||||
func createValueFuncs(funcMap FuncMap) map[string]reflect.Value {
|
|
||||||
m := make(map[string]reflect.Value)
|
|
||||||
addValueFuncs(m, funcMap)
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
|
|
||||||
// addValueFuncs adds to values the functions in funcs, converting them to reflect.Values.
|
|
||||||
func addValueFuncs(out map[string]reflect.Value, in FuncMap) {
|
|
||||||
for name, fn := range in {
|
|
||||||
v := reflect.ValueOf(fn)
|
|
||||||
if v.Kind() != reflect.Func {
|
|
||||||
panic("value for " + name + " not a function")
|
|
||||||
}
|
|
||||||
if !goodFunc(v.Type()) {
|
|
||||||
panic(fmt.Errorf("can't install method/function %q with %d results", name, v.Type().NumOut()))
|
|
||||||
}
|
|
||||||
out[name] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// addFuncs adds to values the functions in funcs. It does no checking of the input -
|
|
||||||
// call addValueFuncs first.
|
|
||||||
func addFuncs(out, in FuncMap) {
|
|
||||||
for name, fn := range in {
|
|
||||||
out[name] = fn
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// goodFunc checks that the function or method has the right result signature.
|
|
||||||
func goodFunc(typ reflect.Type) bool {
|
|
||||||
// We allow functions with 1 result or 2 results where the second is an error.
|
|
||||||
switch {
|
|
||||||
case typ.NumOut() == 1:
|
|
||||||
return true
|
|
||||||
case typ.NumOut() == 2 && typ.Out(1) == errorType:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// findFunction looks for a function in the template, and global map.
|
|
||||||
func findFunction(name string, tmpl *Template) (reflect.Value, bool) {
|
|
||||||
if tmpl != nil && tmpl.common != nil {
|
|
||||||
if fn := tmpl.execFuncs[name]; fn.IsValid() {
|
|
||||||
return fn, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if fn := builtinFuncs[name]; fn.IsValid() {
|
|
||||||
return fn, true
|
|
||||||
}
|
|
||||||
return reflect.Value{}, false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Indexing.
|
|
||||||
|
|
||||||
// index returns the result of indexing its first argument by the following
|
|
||||||
// arguments. Thus "index x 1 2 3" is, in Go syntax, x[1][2][3]. Each
|
|
||||||
// indexed item must be a map, slice, or array.
|
|
||||||
func index(item interface{}, indices ...interface{}) (interface{}, error) {
|
|
||||||
v := reflect.ValueOf(item)
|
|
||||||
for _, i := range indices {
|
|
||||||
index := reflect.ValueOf(i)
|
|
||||||
var isNil bool
|
|
||||||
if v, isNil = indirect(v); isNil {
|
|
||||||
return nil, fmt.Errorf("index of nil pointer")
|
|
||||||
}
|
|
||||||
switch v.Kind() {
|
|
||||||
case reflect.Array, reflect.Slice, reflect.String:
|
|
||||||
var x int64
|
|
||||||
switch index.Kind() {
|
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
||||||
x = index.Int()
|
|
||||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
|
||||||
x = int64(index.Uint())
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("cannot index slice/array with type %s", index.Type())
|
|
||||||
}
|
|
||||||
if x < 0 || x >= int64(v.Len()) {
|
|
||||||
return nil, fmt.Errorf("index out of range: %d", x)
|
|
||||||
}
|
|
||||||
v = v.Index(int(x))
|
|
||||||
case reflect.Map:
|
|
||||||
if !index.IsValid() {
|
|
||||||
index = reflect.Zero(v.Type().Key())
|
|
||||||
}
|
|
||||||
if !index.Type().AssignableTo(v.Type().Key()) {
|
|
||||||
return nil, fmt.Errorf("%s is not index type for %s", index.Type(), v.Type())
|
|
||||||
}
|
|
||||||
if x := v.MapIndex(index); x.IsValid() {
|
|
||||||
v = x
|
|
||||||
} else {
|
|
||||||
v = reflect.Zero(v.Type().Elem())
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("can't index item of type %s", v.Type())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return v.Interface(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Length
|
|
||||||
|
|
||||||
// length returns the length of the item, with an error if it has no defined length.
|
|
||||||
func length(item interface{}) (int, error) {
|
|
||||||
v, isNil := indirect(reflect.ValueOf(item))
|
|
||||||
if isNil {
|
|
||||||
return 0, fmt.Errorf("len of nil pointer")
|
|
||||||
}
|
|
||||||
switch v.Kind() {
|
|
||||||
case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice, reflect.String:
|
|
||||||
return v.Len(), nil
|
|
||||||
}
|
|
||||||
return 0, fmt.Errorf("len of type %s", v.Type())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function invocation
|
|
||||||
|
|
||||||
// call returns the result of evaluating the first argument as a function.
|
|
||||||
// The function must return 1 result, or 2 results, the second of which is an error.
|
|
||||||
func call(fn interface{}, args ...interface{}) (interface{}, error) {
|
|
||||||
v := reflect.ValueOf(fn)
|
|
||||||
typ := v.Type()
|
|
||||||
if typ.Kind() != reflect.Func {
|
|
||||||
return nil, fmt.Errorf("non-function of type %s", typ)
|
|
||||||
}
|
|
||||||
if !goodFunc(typ) {
|
|
||||||
return nil, fmt.Errorf("function called with %d args; should be 1 or 2", typ.NumOut())
|
|
||||||
}
|
|
||||||
numIn := typ.NumIn()
|
|
||||||
var dddType reflect.Type
|
|
||||||
if typ.IsVariadic() {
|
|
||||||
if len(args) < numIn-1 {
|
|
||||||
return nil, fmt.Errorf("wrong number of args: got %d want at least %d", len(args), numIn-1)
|
|
||||||
}
|
|
||||||
dddType = typ.In(numIn - 1).Elem()
|
|
||||||
} else {
|
|
||||||
if len(args) != numIn {
|
|
||||||
return nil, fmt.Errorf("wrong number of args: got %d want %d", len(args), numIn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
argv := make([]reflect.Value, len(args))
|
|
||||||
for i, arg := range args {
|
|
||||||
value := reflect.ValueOf(arg)
|
|
||||||
// Compute the expected type. Clumsy because of variadics.
|
|
||||||
var argType reflect.Type
|
|
||||||
if !typ.IsVariadic() || i < numIn-1 {
|
|
||||||
argType = typ.In(i)
|
|
||||||
} else {
|
|
||||||
argType = dddType
|
|
||||||
}
|
|
||||||
if !value.IsValid() && canBeNil(argType) {
|
|
||||||
value = reflect.Zero(argType)
|
|
||||||
}
|
|
||||||
if !value.Type().AssignableTo(argType) {
|
|
||||||
return nil, fmt.Errorf("arg %d has type %s; should be %s", i, value.Type(), argType)
|
|
||||||
}
|
|
||||||
argv[i] = value
|
|
||||||
}
|
|
||||||
result := v.Call(argv)
|
|
||||||
if len(result) == 2 && !result[1].IsNil() {
|
|
||||||
return result[0].Interface(), result[1].Interface().(error)
|
|
||||||
}
|
|
||||||
return result[0].Interface(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Boolean logic.
|
|
||||||
|
|
||||||
func truth(a interface{}) bool {
|
|
||||||
t, _ := isTrue(reflect.ValueOf(a))
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
// and computes the Boolean AND of its arguments, returning
|
|
||||||
// the first false argument it encounters, or the last argument.
|
|
||||||
func and(arg0 interface{}, args ...interface{}) interface{} {
|
|
||||||
if !truth(arg0) {
|
|
||||||
return arg0
|
|
||||||
}
|
|
||||||
for i := range args {
|
|
||||||
arg0 = args[i]
|
|
||||||
if !truth(arg0) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return arg0
|
|
||||||
}
|
|
||||||
|
|
||||||
// or computes the Boolean OR of its arguments, returning
|
|
||||||
// the first true argument it encounters, or the last argument.
|
|
||||||
func or(arg0 interface{}, args ...interface{}) interface{} {
|
|
||||||
if truth(arg0) {
|
|
||||||
return arg0
|
|
||||||
}
|
|
||||||
for i := range args {
|
|
||||||
arg0 = args[i]
|
|
||||||
if truth(arg0) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return arg0
|
|
||||||
}
|
|
||||||
|
|
||||||
// not returns the Boolean negation of its argument.
|
|
||||||
func not(arg interface{}) (truth bool) {
|
|
||||||
truth, _ = isTrue(reflect.ValueOf(arg))
|
|
||||||
return !truth
|
|
||||||
}
|
|
||||||
|
|
||||||
// Comparison.
|
|
||||||
|
|
||||||
// TODO: Perhaps allow comparison between signed and unsigned integers.
|
|
||||||
|
|
||||||
var (
|
|
||||||
errBadComparisonType = errors.New("invalid type for comparison")
|
|
||||||
errBadComparison = errors.New("incompatible types for comparison")
|
|
||||||
errNoComparison = errors.New("missing argument for comparison")
|
|
||||||
)
|
|
||||||
|
|
||||||
type kind int
|
|
||||||
|
|
||||||
const (
|
|
||||||
invalidKind kind = iota
|
|
||||||
boolKind
|
|
||||||
complexKind
|
|
||||||
intKind
|
|
||||||
floatKind
|
|
||||||
integerKind
|
|
||||||
stringKind
|
|
||||||
uintKind
|
|
||||||
)
|
|
||||||
|
|
||||||
func basicKind(v reflect.Value) (kind, error) {
|
|
||||||
switch v.Kind() {
|
|
||||||
case reflect.Bool:
|
|
||||||
return boolKind, nil
|
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
||||||
return intKind, nil
|
|
||||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
|
||||||
return uintKind, nil
|
|
||||||
case reflect.Float32, reflect.Float64:
|
|
||||||
return floatKind, nil
|
|
||||||
case reflect.Complex64, reflect.Complex128:
|
|
||||||
return complexKind, nil
|
|
||||||
case reflect.String:
|
|
||||||
return stringKind, nil
|
|
||||||
}
|
|
||||||
return invalidKind, errBadComparisonType
|
|
||||||
}
|
|
||||||
|
|
||||||
// eq evaluates the comparison a == b || a == c || ...
|
|
||||||
func eq(arg1 interface{}, arg2 ...interface{}) (bool, error) {
|
|
||||||
v1 := reflect.ValueOf(arg1)
|
|
||||||
k1, err := basicKind(v1)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
if len(arg2) == 0 {
|
|
||||||
return false, errNoComparison
|
|
||||||
}
|
|
||||||
for _, arg := range arg2 {
|
|
||||||
v2 := reflect.ValueOf(arg)
|
|
||||||
k2, err := basicKind(v2)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
truth := false
|
|
||||||
if k1 != k2 {
|
|
||||||
// Special case: Can compare integer values regardless of type's sign.
|
|
||||||
switch {
|
|
||||||
case k1 == intKind && k2 == uintKind:
|
|
||||||
truth = v1.Int() >= 0 && uint64(v1.Int()) == v2.Uint()
|
|
||||||
case k1 == uintKind && k2 == intKind:
|
|
||||||
truth = v2.Int() >= 0 && v1.Uint() == uint64(v2.Int())
|
|
||||||
default:
|
|
||||||
return false, errBadComparison
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch k1 {
|
|
||||||
case boolKind:
|
|
||||||
truth = v1.Bool() == v2.Bool()
|
|
||||||
case complexKind:
|
|
||||||
truth = v1.Complex() == v2.Complex()
|
|
||||||
case floatKind:
|
|
||||||
truth = v1.Float() == v2.Float()
|
|
||||||
case intKind:
|
|
||||||
truth = v1.Int() == v2.Int()
|
|
||||||
case stringKind:
|
|
||||||
truth = v1.String() == v2.String()
|
|
||||||
case uintKind:
|
|
||||||
truth = v1.Uint() == v2.Uint()
|
|
||||||
default:
|
|
||||||
panic("invalid kind")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if truth {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ne evaluates the comparison a != b.
|
|
||||||
func ne(arg1, arg2 interface{}) (bool, error) {
|
|
||||||
// != is the inverse of ==.
|
|
||||||
equal, err := eq(arg1, arg2)
|
|
||||||
return !equal, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// lt evaluates the comparison a < b.
|
|
||||||
func lt(arg1, arg2 interface{}) (bool, error) {
|
|
||||||
v1 := reflect.ValueOf(arg1)
|
|
||||||
k1, err := basicKind(v1)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
v2 := reflect.ValueOf(arg2)
|
|
||||||
k2, err := basicKind(v2)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
truth := false
|
|
||||||
if k1 != k2 {
|
|
||||||
// Special case: Can compare integer values regardless of type's sign.
|
|
||||||
switch {
|
|
||||||
case k1 == intKind && k2 == uintKind:
|
|
||||||
truth = v1.Int() < 0 || uint64(v1.Int()) < v2.Uint()
|
|
||||||
case k1 == uintKind && k2 == intKind:
|
|
||||||
truth = v2.Int() >= 0 && v1.Uint() < uint64(v2.Int())
|
|
||||||
default:
|
|
||||||
return false, errBadComparison
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch k1 {
|
|
||||||
case boolKind, complexKind:
|
|
||||||
return false, errBadComparisonType
|
|
||||||
case floatKind:
|
|
||||||
truth = v1.Float() < v2.Float()
|
|
||||||
case intKind:
|
|
||||||
truth = v1.Int() < v2.Int()
|
|
||||||
case stringKind:
|
|
||||||
truth = v1.String() < v2.String()
|
|
||||||
case uintKind:
|
|
||||||
truth = v1.Uint() < v2.Uint()
|
|
||||||
default:
|
|
||||||
panic("invalid kind")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return truth, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// le evaluates the comparison <= b.
|
|
||||||
func le(arg1, arg2 interface{}) (bool, error) {
|
|
||||||
// <= is < or ==.
|
|
||||||
lessThan, err := lt(arg1, arg2)
|
|
||||||
if lessThan || err != nil {
|
|
||||||
return lessThan, err
|
|
||||||
}
|
|
||||||
return eq(arg1, arg2)
|
|
||||||
}
|
|
||||||
|
|
||||||
// gt evaluates the comparison a > b.
|
|
||||||
func gt(arg1, arg2 interface{}) (bool, error) {
|
|
||||||
// > is the inverse of <=.
|
|
||||||
lessOrEqual, err := le(arg1, arg2)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
return !lessOrEqual, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ge evaluates the comparison a >= b.
|
|
||||||
func ge(arg1, arg2 interface{}) (bool, error) {
|
|
||||||
// >= is the inverse of <.
|
|
||||||
lessThan, err := lt(arg1, arg2)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
return !lessThan, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTML escaping.
|
|
||||||
|
|
||||||
var (
|
|
||||||
htmlQuot = []byte(""") // shorter than """
|
|
||||||
htmlApos = []byte("'") // shorter than "'" and apos was not in HTML until HTML5
|
|
||||||
htmlAmp = []byte("&")
|
|
||||||
htmlLt = []byte("<")
|
|
||||||
htmlGt = []byte(">")
|
|
||||||
)
|
|
||||||
|
|
||||||
// HTMLEscape writes to w the escaped HTML equivalent of the plain text data b.
|
|
||||||
func HTMLEscape(w io.Writer, b []byte) {
|
|
||||||
last := 0
|
|
||||||
for i, c := range b {
|
|
||||||
var html []byte
|
|
||||||
switch c {
|
|
||||||
case '"':
|
|
||||||
html = htmlQuot
|
|
||||||
case '\'':
|
|
||||||
html = htmlApos
|
|
||||||
case '&':
|
|
||||||
html = htmlAmp
|
|
||||||
case '<':
|
|
||||||
html = htmlLt
|
|
||||||
case '>':
|
|
||||||
html = htmlGt
|
|
||||||
default:
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
w.Write(b[last:i])
|
|
||||||
w.Write(html)
|
|
||||||
last = i + 1
|
|
||||||
}
|
|
||||||
w.Write(b[last:])
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTMLEscapeString returns the escaped HTML equivalent of the plain text data s.
|
|
||||||
func HTMLEscapeString(s string) string {
|
|
||||||
// Avoid allocation if we can.
|
|
||||||
if strings.IndexAny(s, `'"&<>`) < 0 {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
var b bytes.Buffer
|
|
||||||
HTMLEscape(&b, []byte(s))
|
|
||||||
return b.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTMLEscaper returns the escaped HTML equivalent of the textual
|
|
||||||
// representation of its arguments.
|
|
||||||
func HTMLEscaper(args ...interface{}) string {
|
|
||||||
return HTMLEscapeString(evalArgs(args))
|
|
||||||
}
|
|
||||||
|
|
||||||
// JavaScript escaping.
|
|
||||||
|
|
||||||
var (
|
|
||||||
jsLowUni = []byte(`\u00`)
|
|
||||||
hex = []byte("0123456789ABCDEF")
|
|
||||||
|
|
||||||
jsBackslash = []byte(`\\`)
|
|
||||||
jsApos = []byte(`\'`)
|
|
||||||
jsQuot = []byte(`\"`)
|
|
||||||
jsLt = []byte(`\x3C`)
|
|
||||||
jsGt = []byte(`\x3E`)
|
|
||||||
)
|
|
||||||
|
|
||||||
// JSEscape writes to w the escaped JavaScript equivalent of the plain text data b.
|
|
||||||
func JSEscape(w io.Writer, b []byte) {
|
|
||||||
last := 0
|
|
||||||
for i := 0; i < len(b); i++ {
|
|
||||||
c := b[i]
|
|
||||||
|
|
||||||
if !jsIsSpecial(rune(c)) {
|
|
||||||
// fast path: nothing to do
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
w.Write(b[last:i])
|
|
||||||
|
|
||||||
if c < utf8.RuneSelf {
|
|
||||||
// Quotes, slashes and angle brackets get quoted.
|
|
||||||
// Control characters get written as \u00XX.
|
|
||||||
switch c {
|
|
||||||
case '\\':
|
|
||||||
w.Write(jsBackslash)
|
|
||||||
case '\'':
|
|
||||||
w.Write(jsApos)
|
|
||||||
case '"':
|
|
||||||
w.Write(jsQuot)
|
|
||||||
case '<':
|
|
||||||
w.Write(jsLt)
|
|
||||||
case '>':
|
|
||||||
w.Write(jsGt)
|
|
||||||
default:
|
|
||||||
w.Write(jsLowUni)
|
|
||||||
t, b := c>>4, c&0x0f
|
|
||||||
w.Write(hex[t : t+1])
|
|
||||||
w.Write(hex[b : b+1])
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Unicode rune.
|
|
||||||
r, size := utf8.DecodeRune(b[i:])
|
|
||||||
if unicode.IsPrint(r) {
|
|
||||||
w.Write(b[i : i+size])
|
|
||||||
} else {
|
|
||||||
fmt.Fprintf(w, "\\u%04X", r)
|
|
||||||
}
|
|
||||||
i += size - 1
|
|
||||||
}
|
|
||||||
last = i + 1
|
|
||||||
}
|
|
||||||
w.Write(b[last:])
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSEscapeString returns the escaped JavaScript equivalent of the plain text data s.
|
|
||||||
func JSEscapeString(s string) string {
|
|
||||||
// Avoid allocation if we can.
|
|
||||||
if strings.IndexFunc(s, jsIsSpecial) < 0 {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
var b bytes.Buffer
|
|
||||||
JSEscape(&b, []byte(s))
|
|
||||||
return b.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func jsIsSpecial(r rune) bool {
|
|
||||||
switch r {
|
|
||||||
case '\\', '\'', '"', '<', '>':
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return r < ' ' || utf8.RuneSelf <= r
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSEscaper returns the escaped JavaScript equivalent of the textual
|
|
||||||
// representation of its arguments.
|
|
||||||
func JSEscaper(args ...interface{}) string {
|
|
||||||
return JSEscapeString(evalArgs(args))
|
|
||||||
}
|
|
||||||
|
|
||||||
// URLQueryEscaper returns the escaped value of the textual representation of
|
|
||||||
// its arguments in a form suitable for embedding in a URL query.
|
|
||||||
func URLQueryEscaper(args ...interface{}) string {
|
|
||||||
return url.QueryEscape(evalArgs(args))
|
|
||||||
}
|
|
||||||
|
|
||||||
// evalArgs formats the list of arguments into a string. It is therefore equivalent to
|
|
||||||
// fmt.Sprint(args...)
|
|
||||||
// except that each argument is indirected (if a pointer), as required,
|
|
||||||
// using the same rules as the default string evaluation during template
|
|
||||||
// execution.
|
|
||||||
func evalArgs(args []interface{}) string {
|
|
||||||
ok := false
|
|
||||||
var s string
|
|
||||||
// Fast path for simple common case.
|
|
||||||
if len(args) == 1 {
|
|
||||||
s, ok = args[0].(string)
|
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
for i, arg := range args {
|
|
||||||
a, ok := printableValue(reflect.ValueOf(arg))
|
|
||||||
if ok {
|
|
||||||
args[i] = a
|
|
||||||
} // else left fmt do its thing
|
|
||||||
}
|
|
||||||
s = fmt.Sprint(args...)
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
1
vendor/github.com/alecthomas/template/go.mod
generated
vendored
1
vendor/github.com/alecthomas/template/go.mod
generated
vendored
|
@ -1 +0,0 @@
|
||||||
module github.com/alecthomas/template
|
|
108
vendor/github.com/alecthomas/template/helper.go
generated
vendored
108
vendor/github.com/alecthomas/template/helper.go
generated
vendored
|
@ -1,108 +0,0 @@
|
||||||
// Copyright 2011 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// Helper functions to make constructing templates easier.
|
|
||||||
|
|
||||||
package template
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"path/filepath"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Functions and methods to parse templates.
|
|
||||||
|
|
||||||
// Must is a helper that wraps a call to a function returning (*Template, error)
|
|
||||||
// and panics if the error is non-nil. It is intended for use in variable
|
|
||||||
// initializations such as
|
|
||||||
// var t = template.Must(template.New("name").Parse("text"))
|
|
||||||
func Must(t *Template, err error) *Template {
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseFiles creates a new Template and parses the template definitions from
|
|
||||||
// the named files. The returned template's name will have the (base) name and
|
|
||||||
// (parsed) contents of the first file. There must be at least one file.
|
|
||||||
// If an error occurs, parsing stops and the returned *Template is nil.
|
|
||||||
func ParseFiles(filenames ...string) (*Template, error) {
|
|
||||||
return parseFiles(nil, filenames...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseFiles parses the named files and associates the resulting templates with
|
|
||||||
// t. If an error occurs, parsing stops and the returned template is nil;
|
|
||||||
// otherwise it is t. There must be at least one file.
|
|
||||||
func (t *Template) ParseFiles(filenames ...string) (*Template, error) {
|
|
||||||
return parseFiles(t, filenames...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseFiles is the helper for the method and function. If the argument
|
|
||||||
// template is nil, it is created from the first file.
|
|
||||||
func parseFiles(t *Template, filenames ...string) (*Template, error) {
|
|
||||||
if len(filenames) == 0 {
|
|
||||||
// Not really a problem, but be consistent.
|
|
||||||
return nil, fmt.Errorf("template: no files named in call to ParseFiles")
|
|
||||||
}
|
|
||||||
for _, filename := range filenames {
|
|
||||||
b, err := ioutil.ReadFile(filename)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
s := string(b)
|
|
||||||
name := filepath.Base(filename)
|
|
||||||
// First template becomes return value if not already defined,
|
|
||||||
// and we use that one for subsequent New calls to associate
|
|
||||||
// all the templates together. Also, if this file has the same name
|
|
||||||
// as t, this file becomes the contents of t, so
|
|
||||||
// t, err := New(name).Funcs(xxx).ParseFiles(name)
|
|
||||||
// works. Otherwise we create a new template associated with t.
|
|
||||||
var tmpl *Template
|
|
||||||
if t == nil {
|
|
||||||
t = New(name)
|
|
||||||
}
|
|
||||||
if name == t.Name() {
|
|
||||||
tmpl = t
|
|
||||||
} else {
|
|
||||||
tmpl = t.New(name)
|
|
||||||
}
|
|
||||||
_, err = tmpl.Parse(s)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return t, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseGlob creates a new Template and parses the template definitions from the
|
|
||||||
// files identified by the pattern, which must match at least one file. The
|
|
||||||
// returned template will have the (base) name and (parsed) contents of the
|
|
||||||
// first file matched by the pattern. ParseGlob is equivalent to calling
|
|
||||||
// ParseFiles with the list of files matched by the pattern.
|
|
||||||
func ParseGlob(pattern string) (*Template, error) {
|
|
||||||
return parseGlob(nil, pattern)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseGlob parses the template definitions in the files identified by the
|
|
||||||
// pattern and associates the resulting templates with t. The pattern is
|
|
||||||
// processed by filepath.Glob and must match at least one file. ParseGlob is
|
|
||||||
// equivalent to calling t.ParseFiles with the list of files matched by the
|
|
||||||
// pattern.
|
|
||||||
func (t *Template) ParseGlob(pattern string) (*Template, error) {
|
|
||||||
return parseGlob(t, pattern)
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseGlob is the implementation of the function and method ParseGlob.
|
|
||||||
func parseGlob(t *Template, pattern string) (*Template, error) {
|
|
||||||
filenames, err := filepath.Glob(pattern)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if len(filenames) == 0 {
|
|
||||||
return nil, fmt.Errorf("template: pattern matches no files: %#q", pattern)
|
|
||||||
}
|
|
||||||
return parseFiles(t, filenames...)
|
|
||||||
}
|
|
556
vendor/github.com/alecthomas/template/parse/lex.go
generated
vendored
556
vendor/github.com/alecthomas/template/parse/lex.go
generated
vendored
|
@ -1,556 +0,0 @@
|
||||||
// Copyright 2011 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package parse
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"unicode"
|
|
||||||
"unicode/utf8"
|
|
||||||
)
|
|
||||||
|
|
||||||
// item represents a token or text string returned from the scanner.
|
|
||||||
type item struct {
|
|
||||||
typ itemType // The type of this item.
|
|
||||||
pos Pos // The starting position, in bytes, of this item in the input string.
|
|
||||||
val string // The value of this item.
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i item) String() string {
|
|
||||||
switch {
|
|
||||||
case i.typ == itemEOF:
|
|
||||||
return "EOF"
|
|
||||||
case i.typ == itemError:
|
|
||||||
return i.val
|
|
||||||
case i.typ > itemKeyword:
|
|
||||||
return fmt.Sprintf("<%s>", i.val)
|
|
||||||
case len(i.val) > 10:
|
|
||||||
return fmt.Sprintf("%.10q...", i.val)
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%q", i.val)
|
|
||||||
}
|
|
||||||
|
|
||||||
// itemType identifies the type of lex items.
|
|
||||||
type itemType int
|
|
||||||
|
|
||||||
const (
|
|
||||||
itemError itemType = iota // error occurred; value is text of error
|
|
||||||
itemBool // boolean constant
|
|
||||||
itemChar // printable ASCII character; grab bag for comma etc.
|
|
||||||
itemCharConstant // character constant
|
|
||||||
itemComplex // complex constant (1+2i); imaginary is just a number
|
|
||||||
itemColonEquals // colon-equals (':=') introducing a declaration
|
|
||||||
itemEOF
|
|
||||||
itemField // alphanumeric identifier starting with '.'
|
|
||||||
itemIdentifier // alphanumeric identifier not starting with '.'
|
|
||||||
itemLeftDelim // left action delimiter
|
|
||||||
itemLeftParen // '(' inside action
|
|
||||||
itemNumber // simple number, including imaginary
|
|
||||||
itemPipe // pipe symbol
|
|
||||||
itemRawString // raw quoted string (includes quotes)
|
|
||||||
itemRightDelim // right action delimiter
|
|
||||||
itemElideNewline // elide newline after right delim
|
|
||||||
itemRightParen // ')' inside action
|
|
||||||
itemSpace // run of spaces separating arguments
|
|
||||||
itemString // quoted string (includes quotes)
|
|
||||||
itemText // plain text
|
|
||||||
itemVariable // variable starting with '$', such as '$' or '$1' or '$hello'
|
|
||||||
// Keywords appear after all the rest.
|
|
||||||
itemKeyword // used only to delimit the keywords
|
|
||||||
itemDot // the cursor, spelled '.'
|
|
||||||
itemDefine // define keyword
|
|
||||||
itemElse // else keyword
|
|
||||||
itemEnd // end keyword
|
|
||||||
itemIf // if keyword
|
|
||||||
itemNil // the untyped nil constant, easiest to treat as a keyword
|
|
||||||
itemRange // range keyword
|
|
||||||
itemTemplate // template keyword
|
|
||||||
itemWith // with keyword
|
|
||||||
)
|
|
||||||
|
|
||||||
var key = map[string]itemType{
|
|
||||||
".": itemDot,
|
|
||||||
"define": itemDefine,
|
|
||||||
"else": itemElse,
|
|
||||||
"end": itemEnd,
|
|
||||||
"if": itemIf,
|
|
||||||
"range": itemRange,
|
|
||||||
"nil": itemNil,
|
|
||||||
"template": itemTemplate,
|
|
||||||
"with": itemWith,
|
|
||||||
}
|
|
||||||
|
|
||||||
const eof = -1
|
|
||||||
|
|
||||||
// stateFn represents the state of the scanner as a function that returns the next state.
|
|
||||||
type stateFn func(*lexer) stateFn
|
|
||||||
|
|
||||||
// lexer holds the state of the scanner.
|
|
||||||
type lexer struct {
|
|
||||||
name string // the name of the input; used only for error reports
|
|
||||||
input string // the string being scanned
|
|
||||||
leftDelim string // start of action
|
|
||||||
rightDelim string // end of action
|
|
||||||
state stateFn // the next lexing function to enter
|
|
||||||
pos Pos // current position in the input
|
|
||||||
start Pos // start position of this item
|
|
||||||
width Pos // width of last rune read from input
|
|
||||||
lastPos Pos // position of most recent item returned by nextItem
|
|
||||||
items chan item // channel of scanned items
|
|
||||||
parenDepth int // nesting depth of ( ) exprs
|
|
||||||
}
|
|
||||||
|
|
||||||
// next returns the next rune in the input.
|
|
||||||
func (l *lexer) next() rune {
|
|
||||||
if int(l.pos) >= len(l.input) {
|
|
||||||
l.width = 0
|
|
||||||
return eof
|
|
||||||
}
|
|
||||||
r, w := utf8.DecodeRuneInString(l.input[l.pos:])
|
|
||||||
l.width = Pos(w)
|
|
||||||
l.pos += l.width
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
|
|
||||||
// peek returns but does not consume the next rune in the input.
|
|
||||||
func (l *lexer) peek() rune {
|
|
||||||
r := l.next()
|
|
||||||
l.backup()
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
|
|
||||||
// backup steps back one rune. Can only be called once per call of next.
|
|
||||||
func (l *lexer) backup() {
|
|
||||||
l.pos -= l.width
|
|
||||||
}
|
|
||||||
|
|
||||||
// emit passes an item back to the client.
|
|
||||||
func (l *lexer) emit(t itemType) {
|
|
||||||
l.items <- item{t, l.start, l.input[l.start:l.pos]}
|
|
||||||
l.start = l.pos
|
|
||||||
}
|
|
||||||
|
|
||||||
// ignore skips over the pending input before this point.
|
|
||||||
func (l *lexer) ignore() {
|
|
||||||
l.start = l.pos
|
|
||||||
}
|
|
||||||
|
|
||||||
// accept consumes the next rune if it's from the valid set.
|
|
||||||
func (l *lexer) accept(valid string) bool {
|
|
||||||
if strings.IndexRune(valid, l.next()) >= 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
l.backup()
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// acceptRun consumes a run of runes from the valid set.
|
|
||||||
func (l *lexer) acceptRun(valid string) {
|
|
||||||
for strings.IndexRune(valid, l.next()) >= 0 {
|
|
||||||
}
|
|
||||||
l.backup()
|
|
||||||
}
|
|
||||||
|
|
||||||
// lineNumber reports which line we're on, based on the position of
|
|
||||||
// the previous item returned by nextItem. Doing it this way
|
|
||||||
// means we don't have to worry about peek double counting.
|
|
||||||
func (l *lexer) lineNumber() int {
|
|
||||||
return 1 + strings.Count(l.input[:l.lastPos], "\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
// errorf returns an error token and terminates the scan by passing
|
|
||||||
// back a nil pointer that will be the next state, terminating l.nextItem.
|
|
||||||
func (l *lexer) errorf(format string, args ...interface{}) stateFn {
|
|
||||||
l.items <- item{itemError, l.start, fmt.Sprintf(format, args...)}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// nextItem returns the next item from the input.
|
|
||||||
func (l *lexer) nextItem() item {
|
|
||||||
item := <-l.items
|
|
||||||
l.lastPos = item.pos
|
|
||||||
return item
|
|
||||||
}
|
|
||||||
|
|
||||||
// lex creates a new scanner for the input string.
|
|
||||||
func lex(name, input, left, right string) *lexer {
|
|
||||||
if left == "" {
|
|
||||||
left = leftDelim
|
|
||||||
}
|
|
||||||
if right == "" {
|
|
||||||
right = rightDelim
|
|
||||||
}
|
|
||||||
l := &lexer{
|
|
||||||
name: name,
|
|
||||||
input: input,
|
|
||||||
leftDelim: left,
|
|
||||||
rightDelim: right,
|
|
||||||
items: make(chan item),
|
|
||||||
}
|
|
||||||
go l.run()
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
|
|
||||||
// run runs the state machine for the lexer.
|
|
||||||
func (l *lexer) run() {
|
|
||||||
for l.state = lexText; l.state != nil; {
|
|
||||||
l.state = l.state(l)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// state functions
|
|
||||||
|
|
||||||
const (
|
|
||||||
leftDelim = "{{"
|
|
||||||
rightDelim = "}}"
|
|
||||||
leftComment = "/*"
|
|
||||||
rightComment = "*/"
|
|
||||||
)
|
|
||||||
|
|
||||||
// lexText scans until an opening action delimiter, "{{".
|
|
||||||
func lexText(l *lexer) stateFn {
|
|
||||||
for {
|
|
||||||
if strings.HasPrefix(l.input[l.pos:], l.leftDelim) {
|
|
||||||
if l.pos > l.start {
|
|
||||||
l.emit(itemText)
|
|
||||||
}
|
|
||||||
return lexLeftDelim
|
|
||||||
}
|
|
||||||
if l.next() == eof {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Correctly reached EOF.
|
|
||||||
if l.pos > l.start {
|
|
||||||
l.emit(itemText)
|
|
||||||
}
|
|
||||||
l.emit(itemEOF)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// lexLeftDelim scans the left delimiter, which is known to be present.
|
|
||||||
func lexLeftDelim(l *lexer) stateFn {
|
|
||||||
l.pos += Pos(len(l.leftDelim))
|
|
||||||
if strings.HasPrefix(l.input[l.pos:], leftComment) {
|
|
||||||
return lexComment
|
|
||||||
}
|
|
||||||
l.emit(itemLeftDelim)
|
|
||||||
l.parenDepth = 0
|
|
||||||
return lexInsideAction
|
|
||||||
}
|
|
||||||
|
|
||||||
// lexComment scans a comment. The left comment marker is known to be present.
|
|
||||||
func lexComment(l *lexer) stateFn {
|
|
||||||
l.pos += Pos(len(leftComment))
|
|
||||||
i := strings.Index(l.input[l.pos:], rightComment)
|
|
||||||
if i < 0 {
|
|
||||||
return l.errorf("unclosed comment")
|
|
||||||
}
|
|
||||||
l.pos += Pos(i + len(rightComment))
|
|
||||||
if !strings.HasPrefix(l.input[l.pos:], l.rightDelim) {
|
|
||||||
return l.errorf("comment ends before closing delimiter")
|
|
||||||
|
|
||||||
}
|
|
||||||
l.pos += Pos(len(l.rightDelim))
|
|
||||||
l.ignore()
|
|
||||||
return lexText
|
|
||||||
}
|
|
||||||
|
|
||||||
// lexRightDelim scans the right delimiter, which is known to be present.
|
|
||||||
func lexRightDelim(l *lexer) stateFn {
|
|
||||||
l.pos += Pos(len(l.rightDelim))
|
|
||||||
l.emit(itemRightDelim)
|
|
||||||
if l.peek() == '\\' {
|
|
||||||
l.pos++
|
|
||||||
l.emit(itemElideNewline)
|
|
||||||
}
|
|
||||||
return lexText
|
|
||||||
}
|
|
||||||
|
|
||||||
// lexInsideAction scans the elements inside action delimiters.
|
|
||||||
func lexInsideAction(l *lexer) stateFn {
|
|
||||||
// Either number, quoted string, or identifier.
|
|
||||||
// Spaces separate arguments; runs of spaces turn into itemSpace.
|
|
||||||
// Pipe symbols separate and are emitted.
|
|
||||||
if strings.HasPrefix(l.input[l.pos:], l.rightDelim+"\\") || strings.HasPrefix(l.input[l.pos:], l.rightDelim) {
|
|
||||||
if l.parenDepth == 0 {
|
|
||||||
return lexRightDelim
|
|
||||||
}
|
|
||||||
return l.errorf("unclosed left paren")
|
|
||||||
}
|
|
||||||
switch r := l.next(); {
|
|
||||||
case r == eof || isEndOfLine(r):
|
|
||||||
return l.errorf("unclosed action")
|
|
||||||
case isSpace(r):
|
|
||||||
return lexSpace
|
|
||||||
case r == ':':
|
|
||||||
if l.next() != '=' {
|
|
||||||
return l.errorf("expected :=")
|
|
||||||
}
|
|
||||||
l.emit(itemColonEquals)
|
|
||||||
case r == '|':
|
|
||||||
l.emit(itemPipe)
|
|
||||||
case r == '"':
|
|
||||||
return lexQuote
|
|
||||||
case r == '`':
|
|
||||||
return lexRawQuote
|
|
||||||
case r == '$':
|
|
||||||
return lexVariable
|
|
||||||
case r == '\'':
|
|
||||||
return lexChar
|
|
||||||
case r == '.':
|
|
||||||
// special look-ahead for ".field" so we don't break l.backup().
|
|
||||||
if l.pos < Pos(len(l.input)) {
|
|
||||||
r := l.input[l.pos]
|
|
||||||
if r < '0' || '9' < r {
|
|
||||||
return lexField
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fallthrough // '.' can start a number.
|
|
||||||
case r == '+' || r == '-' || ('0' <= r && r <= '9'):
|
|
||||||
l.backup()
|
|
||||||
return lexNumber
|
|
||||||
case isAlphaNumeric(r):
|
|
||||||
l.backup()
|
|
||||||
return lexIdentifier
|
|
||||||
case r == '(':
|
|
||||||
l.emit(itemLeftParen)
|
|
||||||
l.parenDepth++
|
|
||||||
return lexInsideAction
|
|
||||||
case r == ')':
|
|
||||||
l.emit(itemRightParen)
|
|
||||||
l.parenDepth--
|
|
||||||
if l.parenDepth < 0 {
|
|
||||||
return l.errorf("unexpected right paren %#U", r)
|
|
||||||
}
|
|
||||||
return lexInsideAction
|
|
||||||
case r <= unicode.MaxASCII && unicode.IsPrint(r):
|
|
||||||
l.emit(itemChar)
|
|
||||||
return lexInsideAction
|
|
||||||
default:
|
|
||||||
return l.errorf("unrecognized character in action: %#U", r)
|
|
||||||
}
|
|
||||||
return lexInsideAction
|
|
||||||
}
|
|
||||||
|
|
||||||
// lexSpace scans a run of space characters.
|
|
||||||
// One space has already been seen.
|
|
||||||
func lexSpace(l *lexer) stateFn {
|
|
||||||
for isSpace(l.peek()) {
|
|
||||||
l.next()
|
|
||||||
}
|
|
||||||
l.emit(itemSpace)
|
|
||||||
return lexInsideAction
|
|
||||||
}
|
|
||||||
|
|
||||||
// lexIdentifier scans an alphanumeric.
|
|
||||||
func lexIdentifier(l *lexer) stateFn {
|
|
||||||
Loop:
|
|
||||||
for {
|
|
||||||
switch r := l.next(); {
|
|
||||||
case isAlphaNumeric(r):
|
|
||||||
// absorb.
|
|
||||||
default:
|
|
||||||
l.backup()
|
|
||||||
word := l.input[l.start:l.pos]
|
|
||||||
if !l.atTerminator() {
|
|
||||||
return l.errorf("bad character %#U", r)
|
|
||||||
}
|
|
||||||
switch {
|
|
||||||
case key[word] > itemKeyword:
|
|
||||||
l.emit(key[word])
|
|
||||||
case word[0] == '.':
|
|
||||||
l.emit(itemField)
|
|
||||||
case word == "true", word == "false":
|
|
||||||
l.emit(itemBool)
|
|
||||||
default:
|
|
||||||
l.emit(itemIdentifier)
|
|
||||||
}
|
|
||||||
break Loop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return lexInsideAction
|
|
||||||
}
|
|
||||||
|
|
||||||
// lexField scans a field: .Alphanumeric.
|
|
||||||
// The . has been scanned.
|
|
||||||
func lexField(l *lexer) stateFn {
|
|
||||||
return lexFieldOrVariable(l, itemField)
|
|
||||||
}
|
|
||||||
|
|
||||||
// lexVariable scans a Variable: $Alphanumeric.
|
|
||||||
// The $ has been scanned.
|
|
||||||
func lexVariable(l *lexer) stateFn {
|
|
||||||
if l.atTerminator() { // Nothing interesting follows -> "$".
|
|
||||||
l.emit(itemVariable)
|
|
||||||
return lexInsideAction
|
|
||||||
}
|
|
||||||
return lexFieldOrVariable(l, itemVariable)
|
|
||||||
}
|
|
||||||
|
|
||||||
// lexVariable scans a field or variable: [.$]Alphanumeric.
|
|
||||||
// The . or $ has been scanned.
|
|
||||||
func lexFieldOrVariable(l *lexer, typ itemType) stateFn {
|
|
||||||
if l.atTerminator() { // Nothing interesting follows -> "." or "$".
|
|
||||||
if typ == itemVariable {
|
|
||||||
l.emit(itemVariable)
|
|
||||||
} else {
|
|
||||||
l.emit(itemDot)
|
|
||||||
}
|
|
||||||
return lexInsideAction
|
|
||||||
}
|
|
||||||
var r rune
|
|
||||||
for {
|
|
||||||
r = l.next()
|
|
||||||
if !isAlphaNumeric(r) {
|
|
||||||
l.backup()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !l.atTerminator() {
|
|
||||||
return l.errorf("bad character %#U", r)
|
|
||||||
}
|
|
||||||
l.emit(typ)
|
|
||||||
return lexInsideAction
|
|
||||||
}
|
|
||||||
|
|
||||||
// atTerminator reports whether the input is at valid termination character to
|
|
||||||
// appear after an identifier. Breaks .X.Y into two pieces. Also catches cases
|
|
||||||
// like "$x+2" not being acceptable without a space, in case we decide one
|
|
||||||
// day to implement arithmetic.
|
|
||||||
func (l *lexer) atTerminator() bool {
|
|
||||||
r := l.peek()
|
|
||||||
if isSpace(r) || isEndOfLine(r) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
switch r {
|
|
||||||
case eof, '.', ',', '|', ':', ')', '(':
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// Does r start the delimiter? This can be ambiguous (with delim=="//", $x/2 will
|
|
||||||
// succeed but should fail) but only in extremely rare cases caused by willfully
|
|
||||||
// bad choice of delimiter.
|
|
||||||
if rd, _ := utf8.DecodeRuneInString(l.rightDelim); rd == r {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// lexChar scans a character constant. The initial quote is already
|
|
||||||
// scanned. Syntax checking is done by the parser.
|
|
||||||
func lexChar(l *lexer) stateFn {
|
|
||||||
Loop:
|
|
||||||
for {
|
|
||||||
switch l.next() {
|
|
||||||
case '\\':
|
|
||||||
if r := l.next(); r != eof && r != '\n' {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
fallthrough
|
|
||||||
case eof, '\n':
|
|
||||||
return l.errorf("unterminated character constant")
|
|
||||||
case '\'':
|
|
||||||
break Loop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
l.emit(itemCharConstant)
|
|
||||||
return lexInsideAction
|
|
||||||
}
|
|
||||||
|
|
||||||
// lexNumber scans a number: decimal, octal, hex, float, or imaginary. This
|
|
||||||
// isn't a perfect number scanner - for instance it accepts "." and "0x0.2"
|
|
||||||
// and "089" - but when it's wrong the input is invalid and the parser (via
|
|
||||||
// strconv) will notice.
|
|
||||||
func lexNumber(l *lexer) stateFn {
|
|
||||||
if !l.scanNumber() {
|
|
||||||
return l.errorf("bad number syntax: %q", l.input[l.start:l.pos])
|
|
||||||
}
|
|
||||||
if sign := l.peek(); sign == '+' || sign == '-' {
|
|
||||||
// Complex: 1+2i. No spaces, must end in 'i'.
|
|
||||||
if !l.scanNumber() || l.input[l.pos-1] != 'i' {
|
|
||||||
return l.errorf("bad number syntax: %q", l.input[l.start:l.pos])
|
|
||||||
}
|
|
||||||
l.emit(itemComplex)
|
|
||||||
} else {
|
|
||||||
l.emit(itemNumber)
|
|
||||||
}
|
|
||||||
return lexInsideAction
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *lexer) scanNumber() bool {
|
|
||||||
// Optional leading sign.
|
|
||||||
l.accept("+-")
|
|
||||||
// Is it hex?
|
|
||||||
digits := "0123456789"
|
|
||||||
if l.accept("0") && l.accept("xX") {
|
|
||||||
digits = "0123456789abcdefABCDEF"
|
|
||||||
}
|
|
||||||
l.acceptRun(digits)
|
|
||||||
if l.accept(".") {
|
|
||||||
l.acceptRun(digits)
|
|
||||||
}
|
|
||||||
if l.accept("eE") {
|
|
||||||
l.accept("+-")
|
|
||||||
l.acceptRun("0123456789")
|
|
||||||
}
|
|
||||||
// Is it imaginary?
|
|
||||||
l.accept("i")
|
|
||||||
// Next thing mustn't be alphanumeric.
|
|
||||||
if isAlphaNumeric(l.peek()) {
|
|
||||||
l.next()
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// lexQuote scans a quoted string.
|
|
||||||
func lexQuote(l *lexer) stateFn {
|
|
||||||
Loop:
|
|
||||||
for {
|
|
||||||
switch l.next() {
|
|
||||||
case '\\':
|
|
||||||
if r := l.next(); r != eof && r != '\n' {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
fallthrough
|
|
||||||
case eof, '\n':
|
|
||||||
return l.errorf("unterminated quoted string")
|
|
||||||
case '"':
|
|
||||||
break Loop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
l.emit(itemString)
|
|
||||||
return lexInsideAction
|
|
||||||
}
|
|
||||||
|
|
||||||
// lexRawQuote scans a raw quoted string.
|
|
||||||
func lexRawQuote(l *lexer) stateFn {
|
|
||||||
Loop:
|
|
||||||
for {
|
|
||||||
switch l.next() {
|
|
||||||
case eof, '\n':
|
|
||||||
return l.errorf("unterminated raw quoted string")
|
|
||||||
case '`':
|
|
||||||
break Loop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
l.emit(itemRawString)
|
|
||||||
return lexInsideAction
|
|
||||||
}
|
|
||||||
|
|
||||||
// isSpace reports whether r is a space character.
|
|
||||||
func isSpace(r rune) bool {
|
|
||||||
return r == ' ' || r == '\t'
|
|
||||||
}
|
|
||||||
|
|
||||||
// isEndOfLine reports whether r is an end-of-line character.
|
|
||||||
func isEndOfLine(r rune) bool {
|
|
||||||
return r == '\r' || r == '\n'
|
|
||||||
}
|
|
||||||
|
|
||||||
// isAlphaNumeric reports whether r is an alphabetic, digit, or underscore.
|
|
||||||
func isAlphaNumeric(r rune) bool {
|
|
||||||
return r == '_' || unicode.IsLetter(r) || unicode.IsDigit(r)
|
|
||||||
}
|
|
834
vendor/github.com/alecthomas/template/parse/node.go
generated
vendored
834
vendor/github.com/alecthomas/template/parse/node.go
generated
vendored
|
@ -1,834 +0,0 @@
|
||||||
// Copyright 2011 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// Parse nodes.
|
|
||||||
|
|
||||||
package parse
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
var textFormat = "%s" // Changed to "%q" in tests for better error messages.
|
|
||||||
|
|
||||||
// A Node is an element in the parse tree. The interface is trivial.
|
|
||||||
// The interface contains an unexported method so that only
|
|
||||||
// types local to this package can satisfy it.
|
|
||||||
type Node interface {
|
|
||||||
Type() NodeType
|
|
||||||
String() string
|
|
||||||
// Copy does a deep copy of the Node and all its components.
|
|
||||||
// To avoid type assertions, some XxxNodes also have specialized
|
|
||||||
// CopyXxx methods that return *XxxNode.
|
|
||||||
Copy() Node
|
|
||||||
Position() Pos // byte position of start of node in full original input string
|
|
||||||
// tree returns the containing *Tree.
|
|
||||||
// It is unexported so all implementations of Node are in this package.
|
|
||||||
tree() *Tree
|
|
||||||
}
|
|
||||||
|
|
||||||
// NodeType identifies the type of a parse tree node.
|
|
||||||
type NodeType int
|
|
||||||
|
|
||||||
// Pos represents a byte position in the original input text from which
|
|
||||||
// this template was parsed.
|
|
||||||
type Pos int
|
|
||||||
|
|
||||||
func (p Pos) Position() Pos {
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type returns itself and provides an easy default implementation
|
|
||||||
// for embedding in a Node. Embedded in all non-trivial Nodes.
|
|
||||||
func (t NodeType) Type() NodeType {
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
NodeText NodeType = iota // Plain text.
|
|
||||||
NodeAction // A non-control action such as a field evaluation.
|
|
||||||
NodeBool // A boolean constant.
|
|
||||||
NodeChain // A sequence of field accesses.
|
|
||||||
NodeCommand // An element of a pipeline.
|
|
||||||
NodeDot // The cursor, dot.
|
|
||||||
nodeElse // An else action. Not added to tree.
|
|
||||||
nodeEnd // An end action. Not added to tree.
|
|
||||||
NodeField // A field or method name.
|
|
||||||
NodeIdentifier // An identifier; always a function name.
|
|
||||||
NodeIf // An if action.
|
|
||||||
NodeList // A list of Nodes.
|
|
||||||
NodeNil // An untyped nil constant.
|
|
||||||
NodeNumber // A numerical constant.
|
|
||||||
NodePipe // A pipeline of commands.
|
|
||||||
NodeRange // A range action.
|
|
||||||
NodeString // A string constant.
|
|
||||||
NodeTemplate // A template invocation action.
|
|
||||||
NodeVariable // A $ variable.
|
|
||||||
NodeWith // A with action.
|
|
||||||
)
|
|
||||||
|
|
||||||
// Nodes.
|
|
||||||
|
|
||||||
// ListNode holds a sequence of nodes.
|
|
||||||
type ListNode struct {
|
|
||||||
NodeType
|
|
||||||
Pos
|
|
||||||
tr *Tree
|
|
||||||
Nodes []Node // The element nodes in lexical order.
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Tree) newList(pos Pos) *ListNode {
|
|
||||||
return &ListNode{tr: t, NodeType: NodeList, Pos: pos}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *ListNode) append(n Node) {
|
|
||||||
l.Nodes = append(l.Nodes, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *ListNode) tree() *Tree {
|
|
||||||
return l.tr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *ListNode) String() string {
|
|
||||||
b := new(bytes.Buffer)
|
|
||||||
for _, n := range l.Nodes {
|
|
||||||
fmt.Fprint(b, n)
|
|
||||||
}
|
|
||||||
return b.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *ListNode) CopyList() *ListNode {
|
|
||||||
if l == nil {
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
n := l.tr.newList(l.Pos)
|
|
||||||
for _, elem := range l.Nodes {
|
|
||||||
n.append(elem.Copy())
|
|
||||||
}
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *ListNode) Copy() Node {
|
|
||||||
return l.CopyList()
|
|
||||||
}
|
|
||||||
|
|
||||||
// TextNode holds plain text.
|
|
||||||
type TextNode struct {
|
|
||||||
NodeType
|
|
||||||
Pos
|
|
||||||
tr *Tree
|
|
||||||
Text []byte // The text; may span newlines.
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Tree) newText(pos Pos, text string) *TextNode {
|
|
||||||
return &TextNode{tr: t, NodeType: NodeText, Pos: pos, Text: []byte(text)}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *TextNode) String() string {
|
|
||||||
return fmt.Sprintf(textFormat, t.Text)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *TextNode) tree() *Tree {
|
|
||||||
return t.tr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *TextNode) Copy() Node {
|
|
||||||
return &TextNode{tr: t.tr, NodeType: NodeText, Pos: t.Pos, Text: append([]byte{}, t.Text...)}
|
|
||||||
}
|
|
||||||
|
|
||||||
// PipeNode holds a pipeline with optional declaration
|
|
||||||
type PipeNode struct {
|
|
||||||
NodeType
|
|
||||||
Pos
|
|
||||||
tr *Tree
|
|
||||||
Line int // The line number in the input (deprecated; kept for compatibility)
|
|
||||||
Decl []*VariableNode // Variable declarations in lexical order.
|
|
||||||
Cmds []*CommandNode // The commands in lexical order.
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Tree) newPipeline(pos Pos, line int, decl []*VariableNode) *PipeNode {
|
|
||||||
return &PipeNode{tr: t, NodeType: NodePipe, Pos: pos, Line: line, Decl: decl}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *PipeNode) append(command *CommandNode) {
|
|
||||||
p.Cmds = append(p.Cmds, command)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *PipeNode) String() string {
|
|
||||||
s := ""
|
|
||||||
if len(p.Decl) > 0 {
|
|
||||||
for i, v := range p.Decl {
|
|
||||||
if i > 0 {
|
|
||||||
s += ", "
|
|
||||||
}
|
|
||||||
s += v.String()
|
|
||||||
}
|
|
||||||
s += " := "
|
|
||||||
}
|
|
||||||
for i, c := range p.Cmds {
|
|
||||||
if i > 0 {
|
|
||||||
s += " | "
|
|
||||||
}
|
|
||||||
s += c.String()
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *PipeNode) tree() *Tree {
|
|
||||||
return p.tr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *PipeNode) CopyPipe() *PipeNode {
|
|
||||||
if p == nil {
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
var decl []*VariableNode
|
|
||||||
for _, d := range p.Decl {
|
|
||||||
decl = append(decl, d.Copy().(*VariableNode))
|
|
||||||
}
|
|
||||||
n := p.tr.newPipeline(p.Pos, p.Line, decl)
|
|
||||||
for _, c := range p.Cmds {
|
|
||||||
n.append(c.Copy().(*CommandNode))
|
|
||||||
}
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *PipeNode) Copy() Node {
|
|
||||||
return p.CopyPipe()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ActionNode holds an action (something bounded by delimiters).
|
|
||||||
// Control actions have their own nodes; ActionNode represents simple
|
|
||||||
// ones such as field evaluations and parenthesized pipelines.
|
|
||||||
type ActionNode struct {
|
|
||||||
NodeType
|
|
||||||
Pos
|
|
||||||
tr *Tree
|
|
||||||
Line int // The line number in the input (deprecated; kept for compatibility)
|
|
||||||
Pipe *PipeNode // The pipeline in the action.
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Tree) newAction(pos Pos, line int, pipe *PipeNode) *ActionNode {
|
|
||||||
return &ActionNode{tr: t, NodeType: NodeAction, Pos: pos, Line: line, Pipe: pipe}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *ActionNode) String() string {
|
|
||||||
return fmt.Sprintf("{{%s}}", a.Pipe)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *ActionNode) tree() *Tree {
|
|
||||||
return a.tr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *ActionNode) Copy() Node {
|
|
||||||
return a.tr.newAction(a.Pos, a.Line, a.Pipe.CopyPipe())
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// CommandNode holds a command (a pipeline inside an evaluating action).
|
|
||||||
type CommandNode struct {
|
|
||||||
NodeType
|
|
||||||
Pos
|
|
||||||
tr *Tree
|
|
||||||
Args []Node // Arguments in lexical order: Identifier, field, or constant.
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Tree) newCommand(pos Pos) *CommandNode {
|
|
||||||
return &CommandNode{tr: t, NodeType: NodeCommand, Pos: pos}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CommandNode) append(arg Node) {
|
|
||||||
c.Args = append(c.Args, arg)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CommandNode) String() string {
|
|
||||||
s := ""
|
|
||||||
for i, arg := range c.Args {
|
|
||||||
if i > 0 {
|
|
||||||
s += " "
|
|
||||||
}
|
|
||||||
if arg, ok := arg.(*PipeNode); ok {
|
|
||||||
s += "(" + arg.String() + ")"
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
s += arg.String()
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CommandNode) tree() *Tree {
|
|
||||||
return c.tr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CommandNode) Copy() Node {
|
|
||||||
if c == nil {
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
n := c.tr.newCommand(c.Pos)
|
|
||||||
for _, c := range c.Args {
|
|
||||||
n.append(c.Copy())
|
|
||||||
}
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
// IdentifierNode holds an identifier.
|
|
||||||
type IdentifierNode struct {
|
|
||||||
NodeType
|
|
||||||
Pos
|
|
||||||
tr *Tree
|
|
||||||
Ident string // The identifier's name.
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewIdentifier returns a new IdentifierNode with the given identifier name.
|
|
||||||
func NewIdentifier(ident string) *IdentifierNode {
|
|
||||||
return &IdentifierNode{NodeType: NodeIdentifier, Ident: ident}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetPos sets the position. NewIdentifier is a public method so we can't modify its signature.
|
|
||||||
// Chained for convenience.
|
|
||||||
// TODO: fix one day?
|
|
||||||
func (i *IdentifierNode) SetPos(pos Pos) *IdentifierNode {
|
|
||||||
i.Pos = pos
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetTree sets the parent tree for the node. NewIdentifier is a public method so we can't modify its signature.
|
|
||||||
// Chained for convenience.
|
|
||||||
// TODO: fix one day?
|
|
||||||
func (i *IdentifierNode) SetTree(t *Tree) *IdentifierNode {
|
|
||||||
i.tr = t
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *IdentifierNode) String() string {
|
|
||||||
return i.Ident
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *IdentifierNode) tree() *Tree {
|
|
||||||
return i.tr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *IdentifierNode) Copy() Node {
|
|
||||||
return NewIdentifier(i.Ident).SetTree(i.tr).SetPos(i.Pos)
|
|
||||||
}
|
|
||||||
|
|
||||||
// VariableNode holds a list of variable names, possibly with chained field
|
|
||||||
// accesses. The dollar sign is part of the (first) name.
|
|
||||||
type VariableNode struct {
|
|
||||||
NodeType
|
|
||||||
Pos
|
|
||||||
tr *Tree
|
|
||||||
Ident []string // Variable name and fields in lexical order.
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Tree) newVariable(pos Pos, ident string) *VariableNode {
|
|
||||||
return &VariableNode{tr: t, NodeType: NodeVariable, Pos: pos, Ident: strings.Split(ident, ".")}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *VariableNode) String() string {
|
|
||||||
s := ""
|
|
||||||
for i, id := range v.Ident {
|
|
||||||
if i > 0 {
|
|
||||||
s += "."
|
|
||||||
}
|
|
||||||
s += id
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *VariableNode) tree() *Tree {
|
|
||||||
return v.tr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *VariableNode) Copy() Node {
|
|
||||||
return &VariableNode{tr: v.tr, NodeType: NodeVariable, Pos: v.Pos, Ident: append([]string{}, v.Ident...)}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DotNode holds the special identifier '.'.
|
|
||||||
type DotNode struct {
|
|
||||||
NodeType
|
|
||||||
Pos
|
|
||||||
tr *Tree
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Tree) newDot(pos Pos) *DotNode {
|
|
||||||
return &DotNode{tr: t, NodeType: NodeDot, Pos: pos}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DotNode) Type() NodeType {
|
|
||||||
// Override method on embedded NodeType for API compatibility.
|
|
||||||
// TODO: Not really a problem; could change API without effect but
|
|
||||||
// api tool complains.
|
|
||||||
return NodeDot
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DotNode) String() string {
|
|
||||||
return "."
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DotNode) tree() *Tree {
|
|
||||||
return d.tr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DotNode) Copy() Node {
|
|
||||||
return d.tr.newDot(d.Pos)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NilNode holds the special identifier 'nil' representing an untyped nil constant.
|
|
||||||
type NilNode struct {
|
|
||||||
NodeType
|
|
||||||
Pos
|
|
||||||
tr *Tree
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Tree) newNil(pos Pos) *NilNode {
|
|
||||||
return &NilNode{tr: t, NodeType: NodeNil, Pos: pos}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *NilNode) Type() NodeType {
|
|
||||||
// Override method on embedded NodeType for API compatibility.
|
|
||||||
// TODO: Not really a problem; could change API without effect but
|
|
||||||
// api tool complains.
|
|
||||||
return NodeNil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *NilNode) String() string {
|
|
||||||
return "nil"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *NilNode) tree() *Tree {
|
|
||||||
return n.tr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *NilNode) Copy() Node {
|
|
||||||
return n.tr.newNil(n.Pos)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FieldNode holds a field (identifier starting with '.').
|
|
||||||
// The names may be chained ('.x.y').
|
|
||||||
// The period is dropped from each ident.
|
|
||||||
type FieldNode struct {
|
|
||||||
NodeType
|
|
||||||
Pos
|
|
||||||
tr *Tree
|
|
||||||
Ident []string // The identifiers in lexical order.
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Tree) newField(pos Pos, ident string) *FieldNode {
|
|
||||||
return &FieldNode{tr: t, NodeType: NodeField, Pos: pos, Ident: strings.Split(ident[1:], ".")} // [1:] to drop leading period
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FieldNode) String() string {
|
|
||||||
s := ""
|
|
||||||
for _, id := range f.Ident {
|
|
||||||
s += "." + id
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FieldNode) tree() *Tree {
|
|
||||||
return f.tr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FieldNode) Copy() Node {
|
|
||||||
return &FieldNode{tr: f.tr, NodeType: NodeField, Pos: f.Pos, Ident: append([]string{}, f.Ident...)}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ChainNode holds a term followed by a chain of field accesses (identifier starting with '.').
|
|
||||||
// The names may be chained ('.x.y').
|
|
||||||
// The periods are dropped from each ident.
|
|
||||||
type ChainNode struct {
|
|
||||||
NodeType
|
|
||||||
Pos
|
|
||||||
tr *Tree
|
|
||||||
Node Node
|
|
||||||
Field []string // The identifiers in lexical order.
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Tree) newChain(pos Pos, node Node) *ChainNode {
|
|
||||||
return &ChainNode{tr: t, NodeType: NodeChain, Pos: pos, Node: node}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add adds the named field (which should start with a period) to the end of the chain.
|
|
||||||
func (c *ChainNode) Add(field string) {
|
|
||||||
if len(field) == 0 || field[0] != '.' {
|
|
||||||
panic("no dot in field")
|
|
||||||
}
|
|
||||||
field = field[1:] // Remove leading dot.
|
|
||||||
if field == "" {
|
|
||||||
panic("empty field")
|
|
||||||
}
|
|
||||||
c.Field = append(c.Field, field)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ChainNode) String() string {
|
|
||||||
s := c.Node.String()
|
|
||||||
if _, ok := c.Node.(*PipeNode); ok {
|
|
||||||
s = "(" + s + ")"
|
|
||||||
}
|
|
||||||
for _, field := range c.Field {
|
|
||||||
s += "." + field
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ChainNode) tree() *Tree {
|
|
||||||
return c.tr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ChainNode) Copy() Node {
|
|
||||||
return &ChainNode{tr: c.tr, NodeType: NodeChain, Pos: c.Pos, Node: c.Node, Field: append([]string{}, c.Field...)}
|
|
||||||
}
|
|
||||||
|
|
||||||
// BoolNode holds a boolean constant.
|
|
||||||
type BoolNode struct {
|
|
||||||
NodeType
|
|
||||||
Pos
|
|
||||||
tr *Tree
|
|
||||||
True bool // The value of the boolean constant.
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Tree) newBool(pos Pos, true bool) *BoolNode {
|
|
||||||
return &BoolNode{tr: t, NodeType: NodeBool, Pos: pos, True: true}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *BoolNode) String() string {
|
|
||||||
if b.True {
|
|
||||||
return "true"
|
|
||||||
}
|
|
||||||
return "false"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *BoolNode) tree() *Tree {
|
|
||||||
return b.tr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *BoolNode) Copy() Node {
|
|
||||||
return b.tr.newBool(b.Pos, b.True)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NumberNode holds a number: signed or unsigned integer, float, or complex.
|
|
||||||
// The value is parsed and stored under all the types that can represent the value.
|
|
||||||
// This simulates in a small amount of code the behavior of Go's ideal constants.
|
|
||||||
type NumberNode struct {
|
|
||||||
NodeType
|
|
||||||
Pos
|
|
||||||
tr *Tree
|
|
||||||
IsInt bool // Number has an integral value.
|
|
||||||
IsUint bool // Number has an unsigned integral value.
|
|
||||||
IsFloat bool // Number has a floating-point value.
|
|
||||||
IsComplex bool // Number is complex.
|
|
||||||
Int64 int64 // The signed integer value.
|
|
||||||
Uint64 uint64 // The unsigned integer value.
|
|
||||||
Float64 float64 // The floating-point value.
|
|
||||||
Complex128 complex128 // The complex value.
|
|
||||||
Text string // The original textual representation from the input.
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Tree) newNumber(pos Pos, text string, typ itemType) (*NumberNode, error) {
|
|
||||||
n := &NumberNode{tr: t, NodeType: NodeNumber, Pos: pos, Text: text}
|
|
||||||
switch typ {
|
|
||||||
case itemCharConstant:
|
|
||||||
rune, _, tail, err := strconv.UnquoteChar(text[1:], text[0])
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if tail != "'" {
|
|
||||||
return nil, fmt.Errorf("malformed character constant: %s", text)
|
|
||||||
}
|
|
||||||
n.Int64 = int64(rune)
|
|
||||||
n.IsInt = true
|
|
||||||
n.Uint64 = uint64(rune)
|
|
||||||
n.IsUint = true
|
|
||||||
n.Float64 = float64(rune) // odd but those are the rules.
|
|
||||||
n.IsFloat = true
|
|
||||||
return n, nil
|
|
||||||
case itemComplex:
|
|
||||||
// fmt.Sscan can parse the pair, so let it do the work.
|
|
||||||
if _, err := fmt.Sscan(text, &n.Complex128); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
n.IsComplex = true
|
|
||||||
n.simplifyComplex()
|
|
||||||
return n, nil
|
|
||||||
}
|
|
||||||
// Imaginary constants can only be complex unless they are zero.
|
|
||||||
if len(text) > 0 && text[len(text)-1] == 'i' {
|
|
||||||
f, err := strconv.ParseFloat(text[:len(text)-1], 64)
|
|
||||||
if err == nil {
|
|
||||||
n.IsComplex = true
|
|
||||||
n.Complex128 = complex(0, f)
|
|
||||||
n.simplifyComplex()
|
|
||||||
return n, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Do integer test first so we get 0x123 etc.
|
|
||||||
u, err := strconv.ParseUint(text, 0, 64) // will fail for -0; fixed below.
|
|
||||||
if err == nil {
|
|
||||||
n.IsUint = true
|
|
||||||
n.Uint64 = u
|
|
||||||
}
|
|
||||||
i, err := strconv.ParseInt(text, 0, 64)
|
|
||||||
if err == nil {
|
|
||||||
n.IsInt = true
|
|
||||||
n.Int64 = i
|
|
||||||
if i == 0 {
|
|
||||||
n.IsUint = true // in case of -0.
|
|
||||||
n.Uint64 = u
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If an integer extraction succeeded, promote the float.
|
|
||||||
if n.IsInt {
|
|
||||||
n.IsFloat = true
|
|
||||||
n.Float64 = float64(n.Int64)
|
|
||||||
} else if n.IsUint {
|
|
||||||
n.IsFloat = true
|
|
||||||
n.Float64 = float64(n.Uint64)
|
|
||||||
} else {
|
|
||||||
f, err := strconv.ParseFloat(text, 64)
|
|
||||||
if err == nil {
|
|
||||||
n.IsFloat = true
|
|
||||||
n.Float64 = f
|
|
||||||
// If a floating-point extraction succeeded, extract the int if needed.
|
|
||||||
if !n.IsInt && float64(int64(f)) == f {
|
|
||||||
n.IsInt = true
|
|
||||||
n.Int64 = int64(f)
|
|
||||||
}
|
|
||||||
if !n.IsUint && float64(uint64(f)) == f {
|
|
||||||
n.IsUint = true
|
|
||||||
n.Uint64 = uint64(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !n.IsInt && !n.IsUint && !n.IsFloat {
|
|
||||||
return nil, fmt.Errorf("illegal number syntax: %q", text)
|
|
||||||
}
|
|
||||||
return n, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// simplifyComplex pulls out any other types that are represented by the complex number.
|
|
||||||
// These all require that the imaginary part be zero.
|
|
||||||
func (n *NumberNode) simplifyComplex() {
|
|
||||||
n.IsFloat = imag(n.Complex128) == 0
|
|
||||||
if n.IsFloat {
|
|
||||||
n.Float64 = real(n.Complex128)
|
|
||||||
n.IsInt = float64(int64(n.Float64)) == n.Float64
|
|
||||||
if n.IsInt {
|
|
||||||
n.Int64 = int64(n.Float64)
|
|
||||||
}
|
|
||||||
n.IsUint = float64(uint64(n.Float64)) == n.Float64
|
|
||||||
if n.IsUint {
|
|
||||||
n.Uint64 = uint64(n.Float64)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *NumberNode) String() string {
|
|
||||||
return n.Text
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *NumberNode) tree() *Tree {
|
|
||||||
return n.tr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *NumberNode) Copy() Node {
|
|
||||||
nn := new(NumberNode)
|
|
||||||
*nn = *n // Easy, fast, correct.
|
|
||||||
return nn
|
|
||||||
}
|
|
||||||
|
|
||||||
// StringNode holds a string constant. The value has been "unquoted".
|
|
||||||
type StringNode struct {
|
|
||||||
NodeType
|
|
||||||
Pos
|
|
||||||
tr *Tree
|
|
||||||
Quoted string // The original text of the string, with quotes.
|
|
||||||
Text string // The string, after quote processing.
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Tree) newString(pos Pos, orig, text string) *StringNode {
|
|
||||||
return &StringNode{tr: t, NodeType: NodeString, Pos: pos, Quoted: orig, Text: text}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *StringNode) String() string {
|
|
||||||
return s.Quoted
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *StringNode) tree() *Tree {
|
|
||||||
return s.tr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *StringNode) Copy() Node {
|
|
||||||
return s.tr.newString(s.Pos, s.Quoted, s.Text)
|
|
||||||
}
|
|
||||||
|
|
||||||
// endNode represents an {{end}} action.
|
|
||||||
// It does not appear in the final parse tree.
|
|
||||||
type endNode struct {
|
|
||||||
NodeType
|
|
||||||
Pos
|
|
||||||
tr *Tree
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Tree) newEnd(pos Pos) *endNode {
|
|
||||||
return &endNode{tr: t, NodeType: nodeEnd, Pos: pos}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *endNode) String() string {
|
|
||||||
return "{{end}}"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *endNode) tree() *Tree {
|
|
||||||
return e.tr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *endNode) Copy() Node {
|
|
||||||
return e.tr.newEnd(e.Pos)
|
|
||||||
}
|
|
||||||
|
|
||||||
// elseNode represents an {{else}} action. Does not appear in the final tree.
|
|
||||||
type elseNode struct {
|
|
||||||
NodeType
|
|
||||||
Pos
|
|
||||||
tr *Tree
|
|
||||||
Line int // The line number in the input (deprecated; kept for compatibility)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Tree) newElse(pos Pos, line int) *elseNode {
|
|
||||||
return &elseNode{tr: t, NodeType: nodeElse, Pos: pos, Line: line}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *elseNode) Type() NodeType {
|
|
||||||
return nodeElse
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *elseNode) String() string {
|
|
||||||
return "{{else}}"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *elseNode) tree() *Tree {
|
|
||||||
return e.tr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *elseNode) Copy() Node {
|
|
||||||
return e.tr.newElse(e.Pos, e.Line)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BranchNode is the common representation of if, range, and with.
|
|
||||||
type BranchNode struct {
|
|
||||||
NodeType
|
|
||||||
Pos
|
|
||||||
tr *Tree
|
|
||||||
Line int // The line number in the input (deprecated; kept for compatibility)
|
|
||||||
Pipe *PipeNode // The pipeline to be evaluated.
|
|
||||||
List *ListNode // What to execute if the value is non-empty.
|
|
||||||
ElseList *ListNode // What to execute if the value is empty (nil if absent).
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *BranchNode) String() string {
|
|
||||||
name := ""
|
|
||||||
switch b.NodeType {
|
|
||||||
case NodeIf:
|
|
||||||
name = "if"
|
|
||||||
case NodeRange:
|
|
||||||
name = "range"
|
|
||||||
case NodeWith:
|
|
||||||
name = "with"
|
|
||||||
default:
|
|
||||||
panic("unknown branch type")
|
|
||||||
}
|
|
||||||
if b.ElseList != nil {
|
|
||||||
return fmt.Sprintf("{{%s %s}}%s{{else}}%s{{end}}", name, b.Pipe, b.List, b.ElseList)
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("{{%s %s}}%s{{end}}", name, b.Pipe, b.List)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *BranchNode) tree() *Tree {
|
|
||||||
return b.tr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *BranchNode) Copy() Node {
|
|
||||||
switch b.NodeType {
|
|
||||||
case NodeIf:
|
|
||||||
return b.tr.newIf(b.Pos, b.Line, b.Pipe, b.List, b.ElseList)
|
|
||||||
case NodeRange:
|
|
||||||
return b.tr.newRange(b.Pos, b.Line, b.Pipe, b.List, b.ElseList)
|
|
||||||
case NodeWith:
|
|
||||||
return b.tr.newWith(b.Pos, b.Line, b.Pipe, b.List, b.ElseList)
|
|
||||||
default:
|
|
||||||
panic("unknown branch type")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// IfNode represents an {{if}} action and its commands.
|
|
||||||
type IfNode struct {
|
|
||||||
BranchNode
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Tree) newIf(pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) *IfNode {
|
|
||||||
return &IfNode{BranchNode{tr: t, NodeType: NodeIf, Pos: pos, Line: line, Pipe: pipe, List: list, ElseList: elseList}}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *IfNode) Copy() Node {
|
|
||||||
return i.tr.newIf(i.Pos, i.Line, i.Pipe.CopyPipe(), i.List.CopyList(), i.ElseList.CopyList())
|
|
||||||
}
|
|
||||||
|
|
||||||
// RangeNode represents a {{range}} action and its commands.
|
|
||||||
type RangeNode struct {
|
|
||||||
BranchNode
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Tree) newRange(pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) *RangeNode {
|
|
||||||
return &RangeNode{BranchNode{tr: t, NodeType: NodeRange, Pos: pos, Line: line, Pipe: pipe, List: list, ElseList: elseList}}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *RangeNode) Copy() Node {
|
|
||||||
return r.tr.newRange(r.Pos, r.Line, r.Pipe.CopyPipe(), r.List.CopyList(), r.ElseList.CopyList())
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithNode represents a {{with}} action and its commands.
|
|
||||||
type WithNode struct {
|
|
||||||
BranchNode
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Tree) newWith(pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) *WithNode {
|
|
||||||
return &WithNode{BranchNode{tr: t, NodeType: NodeWith, Pos: pos, Line: line, Pipe: pipe, List: list, ElseList: elseList}}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *WithNode) Copy() Node {
|
|
||||||
return w.tr.newWith(w.Pos, w.Line, w.Pipe.CopyPipe(), w.List.CopyList(), w.ElseList.CopyList())
|
|
||||||
}
|
|
||||||
|
|
||||||
// TemplateNode represents a {{template}} action.
|
|
||||||
type TemplateNode struct {
|
|
||||||
NodeType
|
|
||||||
Pos
|
|
||||||
tr *Tree
|
|
||||||
Line int // The line number in the input (deprecated; kept for compatibility)
|
|
||||||
Name string // The name of the template (unquoted).
|
|
||||||
Pipe *PipeNode // The command to evaluate as dot for the template.
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Tree) newTemplate(pos Pos, line int, name string, pipe *PipeNode) *TemplateNode {
|
|
||||||
return &TemplateNode{tr: t, NodeType: NodeTemplate, Pos: pos, Line: line, Name: name, Pipe: pipe}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *TemplateNode) String() string {
|
|
||||||
if t.Pipe == nil {
|
|
||||||
return fmt.Sprintf("{{template %q}}", t.Name)
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("{{template %q %s}}", t.Name, t.Pipe)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *TemplateNode) tree() *Tree {
|
|
||||||
return t.tr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *TemplateNode) Copy() Node {
|
|
||||||
return t.tr.newTemplate(t.Pos, t.Line, t.Name, t.Pipe.CopyPipe())
|
|
||||||
}
|
|
700
vendor/github.com/alecthomas/template/parse/parse.go
generated
vendored
700
vendor/github.com/alecthomas/template/parse/parse.go
generated
vendored
|
@ -1,700 +0,0 @@
|
||||||
// Copyright 2011 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// Package parse builds parse trees for templates as defined by text/template
|
|
||||||
// and html/template. Clients should use those packages to construct templates
|
|
||||||
// rather than this one, which provides shared internal data structures not
|
|
||||||
// intended for general use.
|
|
||||||
package parse
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"runtime"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Tree is the representation of a single parsed template.
|
|
||||||
type Tree struct {
|
|
||||||
Name string // name of the template represented by the tree.
|
|
||||||
ParseName string // name of the top-level template during parsing, for error messages.
|
|
||||||
Root *ListNode // top-level root of the tree.
|
|
||||||
text string // text parsed to create the template (or its parent)
|
|
||||||
// Parsing only; cleared after parse.
|
|
||||||
funcs []map[string]interface{}
|
|
||||||
lex *lexer
|
|
||||||
token [3]item // three-token lookahead for parser.
|
|
||||||
peekCount int
|
|
||||||
vars []string // variables defined at the moment.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy returns a copy of the Tree. Any parsing state is discarded.
|
|
||||||
func (t *Tree) Copy() *Tree {
|
|
||||||
if t == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &Tree{
|
|
||||||
Name: t.Name,
|
|
||||||
ParseName: t.ParseName,
|
|
||||||
Root: t.Root.CopyList(),
|
|
||||||
text: t.text,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse returns a map from template name to parse.Tree, created by parsing the
|
|
||||||
// templates described in the argument string. The top-level template will be
|
|
||||||
// given the specified name. If an error is encountered, parsing stops and an
|
|
||||||
// empty map is returned with the error.
|
|
||||||
func Parse(name, text, leftDelim, rightDelim string, funcs ...map[string]interface{}) (treeSet map[string]*Tree, err error) {
|
|
||||||
treeSet = make(map[string]*Tree)
|
|
||||||
t := New(name)
|
|
||||||
t.text = text
|
|
||||||
_, err = t.Parse(text, leftDelim, rightDelim, treeSet, funcs...)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// next returns the next token.
|
|
||||||
func (t *Tree) next() item {
|
|
||||||
if t.peekCount > 0 {
|
|
||||||
t.peekCount--
|
|
||||||
} else {
|
|
||||||
t.token[0] = t.lex.nextItem()
|
|
||||||
}
|
|
||||||
return t.token[t.peekCount]
|
|
||||||
}
|
|
||||||
|
|
||||||
// backup backs the input stream up one token.
|
|
||||||
func (t *Tree) backup() {
|
|
||||||
t.peekCount++
|
|
||||||
}
|
|
||||||
|
|
||||||
// backup2 backs the input stream up two tokens.
|
|
||||||
// The zeroth token is already there.
|
|
||||||
func (t *Tree) backup2(t1 item) {
|
|
||||||
t.token[1] = t1
|
|
||||||
t.peekCount = 2
|
|
||||||
}
|
|
||||||
|
|
||||||
// backup3 backs the input stream up three tokens
|
|
||||||
// The zeroth token is already there.
|
|
||||||
func (t *Tree) backup3(t2, t1 item) { // Reverse order: we're pushing back.
|
|
||||||
t.token[1] = t1
|
|
||||||
t.token[2] = t2
|
|
||||||
t.peekCount = 3
|
|
||||||
}
|
|
||||||
|
|
||||||
// peek returns but does not consume the next token.
|
|
||||||
func (t *Tree) peek() item {
|
|
||||||
if t.peekCount > 0 {
|
|
||||||
return t.token[t.peekCount-1]
|
|
||||||
}
|
|
||||||
t.peekCount = 1
|
|
||||||
t.token[0] = t.lex.nextItem()
|
|
||||||
return t.token[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
// nextNonSpace returns the next non-space token.
|
|
||||||
func (t *Tree) nextNonSpace() (token item) {
|
|
||||||
for {
|
|
||||||
token = t.next()
|
|
||||||
if token.typ != itemSpace {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return token
|
|
||||||
}
|
|
||||||
|
|
||||||
// peekNonSpace returns but does not consume the next non-space token.
|
|
||||||
func (t *Tree) peekNonSpace() (token item) {
|
|
||||||
for {
|
|
||||||
token = t.next()
|
|
||||||
if token.typ != itemSpace {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
t.backup()
|
|
||||||
return token
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parsing.
|
|
||||||
|
|
||||||
// New allocates a new parse tree with the given name.
|
|
||||||
func New(name string, funcs ...map[string]interface{}) *Tree {
|
|
||||||
return &Tree{
|
|
||||||
Name: name,
|
|
||||||
funcs: funcs,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrorContext returns a textual representation of the location of the node in the input text.
|
|
||||||
// The receiver is only used when the node does not have a pointer to the tree inside,
|
|
||||||
// which can occur in old code.
|
|
||||||
func (t *Tree) ErrorContext(n Node) (location, context string) {
|
|
||||||
pos := int(n.Position())
|
|
||||||
tree := n.tree()
|
|
||||||
if tree == nil {
|
|
||||||
tree = t
|
|
||||||
}
|
|
||||||
text := tree.text[:pos]
|
|
||||||
byteNum := strings.LastIndex(text, "\n")
|
|
||||||
if byteNum == -1 {
|
|
||||||
byteNum = pos // On first line.
|
|
||||||
} else {
|
|
||||||
byteNum++ // After the newline.
|
|
||||||
byteNum = pos - byteNum
|
|
||||||
}
|
|
||||||
lineNum := 1 + strings.Count(text, "\n")
|
|
||||||
context = n.String()
|
|
||||||
if len(context) > 20 {
|
|
||||||
context = fmt.Sprintf("%.20s...", context)
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%s:%d:%d", tree.ParseName, lineNum, byteNum), context
|
|
||||||
}
|
|
||||||
|
|
||||||
// errorf formats the error and terminates processing.
|
|
||||||
func (t *Tree) errorf(format string, args ...interface{}) {
|
|
||||||
t.Root = nil
|
|
||||||
format = fmt.Sprintf("template: %s:%d: %s", t.ParseName, t.lex.lineNumber(), format)
|
|
||||||
panic(fmt.Errorf(format, args...))
|
|
||||||
}
|
|
||||||
|
|
||||||
// error terminates processing.
|
|
||||||
func (t *Tree) error(err error) {
|
|
||||||
t.errorf("%s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// expect consumes the next token and guarantees it has the required type.
|
|
||||||
func (t *Tree) expect(expected itemType, context string) item {
|
|
||||||
token := t.nextNonSpace()
|
|
||||||
if token.typ != expected {
|
|
||||||
t.unexpected(token, context)
|
|
||||||
}
|
|
||||||
return token
|
|
||||||
}
|
|
||||||
|
|
||||||
// expectOneOf consumes the next token and guarantees it has one of the required types.
|
|
||||||
func (t *Tree) expectOneOf(expected1, expected2 itemType, context string) item {
|
|
||||||
token := t.nextNonSpace()
|
|
||||||
if token.typ != expected1 && token.typ != expected2 {
|
|
||||||
t.unexpected(token, context)
|
|
||||||
}
|
|
||||||
return token
|
|
||||||
}
|
|
||||||
|
|
||||||
// unexpected complains about the token and terminates processing.
|
|
||||||
func (t *Tree) unexpected(token item, context string) {
|
|
||||||
t.errorf("unexpected %s in %s", token, context)
|
|
||||||
}
|
|
||||||
|
|
||||||
// recover is the handler that turns panics into returns from the top level of Parse.
|
|
||||||
func (t *Tree) recover(errp *error) {
|
|
||||||
e := recover()
|
|
||||||
if e != nil {
|
|
||||||
if _, ok := e.(runtime.Error); ok {
|
|
||||||
panic(e)
|
|
||||||
}
|
|
||||||
if t != nil {
|
|
||||||
t.stopParse()
|
|
||||||
}
|
|
||||||
*errp = e.(error)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// startParse initializes the parser, using the lexer.
|
|
||||||
func (t *Tree) startParse(funcs []map[string]interface{}, lex *lexer) {
|
|
||||||
t.Root = nil
|
|
||||||
t.lex = lex
|
|
||||||
t.vars = []string{"$"}
|
|
||||||
t.funcs = funcs
|
|
||||||
}
|
|
||||||
|
|
||||||
// stopParse terminates parsing.
|
|
||||||
func (t *Tree) stopParse() {
|
|
||||||
t.lex = nil
|
|
||||||
t.vars = nil
|
|
||||||
t.funcs = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse parses the template definition string to construct a representation of
|
|
||||||
// the template for execution. If either action delimiter string is empty, the
|
|
||||||
// default ("{{" or "}}") is used. Embedded template definitions are added to
|
|
||||||
// the treeSet map.
|
|
||||||
func (t *Tree) Parse(text, leftDelim, rightDelim string, treeSet map[string]*Tree, funcs ...map[string]interface{}) (tree *Tree, err error) {
|
|
||||||
defer t.recover(&err)
|
|
||||||
t.ParseName = t.Name
|
|
||||||
t.startParse(funcs, lex(t.Name, text, leftDelim, rightDelim))
|
|
||||||
t.text = text
|
|
||||||
t.parse(treeSet)
|
|
||||||
t.add(treeSet)
|
|
||||||
t.stopParse()
|
|
||||||
return t, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// add adds tree to the treeSet.
|
|
||||||
func (t *Tree) add(treeSet map[string]*Tree) {
|
|
||||||
tree := treeSet[t.Name]
|
|
||||||
if tree == nil || IsEmptyTree(tree.Root) {
|
|
||||||
treeSet[t.Name] = t
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !IsEmptyTree(t.Root) {
|
|
||||||
t.errorf("template: multiple definition of template %q", t.Name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsEmptyTree reports whether this tree (node) is empty of everything but space.
|
|
||||||
func IsEmptyTree(n Node) bool {
|
|
||||||
switch n := n.(type) {
|
|
||||||
case nil:
|
|
||||||
return true
|
|
||||||
case *ActionNode:
|
|
||||||
case *IfNode:
|
|
||||||
case *ListNode:
|
|
||||||
for _, node := range n.Nodes {
|
|
||||||
if !IsEmptyTree(node) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
case *RangeNode:
|
|
||||||
case *TemplateNode:
|
|
||||||
case *TextNode:
|
|
||||||
return len(bytes.TrimSpace(n.Text)) == 0
|
|
||||||
case *WithNode:
|
|
||||||
default:
|
|
||||||
panic("unknown node: " + n.String())
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse is the top-level parser for a template, essentially the same
|
|
||||||
// as itemList except it also parses {{define}} actions.
|
|
||||||
// It runs to EOF.
|
|
||||||
func (t *Tree) parse(treeSet map[string]*Tree) (next Node) {
|
|
||||||
t.Root = t.newList(t.peek().pos)
|
|
||||||
for t.peek().typ != itemEOF {
|
|
||||||
if t.peek().typ == itemLeftDelim {
|
|
||||||
delim := t.next()
|
|
||||||
if t.nextNonSpace().typ == itemDefine {
|
|
||||||
newT := New("definition") // name will be updated once we know it.
|
|
||||||
newT.text = t.text
|
|
||||||
newT.ParseName = t.ParseName
|
|
||||||
newT.startParse(t.funcs, t.lex)
|
|
||||||
newT.parseDefinition(treeSet)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
t.backup2(delim)
|
|
||||||
}
|
|
||||||
n := t.textOrAction()
|
|
||||||
if n.Type() == nodeEnd {
|
|
||||||
t.errorf("unexpected %s", n)
|
|
||||||
}
|
|
||||||
t.Root.append(n)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseDefinition parses a {{define}} ... {{end}} template definition and
|
|
||||||
// installs the definition in the treeSet map. The "define" keyword has already
|
|
||||||
// been scanned.
|
|
||||||
func (t *Tree) parseDefinition(treeSet map[string]*Tree) {
|
|
||||||
const context = "define clause"
|
|
||||||
name := t.expectOneOf(itemString, itemRawString, context)
|
|
||||||
var err error
|
|
||||||
t.Name, err = strconv.Unquote(name.val)
|
|
||||||
if err != nil {
|
|
||||||
t.error(err)
|
|
||||||
}
|
|
||||||
t.expect(itemRightDelim, context)
|
|
||||||
var end Node
|
|
||||||
t.Root, end = t.itemList()
|
|
||||||
if end.Type() != nodeEnd {
|
|
||||||
t.errorf("unexpected %s in %s", end, context)
|
|
||||||
}
|
|
||||||
t.add(treeSet)
|
|
||||||
t.stopParse()
|
|
||||||
}
|
|
||||||
|
|
||||||
// itemList:
|
|
||||||
// textOrAction*
|
|
||||||
// Terminates at {{end}} or {{else}}, returned separately.
|
|
||||||
func (t *Tree) itemList() (list *ListNode, next Node) {
|
|
||||||
list = t.newList(t.peekNonSpace().pos)
|
|
||||||
for t.peekNonSpace().typ != itemEOF {
|
|
||||||
n := t.textOrAction()
|
|
||||||
switch n.Type() {
|
|
||||||
case nodeEnd, nodeElse:
|
|
||||||
return list, n
|
|
||||||
}
|
|
||||||
list.append(n)
|
|
||||||
}
|
|
||||||
t.errorf("unexpected EOF")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// textOrAction:
|
|
||||||
// text | action
|
|
||||||
func (t *Tree) textOrAction() Node {
|
|
||||||
switch token := t.nextNonSpace(); token.typ {
|
|
||||||
case itemElideNewline:
|
|
||||||
return t.elideNewline()
|
|
||||||
case itemText:
|
|
||||||
return t.newText(token.pos, token.val)
|
|
||||||
case itemLeftDelim:
|
|
||||||
return t.action()
|
|
||||||
default:
|
|
||||||
t.unexpected(token, "input")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// elideNewline:
|
|
||||||
// Remove newlines trailing rightDelim if \\ is present.
|
|
||||||
func (t *Tree) elideNewline() Node {
|
|
||||||
token := t.peek()
|
|
||||||
if token.typ != itemText {
|
|
||||||
t.unexpected(token, "input")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
t.next()
|
|
||||||
stripped := strings.TrimLeft(token.val, "\n\r")
|
|
||||||
diff := len(token.val) - len(stripped)
|
|
||||||
if diff > 0 {
|
|
||||||
// This is a bit nasty. We mutate the token in-place to remove
|
|
||||||
// preceding newlines.
|
|
||||||
token.pos += Pos(diff)
|
|
||||||
token.val = stripped
|
|
||||||
}
|
|
||||||
return t.newText(token.pos, token.val)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Action:
|
|
||||||
// control
|
|
||||||
// command ("|" command)*
|
|
||||||
// Left delim is past. Now get actions.
|
|
||||||
// First word could be a keyword such as range.
|
|
||||||
func (t *Tree) action() (n Node) {
|
|
||||||
switch token := t.nextNonSpace(); token.typ {
|
|
||||||
case itemElse:
|
|
||||||
return t.elseControl()
|
|
||||||
case itemEnd:
|
|
||||||
return t.endControl()
|
|
||||||
case itemIf:
|
|
||||||
return t.ifControl()
|
|
||||||
case itemRange:
|
|
||||||
return t.rangeControl()
|
|
||||||
case itemTemplate:
|
|
||||||
return t.templateControl()
|
|
||||||
case itemWith:
|
|
||||||
return t.withControl()
|
|
||||||
}
|
|
||||||
t.backup()
|
|
||||||
// Do not pop variables; they persist until "end".
|
|
||||||
return t.newAction(t.peek().pos, t.lex.lineNumber(), t.pipeline("command"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pipeline:
|
|
||||||
// declarations? command ('|' command)*
|
|
||||||
func (t *Tree) pipeline(context string) (pipe *PipeNode) {
|
|
||||||
var decl []*VariableNode
|
|
||||||
pos := t.peekNonSpace().pos
|
|
||||||
// Are there declarations?
|
|
||||||
for {
|
|
||||||
if v := t.peekNonSpace(); v.typ == itemVariable {
|
|
||||||
t.next()
|
|
||||||
// Since space is a token, we need 3-token look-ahead here in the worst case:
|
|
||||||
// in "$x foo" we need to read "foo" (as opposed to ":=") to know that $x is an
|
|
||||||
// argument variable rather than a declaration. So remember the token
|
|
||||||
// adjacent to the variable so we can push it back if necessary.
|
|
||||||
tokenAfterVariable := t.peek()
|
|
||||||
if next := t.peekNonSpace(); next.typ == itemColonEquals || (next.typ == itemChar && next.val == ",") {
|
|
||||||
t.nextNonSpace()
|
|
||||||
variable := t.newVariable(v.pos, v.val)
|
|
||||||
decl = append(decl, variable)
|
|
||||||
t.vars = append(t.vars, v.val)
|
|
||||||
if next.typ == itemChar && next.val == "," {
|
|
||||||
if context == "range" && len(decl) < 2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
t.errorf("too many declarations in %s", context)
|
|
||||||
}
|
|
||||||
} else if tokenAfterVariable.typ == itemSpace {
|
|
||||||
t.backup3(v, tokenAfterVariable)
|
|
||||||
} else {
|
|
||||||
t.backup2(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
pipe = t.newPipeline(pos, t.lex.lineNumber(), decl)
|
|
||||||
for {
|
|
||||||
switch token := t.nextNonSpace(); token.typ {
|
|
||||||
case itemRightDelim, itemRightParen:
|
|
||||||
if len(pipe.Cmds) == 0 {
|
|
||||||
t.errorf("missing value for %s", context)
|
|
||||||
}
|
|
||||||
if token.typ == itemRightParen {
|
|
||||||
t.backup()
|
|
||||||
}
|
|
||||||
return
|
|
||||||
case itemBool, itemCharConstant, itemComplex, itemDot, itemField, itemIdentifier,
|
|
||||||
itemNumber, itemNil, itemRawString, itemString, itemVariable, itemLeftParen:
|
|
||||||
t.backup()
|
|
||||||
pipe.append(t.command())
|
|
||||||
default:
|
|
||||||
t.unexpected(token, context)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Tree) parseControl(allowElseIf bool, context string) (pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) {
|
|
||||||
defer t.popVars(len(t.vars))
|
|
||||||
line = t.lex.lineNumber()
|
|
||||||
pipe = t.pipeline(context)
|
|
||||||
var next Node
|
|
||||||
list, next = t.itemList()
|
|
||||||
switch next.Type() {
|
|
||||||
case nodeEnd: //done
|
|
||||||
case nodeElse:
|
|
||||||
if allowElseIf {
|
|
||||||
// Special case for "else if". If the "else" is followed immediately by an "if",
|
|
||||||
// the elseControl will have left the "if" token pending. Treat
|
|
||||||
// {{if a}}_{{else if b}}_{{end}}
|
|
||||||
// as
|
|
||||||
// {{if a}}_{{else}}{{if b}}_{{end}}{{end}}.
|
|
||||||
// To do this, parse the if as usual and stop at it {{end}}; the subsequent{{end}}
|
|
||||||
// is assumed. This technique works even for long if-else-if chains.
|
|
||||||
// TODO: Should we allow else-if in with and range?
|
|
||||||
if t.peek().typ == itemIf {
|
|
||||||
t.next() // Consume the "if" token.
|
|
||||||
elseList = t.newList(next.Position())
|
|
||||||
elseList.append(t.ifControl())
|
|
||||||
// Do not consume the next item - only one {{end}} required.
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
elseList, next = t.itemList()
|
|
||||||
if next.Type() != nodeEnd {
|
|
||||||
t.errorf("expected end; found %s", next)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return pipe.Position(), line, pipe, list, elseList
|
|
||||||
}
|
|
||||||
|
|
||||||
// If:
|
|
||||||
// {{if pipeline}} itemList {{end}}
|
|
||||||
// {{if pipeline}} itemList {{else}} itemList {{end}}
|
|
||||||
// If keyword is past.
|
|
||||||
func (t *Tree) ifControl() Node {
|
|
||||||
return t.newIf(t.parseControl(true, "if"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Range:
|
|
||||||
// {{range pipeline}} itemList {{end}}
|
|
||||||
// {{range pipeline}} itemList {{else}} itemList {{end}}
|
|
||||||
// Range keyword is past.
|
|
||||||
func (t *Tree) rangeControl() Node {
|
|
||||||
return t.newRange(t.parseControl(false, "range"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// With:
|
|
||||||
// {{with pipeline}} itemList {{end}}
|
|
||||||
// {{with pipeline}} itemList {{else}} itemList {{end}}
|
|
||||||
// If keyword is past.
|
|
||||||
func (t *Tree) withControl() Node {
|
|
||||||
return t.newWith(t.parseControl(false, "with"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// End:
|
|
||||||
// {{end}}
|
|
||||||
// End keyword is past.
|
|
||||||
func (t *Tree) endControl() Node {
|
|
||||||
return t.newEnd(t.expect(itemRightDelim, "end").pos)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Else:
|
|
||||||
// {{else}}
|
|
||||||
// Else keyword is past.
|
|
||||||
func (t *Tree) elseControl() Node {
|
|
||||||
// Special case for "else if".
|
|
||||||
peek := t.peekNonSpace()
|
|
||||||
if peek.typ == itemIf {
|
|
||||||
// We see "{{else if ... " but in effect rewrite it to {{else}}{{if ... ".
|
|
||||||
return t.newElse(peek.pos, t.lex.lineNumber())
|
|
||||||
}
|
|
||||||
return t.newElse(t.expect(itemRightDelim, "else").pos, t.lex.lineNumber())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Template:
|
|
||||||
// {{template stringValue pipeline}}
|
|
||||||
// Template keyword is past. The name must be something that can evaluate
|
|
||||||
// to a string.
|
|
||||||
func (t *Tree) templateControl() Node {
|
|
||||||
var name string
|
|
||||||
token := t.nextNonSpace()
|
|
||||||
switch token.typ {
|
|
||||||
case itemString, itemRawString:
|
|
||||||
s, err := strconv.Unquote(token.val)
|
|
||||||
if err != nil {
|
|
||||||
t.error(err)
|
|
||||||
}
|
|
||||||
name = s
|
|
||||||
default:
|
|
||||||
t.unexpected(token, "template invocation")
|
|
||||||
}
|
|
||||||
var pipe *PipeNode
|
|
||||||
if t.nextNonSpace().typ != itemRightDelim {
|
|
||||||
t.backup()
|
|
||||||
// Do not pop variables; they persist until "end".
|
|
||||||
pipe = t.pipeline("template")
|
|
||||||
}
|
|
||||||
return t.newTemplate(token.pos, t.lex.lineNumber(), name, pipe)
|
|
||||||
}
|
|
||||||
|
|
||||||
// command:
|
|
||||||
// operand (space operand)*
|
|
||||||
// space-separated arguments up to a pipeline character or right delimiter.
|
|
||||||
// we consume the pipe character but leave the right delim to terminate the action.
|
|
||||||
func (t *Tree) command() *CommandNode {
|
|
||||||
cmd := t.newCommand(t.peekNonSpace().pos)
|
|
||||||
for {
|
|
||||||
t.peekNonSpace() // skip leading spaces.
|
|
||||||
operand := t.operand()
|
|
||||||
if operand != nil {
|
|
||||||
cmd.append(operand)
|
|
||||||
}
|
|
||||||
switch token := t.next(); token.typ {
|
|
||||||
case itemSpace:
|
|
||||||
continue
|
|
||||||
case itemError:
|
|
||||||
t.errorf("%s", token.val)
|
|
||||||
case itemRightDelim, itemRightParen:
|
|
||||||
t.backup()
|
|
||||||
case itemPipe:
|
|
||||||
default:
|
|
||||||
t.errorf("unexpected %s in operand; missing space?", token)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if len(cmd.Args) == 0 {
|
|
||||||
t.errorf("empty command")
|
|
||||||
}
|
|
||||||
return cmd
|
|
||||||
}
|
|
||||||
|
|
||||||
// operand:
|
|
||||||
// term .Field*
|
|
||||||
// An operand is a space-separated component of a command,
|
|
||||||
// a term possibly followed by field accesses.
|
|
||||||
// A nil return means the next item is not an operand.
|
|
||||||
func (t *Tree) operand() Node {
|
|
||||||
node := t.term()
|
|
||||||
if node == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if t.peek().typ == itemField {
|
|
||||||
chain := t.newChain(t.peek().pos, node)
|
|
||||||
for t.peek().typ == itemField {
|
|
||||||
chain.Add(t.next().val)
|
|
||||||
}
|
|
||||||
// Compatibility with original API: If the term is of type NodeField
|
|
||||||
// or NodeVariable, just put more fields on the original.
|
|
||||||
// Otherwise, keep the Chain node.
|
|
||||||
// TODO: Switch to Chains always when we can.
|
|
||||||
switch node.Type() {
|
|
||||||
case NodeField:
|
|
||||||
node = t.newField(chain.Position(), chain.String())
|
|
||||||
case NodeVariable:
|
|
||||||
node = t.newVariable(chain.Position(), chain.String())
|
|
||||||
default:
|
|
||||||
node = chain
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return node
|
|
||||||
}
|
|
||||||
|
|
||||||
// term:
|
|
||||||
// literal (number, string, nil, boolean)
|
|
||||||
// function (identifier)
|
|
||||||
// .
|
|
||||||
// .Field
|
|
||||||
// $
|
|
||||||
// '(' pipeline ')'
|
|
||||||
// A term is a simple "expression".
|
|
||||||
// A nil return means the next item is not a term.
|
|
||||||
func (t *Tree) term() Node {
|
|
||||||
switch token := t.nextNonSpace(); token.typ {
|
|
||||||
case itemError:
|
|
||||||
t.errorf("%s", token.val)
|
|
||||||
case itemIdentifier:
|
|
||||||
if !t.hasFunction(token.val) {
|
|
||||||
t.errorf("function %q not defined", token.val)
|
|
||||||
}
|
|
||||||
return NewIdentifier(token.val).SetTree(t).SetPos(token.pos)
|
|
||||||
case itemDot:
|
|
||||||
return t.newDot(token.pos)
|
|
||||||
case itemNil:
|
|
||||||
return t.newNil(token.pos)
|
|
||||||
case itemVariable:
|
|
||||||
return t.useVar(token.pos, token.val)
|
|
||||||
case itemField:
|
|
||||||
return t.newField(token.pos, token.val)
|
|
||||||
case itemBool:
|
|
||||||
return t.newBool(token.pos, token.val == "true")
|
|
||||||
case itemCharConstant, itemComplex, itemNumber:
|
|
||||||
number, err := t.newNumber(token.pos, token.val, token.typ)
|
|
||||||
if err != nil {
|
|
||||||
t.error(err)
|
|
||||||
}
|
|
||||||
return number
|
|
||||||
case itemLeftParen:
|
|
||||||
pipe := t.pipeline("parenthesized pipeline")
|
|
||||||
if token := t.next(); token.typ != itemRightParen {
|
|
||||||
t.errorf("unclosed right paren: unexpected %s", token)
|
|
||||||
}
|
|
||||||
return pipe
|
|
||||||
case itemString, itemRawString:
|
|
||||||
s, err := strconv.Unquote(token.val)
|
|
||||||
if err != nil {
|
|
||||||
t.error(err)
|
|
||||||
}
|
|
||||||
return t.newString(token.pos, token.val, s)
|
|
||||||
}
|
|
||||||
t.backup()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// hasFunction reports if a function name exists in the Tree's maps.
|
|
||||||
func (t *Tree) hasFunction(name string) bool {
|
|
||||||
for _, funcMap := range t.funcs {
|
|
||||||
if funcMap == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if funcMap[name] != nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// popVars trims the variable list to the specified length
|
|
||||||
func (t *Tree) popVars(n int) {
|
|
||||||
t.vars = t.vars[:n]
|
|
||||||
}
|
|
||||||
|
|
||||||
// useVar returns a node for a variable reference. It errors if the
|
|
||||||
// variable is not defined.
|
|
||||||
func (t *Tree) useVar(pos Pos, name string) Node {
|
|
||||||
v := t.newVariable(pos, name)
|
|
||||||
for _, varName := range t.vars {
|
|
||||||
if varName == v.Ident[0] {
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
t.errorf("undefined variable %q", v.Ident[0])
|
|
||||||
return nil
|
|
||||||
}
|
|
218
vendor/github.com/alecthomas/template/template.go
generated
vendored
218
vendor/github.com/alecthomas/template/template.go
generated
vendored
|
@ -1,218 +0,0 @@
|
||||||
// Copyright 2011 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package template
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
|
|
||||||
"github.com/alecthomas/template/parse"
|
|
||||||
)
|
|
||||||
|
|
||||||
// common holds the information shared by related templates.
|
|
||||||
type common struct {
|
|
||||||
tmpl map[string]*Template
|
|
||||||
// We use two maps, one for parsing and one for execution.
|
|
||||||
// This separation makes the API cleaner since it doesn't
|
|
||||||
// expose reflection to the client.
|
|
||||||
parseFuncs FuncMap
|
|
||||||
execFuncs map[string]reflect.Value
|
|
||||||
}
|
|
||||||
|
|
||||||
// Template is the representation of a parsed template. The *parse.Tree
|
|
||||||
// field is exported only for use by html/template and should be treated
|
|
||||||
// as unexported by all other clients.
|
|
||||||
type Template struct {
|
|
||||||
name string
|
|
||||||
*parse.Tree
|
|
||||||
*common
|
|
||||||
leftDelim string
|
|
||||||
rightDelim string
|
|
||||||
}
|
|
||||||
|
|
||||||
// New allocates a new template with the given name.
|
|
||||||
func New(name string) *Template {
|
|
||||||
return &Template{
|
|
||||||
name: name,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name returns the name of the template.
|
|
||||||
func (t *Template) Name() string {
|
|
||||||
return t.name
|
|
||||||
}
|
|
||||||
|
|
||||||
// New allocates a new template associated with the given one and with the same
|
|
||||||
// delimiters. The association, which is transitive, allows one template to
|
|
||||||
// invoke another with a {{template}} action.
|
|
||||||
func (t *Template) New(name string) *Template {
|
|
||||||
t.init()
|
|
||||||
return &Template{
|
|
||||||
name: name,
|
|
||||||
common: t.common,
|
|
||||||
leftDelim: t.leftDelim,
|
|
||||||
rightDelim: t.rightDelim,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Template) init() {
|
|
||||||
if t.common == nil {
|
|
||||||
t.common = new(common)
|
|
||||||
t.tmpl = make(map[string]*Template)
|
|
||||||
t.parseFuncs = make(FuncMap)
|
|
||||||
t.execFuncs = make(map[string]reflect.Value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clone returns a duplicate of the template, including all associated
|
|
||||||
// templates. The actual representation is not copied, but the name space of
|
|
||||||
// associated templates is, so further calls to Parse in the copy will add
|
|
||||||
// templates to the copy but not to the original. Clone can be used to prepare
|
|
||||||
// common templates and use them with variant definitions for other templates
|
|
||||||
// by adding the variants after the clone is made.
|
|
||||||
func (t *Template) Clone() (*Template, error) {
|
|
||||||
nt := t.copy(nil)
|
|
||||||
nt.init()
|
|
||||||
nt.tmpl[t.name] = nt
|
|
||||||
for k, v := range t.tmpl {
|
|
||||||
if k == t.name { // Already installed.
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// The associated templates share nt's common structure.
|
|
||||||
tmpl := v.copy(nt.common)
|
|
||||||
nt.tmpl[k] = tmpl
|
|
||||||
}
|
|
||||||
for k, v := range t.parseFuncs {
|
|
||||||
nt.parseFuncs[k] = v
|
|
||||||
}
|
|
||||||
for k, v := range t.execFuncs {
|
|
||||||
nt.execFuncs[k] = v
|
|
||||||
}
|
|
||||||
return nt, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy returns a shallow copy of t, with common set to the argument.
|
|
||||||
func (t *Template) copy(c *common) *Template {
|
|
||||||
nt := New(t.name)
|
|
||||||
nt.Tree = t.Tree
|
|
||||||
nt.common = c
|
|
||||||
nt.leftDelim = t.leftDelim
|
|
||||||
nt.rightDelim = t.rightDelim
|
|
||||||
return nt
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddParseTree creates a new template with the name and parse tree
|
|
||||||
// and associates it with t.
|
|
||||||
func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error) {
|
|
||||||
if t.common != nil && t.tmpl[name] != nil {
|
|
||||||
return nil, fmt.Errorf("template: redefinition of template %q", name)
|
|
||||||
}
|
|
||||||
nt := t.New(name)
|
|
||||||
nt.Tree = tree
|
|
||||||
t.tmpl[name] = nt
|
|
||||||
return nt, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Templates returns a slice of the templates associated with t, including t
|
|
||||||
// itself.
|
|
||||||
func (t *Template) Templates() []*Template {
|
|
||||||
if t.common == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
// Return a slice so we don't expose the map.
|
|
||||||
m := make([]*Template, 0, len(t.tmpl))
|
|
||||||
for _, v := range t.tmpl {
|
|
||||||
m = append(m, v)
|
|
||||||
}
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delims sets the action delimiters to the specified strings, to be used in
|
|
||||||
// subsequent calls to Parse, ParseFiles, or ParseGlob. Nested template
|
|
||||||
// definitions will inherit the settings. An empty delimiter stands for the
|
|
||||||
// corresponding default: {{ or }}.
|
|
||||||
// The return value is the template, so calls can be chained.
|
|
||||||
func (t *Template) Delims(left, right string) *Template {
|
|
||||||
t.leftDelim = left
|
|
||||||
t.rightDelim = right
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
// Funcs adds the elements of the argument map to the template's function map.
|
|
||||||
// It panics if a value in the map is not a function with appropriate return
|
|
||||||
// type. However, it is legal to overwrite elements of the map. The return
|
|
||||||
// value is the template, so calls can be chained.
|
|
||||||
func (t *Template) Funcs(funcMap FuncMap) *Template {
|
|
||||||
t.init()
|
|
||||||
addValueFuncs(t.execFuncs, funcMap)
|
|
||||||
addFuncs(t.parseFuncs, funcMap)
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lookup returns the template with the given name that is associated with t,
|
|
||||||
// or nil if there is no such template.
|
|
||||||
func (t *Template) Lookup(name string) *Template {
|
|
||||||
if t.common == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return t.tmpl[name]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse parses a string into a template. Nested template definitions will be
|
|
||||||
// associated with the top-level template t. Parse may be called multiple times
|
|
||||||
// to parse definitions of templates to associate with t. It is an error if a
|
|
||||||
// resulting template is non-empty (contains content other than template
|
|
||||||
// definitions) and would replace a non-empty template with the same name.
|
|
||||||
// (In multiple calls to Parse with the same receiver template, only one call
|
|
||||||
// can contain text other than space, comments, and template definitions.)
|
|
||||||
func (t *Template) Parse(text string) (*Template, error) {
|
|
||||||
t.init()
|
|
||||||
trees, err := parse.Parse(t.name, text, t.leftDelim, t.rightDelim, t.parseFuncs, builtins)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Add the newly parsed trees, including the one for t, into our common structure.
|
|
||||||
for name, tree := range trees {
|
|
||||||
// If the name we parsed is the name of this template, overwrite this template.
|
|
||||||
// The associate method checks it's not a redefinition.
|
|
||||||
tmpl := t
|
|
||||||
if name != t.name {
|
|
||||||
tmpl = t.New(name)
|
|
||||||
}
|
|
||||||
// Even if t == tmpl, we need to install it in the common.tmpl map.
|
|
||||||
if replace, err := t.associate(tmpl, tree); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else if replace {
|
|
||||||
tmpl.Tree = tree
|
|
||||||
}
|
|
||||||
tmpl.leftDelim = t.leftDelim
|
|
||||||
tmpl.rightDelim = t.rightDelim
|
|
||||||
}
|
|
||||||
return t, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// associate installs the new template into the group of templates associated
|
|
||||||
// with t. It is an error to reuse a name except to overwrite an empty
|
|
||||||
// template. The two are already known to share the common structure.
|
|
||||||
// The boolean return value reports wither to store this tree as t.Tree.
|
|
||||||
func (t *Template) associate(new *Template, tree *parse.Tree) (bool, error) {
|
|
||||||
if new.common != t.common {
|
|
||||||
panic("internal error: associate not common")
|
|
||||||
}
|
|
||||||
name := new.name
|
|
||||||
if old := t.tmpl[name]; old != nil {
|
|
||||||
oldIsEmpty := parse.IsEmptyTree(old.Root)
|
|
||||||
newIsEmpty := parse.IsEmptyTree(tree.Root)
|
|
||||||
if newIsEmpty {
|
|
||||||
// Whether old is empty or not, new is empty; no reason to replace old.
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
if !oldIsEmpty {
|
|
||||||
return false, fmt.Errorf("template: redefinition of template %q", name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
t.tmpl[name] = new
|
|
||||||
return true, nil
|
|
||||||
}
|
|
19
vendor/github.com/alecthomas/units/COPYING
generated
vendored
19
vendor/github.com/alecthomas/units/COPYING
generated
vendored
|
@ -1,19 +0,0 @@
|
||||||
Copyright (C) 2014 Alec Thomas
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
||||||
this software and associated documentation files (the "Software"), to deal in
|
|
||||||
the Software without restriction, including without limitation the rights to
|
|
||||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
||||||
of the Software, and to permit persons to whom the Software is furnished to do
|
|
||||||
so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
11
vendor/github.com/alecthomas/units/README.md
generated
vendored
11
vendor/github.com/alecthomas/units/README.md
generated
vendored
|
@ -1,11 +0,0 @@
|
||||||
# Units - Helpful unit multipliers and functions for Go
|
|
||||||
|
|
||||||
The goal of this package is to have functionality similar to the [time](http://golang.org/pkg/time/) package.
|
|
||||||
|
|
||||||
It allows for code like this:
|
|
||||||
|
|
||||||
```go
|
|
||||||
n, err := ParseBase2Bytes("1KB")
|
|
||||||
// n == 1024
|
|
||||||
n = units.Mebibyte * 512
|
|
||||||
```
|
|
85
vendor/github.com/alecthomas/units/bytes.go
generated
vendored
85
vendor/github.com/alecthomas/units/bytes.go
generated
vendored
|
@ -1,85 +0,0 @@
|
||||||
package units
|
|
||||||
|
|
||||||
// Base2Bytes is the old non-SI power-of-2 byte scale (1024 bytes in a kilobyte,
|
|
||||||
// etc.).
|
|
||||||
type Base2Bytes int64
|
|
||||||
|
|
||||||
// Base-2 byte units.
|
|
||||||
const (
|
|
||||||
Kibibyte Base2Bytes = 1024
|
|
||||||
KiB = Kibibyte
|
|
||||||
Mebibyte = Kibibyte * 1024
|
|
||||||
MiB = Mebibyte
|
|
||||||
Gibibyte = Mebibyte * 1024
|
|
||||||
GiB = Gibibyte
|
|
||||||
Tebibyte = Gibibyte * 1024
|
|
||||||
TiB = Tebibyte
|
|
||||||
Pebibyte = Tebibyte * 1024
|
|
||||||
PiB = Pebibyte
|
|
||||||
Exbibyte = Pebibyte * 1024
|
|
||||||
EiB = Exbibyte
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
bytesUnitMap = MakeUnitMap("iB", "B", 1024)
|
|
||||||
oldBytesUnitMap = MakeUnitMap("B", "B", 1024)
|
|
||||||
)
|
|
||||||
|
|
||||||
// ParseBase2Bytes supports both iB and B in base-2 multipliers. That is, KB
|
|
||||||
// and KiB are both 1024.
|
|
||||||
// However "kB", which is the correct SI spelling of 1000 Bytes, is rejected.
|
|
||||||
func ParseBase2Bytes(s string) (Base2Bytes, error) {
|
|
||||||
n, err := ParseUnit(s, bytesUnitMap)
|
|
||||||
if err != nil {
|
|
||||||
n, err = ParseUnit(s, oldBytesUnitMap)
|
|
||||||
}
|
|
||||||
return Base2Bytes(n), err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b Base2Bytes) String() string {
|
|
||||||
return ToString(int64(b), 1024, "iB", "B")
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
metricBytesUnitMap = MakeUnitMap("B", "B", 1000)
|
|
||||||
)
|
|
||||||
|
|
||||||
// MetricBytes are SI byte units (1000 bytes in a kilobyte).
|
|
||||||
type MetricBytes SI
|
|
||||||
|
|
||||||
// SI base-10 byte units.
|
|
||||||
const (
|
|
||||||
Kilobyte MetricBytes = 1000
|
|
||||||
KB = Kilobyte
|
|
||||||
Megabyte = Kilobyte * 1000
|
|
||||||
MB = Megabyte
|
|
||||||
Gigabyte = Megabyte * 1000
|
|
||||||
GB = Gigabyte
|
|
||||||
Terabyte = Gigabyte * 1000
|
|
||||||
TB = Terabyte
|
|
||||||
Petabyte = Terabyte * 1000
|
|
||||||
PB = Petabyte
|
|
||||||
Exabyte = Petabyte * 1000
|
|
||||||
EB = Exabyte
|
|
||||||
)
|
|
||||||
|
|
||||||
// ParseMetricBytes parses base-10 metric byte units. That is, KB is 1000 bytes.
|
|
||||||
func ParseMetricBytes(s string) (MetricBytes, error) {
|
|
||||||
n, err := ParseUnit(s, metricBytesUnitMap)
|
|
||||||
return MetricBytes(n), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: represents 1000B as uppercase "KB", while SI standard requires "kB".
|
|
||||||
func (m MetricBytes) String() string {
|
|
||||||
return ToString(int64(m), 1000, "B", "B")
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseStrictBytes supports both iB and B suffixes for base 2 and metric,
|
|
||||||
// respectively. That is, KiB represents 1024 and kB, KB represent 1000.
|
|
||||||
func ParseStrictBytes(s string) (int64, error) {
|
|
||||||
n, err := ParseUnit(s, bytesUnitMap)
|
|
||||||
if err != nil {
|
|
||||||
n, err = ParseUnit(s, metricBytesUnitMap)
|
|
||||||
}
|
|
||||||
return int64(n), err
|
|
||||||
}
|
|
13
vendor/github.com/alecthomas/units/doc.go
generated
vendored
13
vendor/github.com/alecthomas/units/doc.go
generated
vendored
|
@ -1,13 +0,0 @@
|
||||||
// Package units provides helpful unit multipliers and functions for Go.
|
|
||||||
//
|
|
||||||
// The goal of this package is to have functionality similar to the time [1] package.
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// [1] http://golang.org/pkg/time/
|
|
||||||
//
|
|
||||||
// It allows for code like this:
|
|
||||||
//
|
|
||||||
// n, err := ParseBase2Bytes("1KB")
|
|
||||||
// // n == 1024
|
|
||||||
// n = units.Mebibyte * 512
|
|
||||||
package units
|
|
3
vendor/github.com/alecthomas/units/go.mod
generated
vendored
3
vendor/github.com/alecthomas/units/go.mod
generated
vendored
|
@ -1,3 +0,0 @@
|
||||||
module github.com/alecthomas/units
|
|
||||||
|
|
||||||
require github.com/stretchr/testify v1.4.0
|
|
11
vendor/github.com/alecthomas/units/go.sum
generated
vendored
11
vendor/github.com/alecthomas/units/go.sum
generated
vendored
|
@ -1,11 +0,0 @@
|
||||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
|
||||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
50
vendor/github.com/alecthomas/units/si.go
generated
vendored
50
vendor/github.com/alecthomas/units/si.go
generated
vendored
|
@ -1,50 +0,0 @@
|
||||||
package units
|
|
||||||
|
|
||||||
// SI units.
|
|
||||||
type SI int64
|
|
||||||
|
|
||||||
// SI unit multiples.
|
|
||||||
const (
|
|
||||||
Kilo SI = 1000
|
|
||||||
Mega = Kilo * 1000
|
|
||||||
Giga = Mega * 1000
|
|
||||||
Tera = Giga * 1000
|
|
||||||
Peta = Tera * 1000
|
|
||||||
Exa = Peta * 1000
|
|
||||||
)
|
|
||||||
|
|
||||||
func MakeUnitMap(suffix, shortSuffix string, scale int64) map[string]float64 {
|
|
||||||
res := map[string]float64{
|
|
||||||
shortSuffix: 1,
|
|
||||||
// see below for "k" / "K"
|
|
||||||
"M" + suffix: float64(scale * scale),
|
|
||||||
"G" + suffix: float64(scale * scale * scale),
|
|
||||||
"T" + suffix: float64(scale * scale * scale * scale),
|
|
||||||
"P" + suffix: float64(scale * scale * scale * scale * scale),
|
|
||||||
"E" + suffix: float64(scale * scale * scale * scale * scale * scale),
|
|
||||||
}
|
|
||||||
|
|
||||||
// Standard SI prefixes use lowercase "k" for kilo = 1000.
|
|
||||||
// For compatibility, and to be fool-proof, we accept both "k" and "K" in metric mode.
|
|
||||||
//
|
|
||||||
// However, official binary prefixes are always capitalized - "KiB" -
|
|
||||||
// and we specifically never parse "kB" as 1024B because:
|
|
||||||
//
|
|
||||||
// (1) people pedantic enough to use lowercase according to SI unlikely to abuse "k" to mean 1024 :-)
|
|
||||||
//
|
|
||||||
// (2) Use of capital K for 1024 was an informal tradition predating IEC prefixes:
|
|
||||||
// "The binary meaning of the kilobyte for 1024 bytes typically uses the symbol KB, with an
|
|
||||||
// uppercase letter K."
|
|
||||||
// -- https://en.wikipedia.org/wiki/Kilobyte#Base_2_(1024_bytes)
|
|
||||||
// "Capitalization of the letter K became the de facto standard for binary notation, although this
|
|
||||||
// could not be extended to higher powers, and use of the lowercase k did persist.[13][14][15]"
|
|
||||||
// -- https://en.wikipedia.org/wiki/Binary_prefix#History
|
|
||||||
// See also the extensive https://en.wikipedia.org/wiki/Timeline_of_binary_prefixes.
|
|
||||||
if scale == 1024 {
|
|
||||||
res["K"+suffix] = float64(scale)
|
|
||||||
} else {
|
|
||||||
res["k"+suffix] = float64(scale)
|
|
||||||
res["K"+suffix] = float64(scale)
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
138
vendor/github.com/alecthomas/units/util.go
generated
vendored
138
vendor/github.com/alecthomas/units/util.go
generated
vendored
|
@ -1,138 +0,0 @@
|
||||||
package units
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
siUnits = []string{"", "K", "M", "G", "T", "P", "E"}
|
|
||||||
)
|
|
||||||
|
|
||||||
func ToString(n int64, scale int64, suffix, baseSuffix string) string {
|
|
||||||
mn := len(siUnits)
|
|
||||||
out := make([]string, mn)
|
|
||||||
for i, m := range siUnits {
|
|
||||||
if n%scale != 0 || i == 0 && n == 0 {
|
|
||||||
s := suffix
|
|
||||||
if i == 0 {
|
|
||||||
s = baseSuffix
|
|
||||||
}
|
|
||||||
out[mn-1-i] = fmt.Sprintf("%d%s%s", n%scale, m, s)
|
|
||||||
}
|
|
||||||
n /= scale
|
|
||||||
if n == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return strings.Join(out, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Below code ripped straight from http://golang.org/src/pkg/time/format.go?s=33392:33438#L1123
|
|
||||||
var errLeadingInt = errors.New("units: bad [0-9]*") // never printed
|
|
||||||
|
|
||||||
// leadingInt consumes the leading [0-9]* from s.
|
|
||||||
func leadingInt(s string) (x int64, rem string, err error) {
|
|
||||||
i := 0
|
|
||||||
for ; i < len(s); i++ {
|
|
||||||
c := s[i]
|
|
||||||
if c < '0' || c > '9' {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if x >= (1<<63-10)/10 {
|
|
||||||
// overflow
|
|
||||||
return 0, "", errLeadingInt
|
|
||||||
}
|
|
||||||
x = x*10 + int64(c) - '0'
|
|
||||||
}
|
|
||||||
return x, s[i:], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseUnit(s string, unitMap map[string]float64) (int64, error) {
|
|
||||||
// [-+]?([0-9]*(\.[0-9]*)?[a-z]+)+
|
|
||||||
orig := s
|
|
||||||
f := float64(0)
|
|
||||||
neg := false
|
|
||||||
|
|
||||||
// Consume [-+]?
|
|
||||||
if s != "" {
|
|
||||||
c := s[0]
|
|
||||||
if c == '-' || c == '+' {
|
|
||||||
neg = c == '-'
|
|
||||||
s = s[1:]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Special case: if all that is left is "0", this is zero.
|
|
||||||
if s == "0" {
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
if s == "" {
|
|
||||||
return 0, errors.New("units: invalid " + orig)
|
|
||||||
}
|
|
||||||
for s != "" {
|
|
||||||
g := float64(0) // this element of the sequence
|
|
||||||
|
|
||||||
var x int64
|
|
||||||
var err error
|
|
||||||
|
|
||||||
// The next character must be [0-9.]
|
|
||||||
if !(s[0] == '.' || ('0' <= s[0] && s[0] <= '9')) {
|
|
||||||
return 0, errors.New("units: invalid " + orig)
|
|
||||||
}
|
|
||||||
// Consume [0-9]*
|
|
||||||
pl := len(s)
|
|
||||||
x, s, err = leadingInt(s)
|
|
||||||
if err != nil {
|
|
||||||
return 0, errors.New("units: invalid " + orig)
|
|
||||||
}
|
|
||||||
g = float64(x)
|
|
||||||
pre := pl != len(s) // whether we consumed anything before a period
|
|
||||||
|
|
||||||
// Consume (\.[0-9]*)?
|
|
||||||
post := false
|
|
||||||
if s != "" && s[0] == '.' {
|
|
||||||
s = s[1:]
|
|
||||||
pl := len(s)
|
|
||||||
x, s, err = leadingInt(s)
|
|
||||||
if err != nil {
|
|
||||||
return 0, errors.New("units: invalid " + orig)
|
|
||||||
}
|
|
||||||
scale := 1.0
|
|
||||||
for n := pl - len(s); n > 0; n-- {
|
|
||||||
scale *= 10
|
|
||||||
}
|
|
||||||
g += float64(x) / scale
|
|
||||||
post = pl != len(s)
|
|
||||||
}
|
|
||||||
if !pre && !post {
|
|
||||||
// no digits (e.g. ".s" or "-.s")
|
|
||||||
return 0, errors.New("units: invalid " + orig)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Consume unit.
|
|
||||||
i := 0
|
|
||||||
for ; i < len(s); i++ {
|
|
||||||
c := s[i]
|
|
||||||
if c == '.' || ('0' <= c && c <= '9') {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
u := s[:i]
|
|
||||||
s = s[i:]
|
|
||||||
unit, ok := unitMap[u]
|
|
||||||
if !ok {
|
|
||||||
return 0, errors.New("units: unknown unit " + u + " in " + orig)
|
|
||||||
}
|
|
||||||
|
|
||||||
f += g * unit
|
|
||||||
}
|
|
||||||
|
|
||||||
if neg {
|
|
||||||
f = -f
|
|
||||||
}
|
|
||||||
if f < float64(-1<<63) || f > float64(1<<63-1) {
|
|
||||||
return 0, errors.New("units: overflow parsing unit")
|
|
||||||
}
|
|
||||||
return int64(f), nil
|
|
||||||
}
|
|
20
vendor/github.com/beorn7/perks/LICENSE
generated
vendored
20
vendor/github.com/beorn7/perks/LICENSE
generated
vendored
|
@ -1,20 +0,0 @@
|
||||||
Copyright (C) 2013 Blake Mizerany
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
a copy of this software and associated documentation files (the
|
|
||||||
"Software"), to deal in the Software without restriction, including
|
|
||||||
without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
|
||||||
included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
||||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
2388
vendor/github.com/beorn7/perks/quantile/exampledata.txt
generated
vendored
2388
vendor/github.com/beorn7/perks/quantile/exampledata.txt
generated
vendored
File diff suppressed because it is too large
Load diff
316
vendor/github.com/beorn7/perks/quantile/stream.go
generated
vendored
316
vendor/github.com/beorn7/perks/quantile/stream.go
generated
vendored
|
@ -1,316 +0,0 @@
|
||||||
// Package quantile computes approximate quantiles over an unbounded data
|
|
||||||
// stream within low memory and CPU bounds.
|
|
||||||
//
|
|
||||||
// A small amount of accuracy is traded to achieve the above properties.
|
|
||||||
//
|
|
||||||
// Multiple streams can be merged before calling Query to generate a single set
|
|
||||||
// of results. This is meaningful when the streams represent the same type of
|
|
||||||
// data. See Merge and Samples.
|
|
||||||
//
|
|
||||||
// For more detailed information about the algorithm used, see:
|
|
||||||
//
|
|
||||||
// Effective Computation of Biased Quantiles over Data Streams
|
|
||||||
//
|
|
||||||
// http://www.cs.rutgers.edu/~muthu/bquant.pdf
|
|
||||||
package quantile
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math"
|
|
||||||
"sort"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Sample holds an observed value and meta information for compression. JSON
|
|
||||||
// tags have been added for convenience.
|
|
||||||
type Sample struct {
|
|
||||||
Value float64 `json:",string"`
|
|
||||||
Width float64 `json:",string"`
|
|
||||||
Delta float64 `json:",string"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Samples represents a slice of samples. It implements sort.Interface.
|
|
||||||
type Samples []Sample
|
|
||||||
|
|
||||||
func (a Samples) Len() int { return len(a) }
|
|
||||||
func (a Samples) Less(i, j int) bool { return a[i].Value < a[j].Value }
|
|
||||||
func (a Samples) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
|
||||||
|
|
||||||
type invariant func(s *stream, r float64) float64
|
|
||||||
|
|
||||||
// NewLowBiased returns an initialized Stream for low-biased quantiles
|
|
||||||
// (e.g. 0.01, 0.1, 0.5) where the needed quantiles are not known a priori, but
|
|
||||||
// error guarantees can still be given even for the lower ranks of the data
|
|
||||||
// distribution.
|
|
||||||
//
|
|
||||||
// The provided epsilon is a relative error, i.e. the true quantile of a value
|
|
||||||
// returned by a query is guaranteed to be within (1±Epsilon)*Quantile.
|
|
||||||
//
|
|
||||||
// See http://www.cs.rutgers.edu/~muthu/bquant.pdf for time, space, and error
|
|
||||||
// properties.
|
|
||||||
func NewLowBiased(epsilon float64) *Stream {
|
|
||||||
ƒ := func(s *stream, r float64) float64 {
|
|
||||||
return 2 * epsilon * r
|
|
||||||
}
|
|
||||||
return newStream(ƒ)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewHighBiased returns an initialized Stream for high-biased quantiles
|
|
||||||
// (e.g. 0.01, 0.1, 0.5) where the needed quantiles are not known a priori, but
|
|
||||||
// error guarantees can still be given even for the higher ranks of the data
|
|
||||||
// distribution.
|
|
||||||
//
|
|
||||||
// The provided epsilon is a relative error, i.e. the true quantile of a value
|
|
||||||
// returned by a query is guaranteed to be within 1-(1±Epsilon)*(1-Quantile).
|
|
||||||
//
|
|
||||||
// See http://www.cs.rutgers.edu/~muthu/bquant.pdf for time, space, and error
|
|
||||||
// properties.
|
|
||||||
func NewHighBiased(epsilon float64) *Stream {
|
|
||||||
ƒ := func(s *stream, r float64) float64 {
|
|
||||||
return 2 * epsilon * (s.n - r)
|
|
||||||
}
|
|
||||||
return newStream(ƒ)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewTargeted returns an initialized Stream concerned with a particular set of
|
|
||||||
// quantile values that are supplied a priori. Knowing these a priori reduces
|
|
||||||
// space and computation time. The targets map maps the desired quantiles to
|
|
||||||
// their absolute errors, i.e. the true quantile of a value returned by a query
|
|
||||||
// is guaranteed to be within (Quantile±Epsilon).
|
|
||||||
//
|
|
||||||
// See http://www.cs.rutgers.edu/~muthu/bquant.pdf for time, space, and error properties.
|
|
||||||
func NewTargeted(targetMap map[float64]float64) *Stream {
|
|
||||||
// Convert map to slice to avoid slow iterations on a map.
|
|
||||||
// ƒ is called on the hot path, so converting the map to a slice
|
|
||||||
// beforehand results in significant CPU savings.
|
|
||||||
targets := targetMapToSlice(targetMap)
|
|
||||||
|
|
||||||
ƒ := func(s *stream, r float64) float64 {
|
|
||||||
var m = math.MaxFloat64
|
|
||||||
var f float64
|
|
||||||
for _, t := range targets {
|
|
||||||
if t.quantile*s.n <= r {
|
|
||||||
f = (2 * t.epsilon * r) / t.quantile
|
|
||||||
} else {
|
|
||||||
f = (2 * t.epsilon * (s.n - r)) / (1 - t.quantile)
|
|
||||||
}
|
|
||||||
if f < m {
|
|
||||||
m = f
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
return newStream(ƒ)
|
|
||||||
}
|
|
||||||
|
|
||||||
type target struct {
|
|
||||||
quantile float64
|
|
||||||
epsilon float64
|
|
||||||
}
|
|
||||||
|
|
||||||
func targetMapToSlice(targetMap map[float64]float64) []target {
|
|
||||||
targets := make([]target, 0, len(targetMap))
|
|
||||||
|
|
||||||
for quantile, epsilon := range targetMap {
|
|
||||||
t := target{
|
|
||||||
quantile: quantile,
|
|
||||||
epsilon: epsilon,
|
|
||||||
}
|
|
||||||
targets = append(targets, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
return targets
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stream computes quantiles for a stream of float64s. It is not thread-safe by
|
|
||||||
// design. Take care when using across multiple goroutines.
|
|
||||||
type Stream struct {
|
|
||||||
*stream
|
|
||||||
b Samples
|
|
||||||
sorted bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func newStream(ƒ invariant) *Stream {
|
|
||||||
x := &stream{ƒ: ƒ}
|
|
||||||
return &Stream{x, make(Samples, 0, 500), true}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert inserts v into the stream.
|
|
||||||
func (s *Stream) Insert(v float64) {
|
|
||||||
s.insert(Sample{Value: v, Width: 1})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Stream) insert(sample Sample) {
|
|
||||||
s.b = append(s.b, sample)
|
|
||||||
s.sorted = false
|
|
||||||
if len(s.b) == cap(s.b) {
|
|
||||||
s.flush()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Query returns the computed qth percentiles value. If s was created with
|
|
||||||
// NewTargeted, and q is not in the set of quantiles provided a priori, Query
|
|
||||||
// will return an unspecified result.
|
|
||||||
func (s *Stream) Query(q float64) float64 {
|
|
||||||
if !s.flushed() {
|
|
||||||
// Fast path when there hasn't been enough data for a flush;
|
|
||||||
// this also yields better accuracy for small sets of data.
|
|
||||||
l := len(s.b)
|
|
||||||
if l == 0 {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
i := int(math.Ceil(float64(l) * q))
|
|
||||||
if i > 0 {
|
|
||||||
i -= 1
|
|
||||||
}
|
|
||||||
s.maybeSort()
|
|
||||||
return s.b[i].Value
|
|
||||||
}
|
|
||||||
s.flush()
|
|
||||||
return s.stream.query(q)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Merge merges samples into the underlying streams samples. This is handy when
|
|
||||||
// merging multiple streams from separate threads, database shards, etc.
|
|
||||||
//
|
|
||||||
// ATTENTION: This method is broken and does not yield correct results. The
|
|
||||||
// underlying algorithm is not capable of merging streams correctly.
|
|
||||||
func (s *Stream) Merge(samples Samples) {
|
|
||||||
sort.Sort(samples)
|
|
||||||
s.stream.merge(samples)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset reinitializes and clears the list reusing the samples buffer memory.
|
|
||||||
func (s *Stream) Reset() {
|
|
||||||
s.stream.reset()
|
|
||||||
s.b = s.b[:0]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Samples returns stream samples held by s.
|
|
||||||
func (s *Stream) Samples() Samples {
|
|
||||||
if !s.flushed() {
|
|
||||||
return s.b
|
|
||||||
}
|
|
||||||
s.flush()
|
|
||||||
return s.stream.samples()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Count returns the total number of samples observed in the stream
|
|
||||||
// since initialization.
|
|
||||||
func (s *Stream) Count() int {
|
|
||||||
return len(s.b) + s.stream.count()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Stream) flush() {
|
|
||||||
s.maybeSort()
|
|
||||||
s.stream.merge(s.b)
|
|
||||||
s.b = s.b[:0]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Stream) maybeSort() {
|
|
||||||
if !s.sorted {
|
|
||||||
s.sorted = true
|
|
||||||
sort.Sort(s.b)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Stream) flushed() bool {
|
|
||||||
return len(s.stream.l) > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
type stream struct {
|
|
||||||
n float64
|
|
||||||
l []Sample
|
|
||||||
ƒ invariant
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *stream) reset() {
|
|
||||||
s.l = s.l[:0]
|
|
||||||
s.n = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *stream) insert(v float64) {
|
|
||||||
s.merge(Samples{{v, 1, 0}})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *stream) merge(samples Samples) {
|
|
||||||
// TODO(beorn7): This tries to merge not only individual samples, but
|
|
||||||
// whole summaries. The paper doesn't mention merging summaries at
|
|
||||||
// all. Unittests show that the merging is inaccurate. Find out how to
|
|
||||||
// do merges properly.
|
|
||||||
var r float64
|
|
||||||
i := 0
|
|
||||||
for _, sample := range samples {
|
|
||||||
for ; i < len(s.l); i++ {
|
|
||||||
c := s.l[i]
|
|
||||||
if c.Value > sample.Value {
|
|
||||||
// Insert at position i.
|
|
||||||
s.l = append(s.l, Sample{})
|
|
||||||
copy(s.l[i+1:], s.l[i:])
|
|
||||||
s.l[i] = Sample{
|
|
||||||
sample.Value,
|
|
||||||
sample.Width,
|
|
||||||
math.Max(sample.Delta, math.Floor(s.ƒ(s, r))-1),
|
|
||||||
// TODO(beorn7): How to calculate delta correctly?
|
|
||||||
}
|
|
||||||
i++
|
|
||||||
goto inserted
|
|
||||||
}
|
|
||||||
r += c.Width
|
|
||||||
}
|
|
||||||
s.l = append(s.l, Sample{sample.Value, sample.Width, 0})
|
|
||||||
i++
|
|
||||||
inserted:
|
|
||||||
s.n += sample.Width
|
|
||||||
r += sample.Width
|
|
||||||
}
|
|
||||||
s.compress()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *stream) count() int {
|
|
||||||
return int(s.n)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *stream) query(q float64) float64 {
|
|
||||||
t := math.Ceil(q * s.n)
|
|
||||||
t += math.Ceil(s.ƒ(s, t) / 2)
|
|
||||||
p := s.l[0]
|
|
||||||
var r float64
|
|
||||||
for _, c := range s.l[1:] {
|
|
||||||
r += p.Width
|
|
||||||
if r+c.Width+c.Delta > t {
|
|
||||||
return p.Value
|
|
||||||
}
|
|
||||||
p = c
|
|
||||||
}
|
|
||||||
return p.Value
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *stream) compress() {
|
|
||||||
if len(s.l) < 2 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
x := s.l[len(s.l)-1]
|
|
||||||
xi := len(s.l) - 1
|
|
||||||
r := s.n - 1 - x.Width
|
|
||||||
|
|
||||||
for i := len(s.l) - 2; i >= 0; i-- {
|
|
||||||
c := s.l[i]
|
|
||||||
if c.Width+x.Width+x.Delta <= s.ƒ(s, r) {
|
|
||||||
x.Width += c.Width
|
|
||||||
s.l[xi] = x
|
|
||||||
// Remove element at i.
|
|
||||||
copy(s.l[i:], s.l[i+1:])
|
|
||||||
s.l = s.l[:len(s.l)-1]
|
|
||||||
xi -= 1
|
|
||||||
} else {
|
|
||||||
x = c
|
|
||||||
xi = i
|
|
||||||
}
|
|
||||||
r -= c.Width
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *stream) samples() Samples {
|
|
||||||
samples := make(Samples, len(s.l))
|
|
||||||
copy(samples, s.l)
|
|
||||||
return samples
|
|
||||||
}
|
|
8
vendor/github.com/cespare/xxhash/v2/.travis.yml
generated
vendored
8
vendor/github.com/cespare/xxhash/v2/.travis.yml
generated
vendored
|
@ -1,8 +0,0 @@
|
||||||
language: go
|
|
||||||
go:
|
|
||||||
- "1.x"
|
|
||||||
- master
|
|
||||||
env:
|
|
||||||
- TAGS=""
|
|
||||||
- TAGS="-tags purego"
|
|
||||||
script: go test $TAGS -v ./...
|
|
22
vendor/github.com/cespare/xxhash/v2/LICENSE.txt
generated
vendored
22
vendor/github.com/cespare/xxhash/v2/LICENSE.txt
generated
vendored
|
@ -1,22 +0,0 @@
|
||||||
Copyright (c) 2016 Caleb Spare
|
|
||||||
|
|
||||||
MIT License
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
a copy of this software and associated documentation files (the
|
|
||||||
"Software"), to deal in the Software without restriction, including
|
|
||||||
without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
|
||||||
included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
||||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
67
vendor/github.com/cespare/xxhash/v2/README.md
generated
vendored
67
vendor/github.com/cespare/xxhash/v2/README.md
generated
vendored
|
@ -1,67 +0,0 @@
|
||||||
# xxhash
|
|
||||||
|
|
||||||
[![GoDoc](https://godoc.org/github.com/cespare/xxhash?status.svg)](https://godoc.org/github.com/cespare/xxhash)
|
|
||||||
[![Build Status](https://travis-ci.org/cespare/xxhash.svg?branch=master)](https://travis-ci.org/cespare/xxhash)
|
|
||||||
|
|
||||||
xxhash is a Go implementation of the 64-bit
|
|
||||||
[xxHash](http://cyan4973.github.io/xxHash/) algorithm, XXH64. This is a
|
|
||||||
high-quality hashing algorithm that is much faster than anything in the Go
|
|
||||||
standard library.
|
|
||||||
|
|
||||||
This package provides a straightforward API:
|
|
||||||
|
|
||||||
```
|
|
||||||
func Sum64(b []byte) uint64
|
|
||||||
func Sum64String(s string) uint64
|
|
||||||
type Digest struct{ ... }
|
|
||||||
func New() *Digest
|
|
||||||
```
|
|
||||||
|
|
||||||
The `Digest` type implements hash.Hash64. Its key methods are:
|
|
||||||
|
|
||||||
```
|
|
||||||
func (*Digest) Write([]byte) (int, error)
|
|
||||||
func (*Digest) WriteString(string) (int, error)
|
|
||||||
func (*Digest) Sum64() uint64
|
|
||||||
```
|
|
||||||
|
|
||||||
This implementation provides a fast pure-Go implementation and an even faster
|
|
||||||
assembly implementation for amd64.
|
|
||||||
|
|
||||||
## Compatibility
|
|
||||||
|
|
||||||
This package is in a module and the latest code is in version 2 of the module.
|
|
||||||
You need a version of Go with at least "minimal module compatibility" to use
|
|
||||||
github.com/cespare/xxhash/v2:
|
|
||||||
|
|
||||||
* 1.9.7+ for Go 1.9
|
|
||||||
* 1.10.3+ for Go 1.10
|
|
||||||
* Go 1.11 or later
|
|
||||||
|
|
||||||
I recommend using the latest release of Go.
|
|
||||||
|
|
||||||
## Benchmarks
|
|
||||||
|
|
||||||
Here are some quick benchmarks comparing the pure-Go and assembly
|
|
||||||
implementations of Sum64.
|
|
||||||
|
|
||||||
| input size | purego | asm |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| 5 B | 979.66 MB/s | 1291.17 MB/s |
|
|
||||||
| 100 B | 7475.26 MB/s | 7973.40 MB/s |
|
|
||||||
| 4 KB | 17573.46 MB/s | 17602.65 MB/s |
|
|
||||||
| 10 MB | 17131.46 MB/s | 17142.16 MB/s |
|
|
||||||
|
|
||||||
These numbers were generated on Ubuntu 18.04 with an Intel i7-8700K CPU using
|
|
||||||
the following commands under Go 1.11.2:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ go test -tags purego -benchtime 10s -bench '/xxhash,direct,bytes'
|
|
||||||
$ go test -benchtime 10s -bench '/xxhash,direct,bytes'
|
|
||||||
```
|
|
||||||
|
|
||||||
## Projects using this package
|
|
||||||
|
|
||||||
- [InfluxDB](https://github.com/influxdata/influxdb)
|
|
||||||
- [Prometheus](https://github.com/prometheus/prometheus)
|
|
||||||
- [FreeCache](https://github.com/coocood/freecache)
|
|
3
vendor/github.com/cespare/xxhash/v2/go.mod
generated
vendored
3
vendor/github.com/cespare/xxhash/v2/go.mod
generated
vendored
|
@ -1,3 +0,0 @@
|
||||||
module github.com/cespare/xxhash/v2
|
|
||||||
|
|
||||||
go 1.11
|
|
0
vendor/github.com/cespare/xxhash/v2/go.sum
generated
vendored
0
vendor/github.com/cespare/xxhash/v2/go.sum
generated
vendored
236
vendor/github.com/cespare/xxhash/v2/xxhash.go
generated
vendored
236
vendor/github.com/cespare/xxhash/v2/xxhash.go
generated
vendored
|
@ -1,236 +0,0 @@
|
||||||
// Package xxhash implements the 64-bit variant of xxHash (XXH64) as described
|
|
||||||
// at http://cyan4973.github.io/xxHash/.
|
|
||||||
package xxhash
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/binary"
|
|
||||||
"errors"
|
|
||||||
"math/bits"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
prime1 uint64 = 11400714785074694791
|
|
||||||
prime2 uint64 = 14029467366897019727
|
|
||||||
prime3 uint64 = 1609587929392839161
|
|
||||||
prime4 uint64 = 9650029242287828579
|
|
||||||
prime5 uint64 = 2870177450012600261
|
|
||||||
)
|
|
||||||
|
|
||||||
// NOTE(caleb): I'm using both consts and vars of the primes. Using consts where
|
|
||||||
// possible in the Go code is worth a small (but measurable) performance boost
|
|
||||||
// by avoiding some MOVQs. Vars are needed for the asm and also are useful for
|
|
||||||
// convenience in the Go code in a few places where we need to intentionally
|
|
||||||
// avoid constant arithmetic (e.g., v1 := prime1 + prime2 fails because the
|
|
||||||
// result overflows a uint64).
|
|
||||||
var (
|
|
||||||
prime1v = prime1
|
|
||||||
prime2v = prime2
|
|
||||||
prime3v = prime3
|
|
||||||
prime4v = prime4
|
|
||||||
prime5v = prime5
|
|
||||||
)
|
|
||||||
|
|
||||||
// Digest implements hash.Hash64.
|
|
||||||
type Digest struct {
|
|
||||||
v1 uint64
|
|
||||||
v2 uint64
|
|
||||||
v3 uint64
|
|
||||||
v4 uint64
|
|
||||||
total uint64
|
|
||||||
mem [32]byte
|
|
||||||
n int // how much of mem is used
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates a new Digest that computes the 64-bit xxHash algorithm.
|
|
||||||
func New() *Digest {
|
|
||||||
var d Digest
|
|
||||||
d.Reset()
|
|
||||||
return &d
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset clears the Digest's state so that it can be reused.
|
|
||||||
func (d *Digest) Reset() {
|
|
||||||
d.v1 = prime1v + prime2
|
|
||||||
d.v2 = prime2
|
|
||||||
d.v3 = 0
|
|
||||||
d.v4 = -prime1v
|
|
||||||
d.total = 0
|
|
||||||
d.n = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Size always returns 8 bytes.
|
|
||||||
func (d *Digest) Size() int { return 8 }
|
|
||||||
|
|
||||||
// BlockSize always returns 32 bytes.
|
|
||||||
func (d *Digest) BlockSize() int { return 32 }
|
|
||||||
|
|
||||||
// Write adds more data to d. It always returns len(b), nil.
|
|
||||||
func (d *Digest) Write(b []byte) (n int, err error) {
|
|
||||||
n = len(b)
|
|
||||||
d.total += uint64(n)
|
|
||||||
|
|
||||||
if d.n+n < 32 {
|
|
||||||
// This new data doesn't even fill the current block.
|
|
||||||
copy(d.mem[d.n:], b)
|
|
||||||
d.n += n
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if d.n > 0 {
|
|
||||||
// Finish off the partial block.
|
|
||||||
copy(d.mem[d.n:], b)
|
|
||||||
d.v1 = round(d.v1, u64(d.mem[0:8]))
|
|
||||||
d.v2 = round(d.v2, u64(d.mem[8:16]))
|
|
||||||
d.v3 = round(d.v3, u64(d.mem[16:24]))
|
|
||||||
d.v4 = round(d.v4, u64(d.mem[24:32]))
|
|
||||||
b = b[32-d.n:]
|
|
||||||
d.n = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(b) >= 32 {
|
|
||||||
// One or more full blocks left.
|
|
||||||
nw := writeBlocks(d, b)
|
|
||||||
b = b[nw:]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store any remaining partial block.
|
|
||||||
copy(d.mem[:], b)
|
|
||||||
d.n = len(b)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sum appends the current hash to b and returns the resulting slice.
|
|
||||||
func (d *Digest) Sum(b []byte) []byte {
|
|
||||||
s := d.Sum64()
|
|
||||||
return append(
|
|
||||||
b,
|
|
||||||
byte(s>>56),
|
|
||||||
byte(s>>48),
|
|
||||||
byte(s>>40),
|
|
||||||
byte(s>>32),
|
|
||||||
byte(s>>24),
|
|
||||||
byte(s>>16),
|
|
||||||
byte(s>>8),
|
|
||||||
byte(s),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sum64 returns the current hash.
|
|
||||||
func (d *Digest) Sum64() uint64 {
|
|
||||||
var h uint64
|
|
||||||
|
|
||||||
if d.total >= 32 {
|
|
||||||
v1, v2, v3, v4 := d.v1, d.v2, d.v3, d.v4
|
|
||||||
h = rol1(v1) + rol7(v2) + rol12(v3) + rol18(v4)
|
|
||||||
h = mergeRound(h, v1)
|
|
||||||
h = mergeRound(h, v2)
|
|
||||||
h = mergeRound(h, v3)
|
|
||||||
h = mergeRound(h, v4)
|
|
||||||
} else {
|
|
||||||
h = d.v3 + prime5
|
|
||||||
}
|
|
||||||
|
|
||||||
h += d.total
|
|
||||||
|
|
||||||
i, end := 0, d.n
|
|
||||||
for ; i+8 <= end; i += 8 {
|
|
||||||
k1 := round(0, u64(d.mem[i:i+8]))
|
|
||||||
h ^= k1
|
|
||||||
h = rol27(h)*prime1 + prime4
|
|
||||||
}
|
|
||||||
if i+4 <= end {
|
|
||||||
h ^= uint64(u32(d.mem[i:i+4])) * prime1
|
|
||||||
h = rol23(h)*prime2 + prime3
|
|
||||||
i += 4
|
|
||||||
}
|
|
||||||
for i < end {
|
|
||||||
h ^= uint64(d.mem[i]) * prime5
|
|
||||||
h = rol11(h) * prime1
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
|
|
||||||
h ^= h >> 33
|
|
||||||
h *= prime2
|
|
||||||
h ^= h >> 29
|
|
||||||
h *= prime3
|
|
||||||
h ^= h >> 32
|
|
||||||
|
|
||||||
return h
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
magic = "xxh\x06"
|
|
||||||
marshaledSize = len(magic) + 8*5 + 32
|
|
||||||
)
|
|
||||||
|
|
||||||
// MarshalBinary implements the encoding.BinaryMarshaler interface.
|
|
||||||
func (d *Digest) MarshalBinary() ([]byte, error) {
|
|
||||||
b := make([]byte, 0, marshaledSize)
|
|
||||||
b = append(b, magic...)
|
|
||||||
b = appendUint64(b, d.v1)
|
|
||||||
b = appendUint64(b, d.v2)
|
|
||||||
b = appendUint64(b, d.v3)
|
|
||||||
b = appendUint64(b, d.v4)
|
|
||||||
b = appendUint64(b, d.total)
|
|
||||||
b = append(b, d.mem[:d.n]...)
|
|
||||||
b = b[:len(b)+len(d.mem)-d.n]
|
|
||||||
return b, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
|
|
||||||
func (d *Digest) UnmarshalBinary(b []byte) error {
|
|
||||||
if len(b) < len(magic) || string(b[:len(magic)]) != magic {
|
|
||||||
return errors.New("xxhash: invalid hash state identifier")
|
|
||||||
}
|
|
||||||
if len(b) != marshaledSize {
|
|
||||||
return errors.New("xxhash: invalid hash state size")
|
|
||||||
}
|
|
||||||
b = b[len(magic):]
|
|
||||||
b, d.v1 = consumeUint64(b)
|
|
||||||
b, d.v2 = consumeUint64(b)
|
|
||||||
b, d.v3 = consumeUint64(b)
|
|
||||||
b, d.v4 = consumeUint64(b)
|
|
||||||
b, d.total = consumeUint64(b)
|
|
||||||
copy(d.mem[:], b)
|
|
||||||
b = b[len(d.mem):]
|
|
||||||
d.n = int(d.total % uint64(len(d.mem)))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func appendUint64(b []byte, x uint64) []byte {
|
|
||||||
var a [8]byte
|
|
||||||
binary.LittleEndian.PutUint64(a[:], x)
|
|
||||||
return append(b, a[:]...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func consumeUint64(b []byte) ([]byte, uint64) {
|
|
||||||
x := u64(b)
|
|
||||||
return b[8:], x
|
|
||||||
}
|
|
||||||
|
|
||||||
func u64(b []byte) uint64 { return binary.LittleEndian.Uint64(b) }
|
|
||||||
func u32(b []byte) uint32 { return binary.LittleEndian.Uint32(b) }
|
|
||||||
|
|
||||||
func round(acc, input uint64) uint64 {
|
|
||||||
acc += input * prime2
|
|
||||||
acc = rol31(acc)
|
|
||||||
acc *= prime1
|
|
||||||
return acc
|
|
||||||
}
|
|
||||||
|
|
||||||
func mergeRound(acc, val uint64) uint64 {
|
|
||||||
val = round(0, val)
|
|
||||||
acc ^= val
|
|
||||||
acc = acc*prime1 + prime4
|
|
||||||
return acc
|
|
||||||
}
|
|
||||||
|
|
||||||
func rol1(x uint64) uint64 { return bits.RotateLeft64(x, 1) }
|
|
||||||
func rol7(x uint64) uint64 { return bits.RotateLeft64(x, 7) }
|
|
||||||
func rol11(x uint64) uint64 { return bits.RotateLeft64(x, 11) }
|
|
||||||
func rol12(x uint64) uint64 { return bits.RotateLeft64(x, 12) }
|
|
||||||
func rol18(x uint64) uint64 { return bits.RotateLeft64(x, 18) }
|
|
||||||
func rol23(x uint64) uint64 { return bits.RotateLeft64(x, 23) }
|
|
||||||
func rol27(x uint64) uint64 { return bits.RotateLeft64(x, 27) }
|
|
||||||
func rol31(x uint64) uint64 { return bits.RotateLeft64(x, 31) }
|
|
13
vendor/github.com/cespare/xxhash/v2/xxhash_amd64.go
generated
vendored
13
vendor/github.com/cespare/xxhash/v2/xxhash_amd64.go
generated
vendored
|
@ -1,13 +0,0 @@
|
||||||
// +build !appengine
|
|
||||||
// +build gc
|
|
||||||
// +build !purego
|
|
||||||
|
|
||||||
package xxhash
|
|
||||||
|
|
||||||
// Sum64 computes the 64-bit xxHash digest of b.
|
|
||||||
//
|
|
||||||
//go:noescape
|
|
||||||
func Sum64(b []byte) uint64
|
|
||||||
|
|
||||||
//go:noescape
|
|
||||||
func writeBlocks(d *Digest, b []byte) int
|
|
215
vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s
generated
vendored
215
vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s
generated
vendored
|
@ -1,215 +0,0 @@
|
||||||
// +build !appengine
|
|
||||||
// +build gc
|
|
||||||
// +build !purego
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
// Register allocation:
|
|
||||||
// AX h
|
|
||||||
// CX pointer to advance through b
|
|
||||||
// DX n
|
|
||||||
// BX loop end
|
|
||||||
// R8 v1, k1
|
|
||||||
// R9 v2
|
|
||||||
// R10 v3
|
|
||||||
// R11 v4
|
|
||||||
// R12 tmp
|
|
||||||
// R13 prime1v
|
|
||||||
// R14 prime2v
|
|
||||||
// R15 prime4v
|
|
||||||
|
|
||||||
// round reads from and advances the buffer pointer in CX.
|
|
||||||
// It assumes that R13 has prime1v and R14 has prime2v.
|
|
||||||
#define round(r) \
|
|
||||||
MOVQ (CX), R12 \
|
|
||||||
ADDQ $8, CX \
|
|
||||||
IMULQ R14, R12 \
|
|
||||||
ADDQ R12, r \
|
|
||||||
ROLQ $31, r \
|
|
||||||
IMULQ R13, r
|
|
||||||
|
|
||||||
// mergeRound applies a merge round on the two registers acc and val.
|
|
||||||
// It assumes that R13 has prime1v, R14 has prime2v, and R15 has prime4v.
|
|
||||||
#define mergeRound(acc, val) \
|
|
||||||
IMULQ R14, val \
|
|
||||||
ROLQ $31, val \
|
|
||||||
IMULQ R13, val \
|
|
||||||
XORQ val, acc \
|
|
||||||
IMULQ R13, acc \
|
|
||||||
ADDQ R15, acc
|
|
||||||
|
|
||||||
// func Sum64(b []byte) uint64
|
|
||||||
TEXT ·Sum64(SB), NOSPLIT, $0-32
|
|
||||||
// Load fixed primes.
|
|
||||||
MOVQ ·prime1v(SB), R13
|
|
||||||
MOVQ ·prime2v(SB), R14
|
|
||||||
MOVQ ·prime4v(SB), R15
|
|
||||||
|
|
||||||
// Load slice.
|
|
||||||
MOVQ b_base+0(FP), CX
|
|
||||||
MOVQ b_len+8(FP), DX
|
|
||||||
LEAQ (CX)(DX*1), BX
|
|
||||||
|
|
||||||
// The first loop limit will be len(b)-32.
|
|
||||||
SUBQ $32, BX
|
|
||||||
|
|
||||||
// Check whether we have at least one block.
|
|
||||||
CMPQ DX, $32
|
|
||||||
JLT noBlocks
|
|
||||||
|
|
||||||
// Set up initial state (v1, v2, v3, v4).
|
|
||||||
MOVQ R13, R8
|
|
||||||
ADDQ R14, R8
|
|
||||||
MOVQ R14, R9
|
|
||||||
XORQ R10, R10
|
|
||||||
XORQ R11, R11
|
|
||||||
SUBQ R13, R11
|
|
||||||
|
|
||||||
// Loop until CX > BX.
|
|
||||||
blockLoop:
|
|
||||||
round(R8)
|
|
||||||
round(R9)
|
|
||||||
round(R10)
|
|
||||||
round(R11)
|
|
||||||
|
|
||||||
CMPQ CX, BX
|
|
||||||
JLE blockLoop
|
|
||||||
|
|
||||||
MOVQ R8, AX
|
|
||||||
ROLQ $1, AX
|
|
||||||
MOVQ R9, R12
|
|
||||||
ROLQ $7, R12
|
|
||||||
ADDQ R12, AX
|
|
||||||
MOVQ R10, R12
|
|
||||||
ROLQ $12, R12
|
|
||||||
ADDQ R12, AX
|
|
||||||
MOVQ R11, R12
|
|
||||||
ROLQ $18, R12
|
|
||||||
ADDQ R12, AX
|
|
||||||
|
|
||||||
mergeRound(AX, R8)
|
|
||||||
mergeRound(AX, R9)
|
|
||||||
mergeRound(AX, R10)
|
|
||||||
mergeRound(AX, R11)
|
|
||||||
|
|
||||||
JMP afterBlocks
|
|
||||||
|
|
||||||
noBlocks:
|
|
||||||
MOVQ ·prime5v(SB), AX
|
|
||||||
|
|
||||||
afterBlocks:
|
|
||||||
ADDQ DX, AX
|
|
||||||
|
|
||||||
// Right now BX has len(b)-32, and we want to loop until CX > len(b)-8.
|
|
||||||
ADDQ $24, BX
|
|
||||||
|
|
||||||
CMPQ CX, BX
|
|
||||||
JG fourByte
|
|
||||||
|
|
||||||
wordLoop:
|
|
||||||
// Calculate k1.
|
|
||||||
MOVQ (CX), R8
|
|
||||||
ADDQ $8, CX
|
|
||||||
IMULQ R14, R8
|
|
||||||
ROLQ $31, R8
|
|
||||||
IMULQ R13, R8
|
|
||||||
|
|
||||||
XORQ R8, AX
|
|
||||||
ROLQ $27, AX
|
|
||||||
IMULQ R13, AX
|
|
||||||
ADDQ R15, AX
|
|
||||||
|
|
||||||
CMPQ CX, BX
|
|
||||||
JLE wordLoop
|
|
||||||
|
|
||||||
fourByte:
|
|
||||||
ADDQ $4, BX
|
|
||||||
CMPQ CX, BX
|
|
||||||
JG singles
|
|
||||||
|
|
||||||
MOVL (CX), R8
|
|
||||||
ADDQ $4, CX
|
|
||||||
IMULQ R13, R8
|
|
||||||
XORQ R8, AX
|
|
||||||
|
|
||||||
ROLQ $23, AX
|
|
||||||
IMULQ R14, AX
|
|
||||||
ADDQ ·prime3v(SB), AX
|
|
||||||
|
|
||||||
singles:
|
|
||||||
ADDQ $4, BX
|
|
||||||
CMPQ CX, BX
|
|
||||||
JGE finalize
|
|
||||||
|
|
||||||
singlesLoop:
|
|
||||||
MOVBQZX (CX), R12
|
|
||||||
ADDQ $1, CX
|
|
||||||
IMULQ ·prime5v(SB), R12
|
|
||||||
XORQ R12, AX
|
|
||||||
|
|
||||||
ROLQ $11, AX
|
|
||||||
IMULQ R13, AX
|
|
||||||
|
|
||||||
CMPQ CX, BX
|
|
||||||
JL singlesLoop
|
|
||||||
|
|
||||||
finalize:
|
|
||||||
MOVQ AX, R12
|
|
||||||
SHRQ $33, R12
|
|
||||||
XORQ R12, AX
|
|
||||||
IMULQ R14, AX
|
|
||||||
MOVQ AX, R12
|
|
||||||
SHRQ $29, R12
|
|
||||||
XORQ R12, AX
|
|
||||||
IMULQ ·prime3v(SB), AX
|
|
||||||
MOVQ AX, R12
|
|
||||||
SHRQ $32, R12
|
|
||||||
XORQ R12, AX
|
|
||||||
|
|
||||||
MOVQ AX, ret+24(FP)
|
|
||||||
RET
|
|
||||||
|
|
||||||
// writeBlocks uses the same registers as above except that it uses AX to store
|
|
||||||
// the d pointer.
|
|
||||||
|
|
||||||
// func writeBlocks(d *Digest, b []byte) int
|
|
||||||
TEXT ·writeBlocks(SB), NOSPLIT, $0-40
|
|
||||||
// Load fixed primes needed for round.
|
|
||||||
MOVQ ·prime1v(SB), R13
|
|
||||||
MOVQ ·prime2v(SB), R14
|
|
||||||
|
|
||||||
// Load slice.
|
|
||||||
MOVQ b_base+8(FP), CX
|
|
||||||
MOVQ b_len+16(FP), DX
|
|
||||||
LEAQ (CX)(DX*1), BX
|
|
||||||
SUBQ $32, BX
|
|
||||||
|
|
||||||
// Load vN from d.
|
|
||||||
MOVQ d+0(FP), AX
|
|
||||||
MOVQ 0(AX), R8 // v1
|
|
||||||
MOVQ 8(AX), R9 // v2
|
|
||||||
MOVQ 16(AX), R10 // v3
|
|
||||||
MOVQ 24(AX), R11 // v4
|
|
||||||
|
|
||||||
// We don't need to check the loop condition here; this function is
|
|
||||||
// always called with at least one block of data to process.
|
|
||||||
blockLoop:
|
|
||||||
round(R8)
|
|
||||||
round(R9)
|
|
||||||
round(R10)
|
|
||||||
round(R11)
|
|
||||||
|
|
||||||
CMPQ CX, BX
|
|
||||||
JLE blockLoop
|
|
||||||
|
|
||||||
// Copy vN back to d.
|
|
||||||
MOVQ R8, 0(AX)
|
|
||||||
MOVQ R9, 8(AX)
|
|
||||||
MOVQ R10, 16(AX)
|
|
||||||
MOVQ R11, 24(AX)
|
|
||||||
|
|
||||||
// The number of bytes written is CX minus the old base pointer.
|
|
||||||
SUBQ b_base+8(FP), CX
|
|
||||||
MOVQ CX, ret+32(FP)
|
|
||||||
|
|
||||||
RET
|
|
76
vendor/github.com/cespare/xxhash/v2/xxhash_other.go
generated
vendored
76
vendor/github.com/cespare/xxhash/v2/xxhash_other.go
generated
vendored
|
@ -1,76 +0,0 @@
|
||||||
// +build !amd64 appengine !gc purego
|
|
||||||
|
|
||||||
package xxhash
|
|
||||||
|
|
||||||
// Sum64 computes the 64-bit xxHash digest of b.
|
|
||||||
func Sum64(b []byte) uint64 {
|
|
||||||
// A simpler version would be
|
|
||||||
// d := New()
|
|
||||||
// d.Write(b)
|
|
||||||
// return d.Sum64()
|
|
||||||
// but this is faster, particularly for small inputs.
|
|
||||||
|
|
||||||
n := len(b)
|
|
||||||
var h uint64
|
|
||||||
|
|
||||||
if n >= 32 {
|
|
||||||
v1 := prime1v + prime2
|
|
||||||
v2 := prime2
|
|
||||||
v3 := uint64(0)
|
|
||||||
v4 := -prime1v
|
|
||||||
for len(b) >= 32 {
|
|
||||||
v1 = round(v1, u64(b[0:8:len(b)]))
|
|
||||||
v2 = round(v2, u64(b[8:16:len(b)]))
|
|
||||||
v3 = round(v3, u64(b[16:24:len(b)]))
|
|
||||||
v4 = round(v4, u64(b[24:32:len(b)]))
|
|
||||||
b = b[32:len(b):len(b)]
|
|
||||||
}
|
|
||||||
h = rol1(v1) + rol7(v2) + rol12(v3) + rol18(v4)
|
|
||||||
h = mergeRound(h, v1)
|
|
||||||
h = mergeRound(h, v2)
|
|
||||||
h = mergeRound(h, v3)
|
|
||||||
h = mergeRound(h, v4)
|
|
||||||
} else {
|
|
||||||
h = prime5
|
|
||||||
}
|
|
||||||
|
|
||||||
h += uint64(n)
|
|
||||||
|
|
||||||
i, end := 0, len(b)
|
|
||||||
for ; i+8 <= end; i += 8 {
|
|
||||||
k1 := round(0, u64(b[i:i+8:len(b)]))
|
|
||||||
h ^= k1
|
|
||||||
h = rol27(h)*prime1 + prime4
|
|
||||||
}
|
|
||||||
if i+4 <= end {
|
|
||||||
h ^= uint64(u32(b[i:i+4:len(b)])) * prime1
|
|
||||||
h = rol23(h)*prime2 + prime3
|
|
||||||
i += 4
|
|
||||||
}
|
|
||||||
for ; i < end; i++ {
|
|
||||||
h ^= uint64(b[i]) * prime5
|
|
||||||
h = rol11(h) * prime1
|
|
||||||
}
|
|
||||||
|
|
||||||
h ^= h >> 33
|
|
||||||
h *= prime2
|
|
||||||
h ^= h >> 29
|
|
||||||
h *= prime3
|
|
||||||
h ^= h >> 32
|
|
||||||
|
|
||||||
return h
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeBlocks(d *Digest, b []byte) int {
|
|
||||||
v1, v2, v3, v4 := d.v1, d.v2, d.v3, d.v4
|
|
||||||
n := len(b)
|
|
||||||
for len(b) >= 32 {
|
|
||||||
v1 = round(v1, u64(b[0:8:len(b)]))
|
|
||||||
v2 = round(v2, u64(b[8:16:len(b)]))
|
|
||||||
v3 = round(v3, u64(b[16:24:len(b)]))
|
|
||||||
v4 = round(v4, u64(b[24:32:len(b)]))
|
|
||||||
b = b[32:len(b):len(b)]
|
|
||||||
}
|
|
||||||
d.v1, d.v2, d.v3, d.v4 = v1, v2, v3, v4
|
|
||||||
return n - len(b)
|
|
||||||
}
|
|
15
vendor/github.com/cespare/xxhash/v2/xxhash_safe.go
generated
vendored
15
vendor/github.com/cespare/xxhash/v2/xxhash_safe.go
generated
vendored
|
@ -1,15 +0,0 @@
|
||||||
// +build appengine
|
|
||||||
|
|
||||||
// This file contains the safe implementations of otherwise unsafe-using code.
|
|
||||||
|
|
||||||
package xxhash
|
|
||||||
|
|
||||||
// Sum64String computes the 64-bit xxHash digest of s.
|
|
||||||
func Sum64String(s string) uint64 {
|
|
||||||
return Sum64([]byte(s))
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteString adds more data to d. It always returns len(s), nil.
|
|
||||||
func (d *Digest) WriteString(s string) (n int, err error) {
|
|
||||||
return d.Write([]byte(s))
|
|
||||||
}
|
|
46
vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go
generated
vendored
46
vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go
generated
vendored
|
@ -1,46 +0,0 @@
|
||||||
// +build !appengine
|
|
||||||
|
|
||||||
// This file encapsulates usage of unsafe.
|
|
||||||
// xxhash_safe.go contains the safe implementations.
|
|
||||||
|
|
||||||
package xxhash
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Notes:
|
|
||||||
//
|
|
||||||
// See https://groups.google.com/d/msg/golang-nuts/dcjzJy-bSpw/tcZYBzQqAQAJ
|
|
||||||
// for some discussion about these unsafe conversions.
|
|
||||||
//
|
|
||||||
// In the future it's possible that compiler optimizations will make these
|
|
||||||
// unsafe operations unnecessary: https://golang.org/issue/2205.
|
|
||||||
//
|
|
||||||
// Both of these wrapper functions still incur function call overhead since they
|
|
||||||
// will not be inlined. We could write Go/asm copies of Sum64 and Digest.Write
|
|
||||||
// for strings to squeeze out a bit more speed. Mid-stack inlining should
|
|
||||||
// eventually fix this.
|
|
||||||
|
|
||||||
// Sum64String computes the 64-bit xxHash digest of s.
|
|
||||||
// It may be faster than Sum64([]byte(s)) by avoiding a copy.
|
|
||||||
func Sum64String(s string) uint64 {
|
|
||||||
var b []byte
|
|
||||||
bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
|
|
||||||
bh.Data = (*reflect.StringHeader)(unsafe.Pointer(&s)).Data
|
|
||||||
bh.Len = len(s)
|
|
||||||
bh.Cap = len(s)
|
|
||||||
return Sum64(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteString adds more data to d. It always returns len(s), nil.
|
|
||||||
// It may be faster than Write([]byte(s)) by avoiding a copy.
|
|
||||||
func (d *Digest) WriteString(s string) (n int, err error) {
|
|
||||||
var b []byte
|
|
||||||
bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
|
|
||||||
bh.Data = (*reflect.StringHeader)(unsafe.Pointer(&s)).Data
|
|
||||||
bh.Len = len(s)
|
|
||||||
bh.Cap = len(s)
|
|
||||||
return d.Write(b)
|
|
||||||
}
|
|
22
vendor/github.com/go-kit/kit/LICENSE
generated
vendored
22
vendor/github.com/go-kit/kit/LICENSE
generated
vendored
|
@ -1,22 +0,0 @@
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2015 Peter Bourgon
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
|
|
151
vendor/github.com/go-kit/kit/log/README.md
generated
vendored
151
vendor/github.com/go-kit/kit/log/README.md
generated
vendored
|
@ -1,151 +0,0 @@
|
||||||
# package log
|
|
||||||
|
|
||||||
`package log` provides a minimal interface for structured logging in services.
|
|
||||||
It may be wrapped to encode conventions, enforce type-safety, provide leveled
|
|
||||||
logging, and so on. It can be used for both typical application log events,
|
|
||||||
and log-structured data streams.
|
|
||||||
|
|
||||||
## Structured logging
|
|
||||||
|
|
||||||
Structured logging is, basically, conceding to the reality that logs are
|
|
||||||
_data_, and warrant some level of schematic rigor. Using a stricter,
|
|
||||||
key/value-oriented message format for our logs, containing contextual and
|
|
||||||
semantic information, makes it much easier to get insight into the
|
|
||||||
operational activity of the systems we build. Consequently, `package log` is
|
|
||||||
of the strong belief that "[the benefits of structured logging outweigh the
|
|
||||||
minimal effort involved](https://www.thoughtworks.com/radar/techniques/structured-logging)".
|
|
||||||
|
|
||||||
Migrating from unstructured to structured logging is probably a lot easier
|
|
||||||
than you'd expect.
|
|
||||||
|
|
||||||
```go
|
|
||||||
// Unstructured
|
|
||||||
log.Printf("HTTP server listening on %s", addr)
|
|
||||||
|
|
||||||
// Structured
|
|
||||||
logger.Log("transport", "HTTP", "addr", addr, "msg", "listening")
|
|
||||||
```
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
### Typical application logging
|
|
||||||
|
|
||||||
```go
|
|
||||||
w := log.NewSyncWriter(os.Stderr)
|
|
||||||
logger := log.NewLogfmtLogger(w)
|
|
||||||
logger.Log("question", "what is the meaning of life?", "answer", 42)
|
|
||||||
|
|
||||||
// Output:
|
|
||||||
// question="what is the meaning of life?" answer=42
|
|
||||||
```
|
|
||||||
|
|
||||||
### Contextual Loggers
|
|
||||||
|
|
||||||
```go
|
|
||||||
func main() {
|
|
||||||
var logger log.Logger
|
|
||||||
logger = log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr))
|
|
||||||
logger = log.With(logger, "instance_id", 123)
|
|
||||||
|
|
||||||
logger.Log("msg", "starting")
|
|
||||||
NewWorker(log.With(logger, "component", "worker")).Run()
|
|
||||||
NewSlacker(log.With(logger, "component", "slacker")).Run()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Output:
|
|
||||||
// instance_id=123 msg=starting
|
|
||||||
// instance_id=123 component=worker msg=running
|
|
||||||
// instance_id=123 component=slacker msg=running
|
|
||||||
```
|
|
||||||
|
|
||||||
### Interact with stdlib logger
|
|
||||||
|
|
||||||
Redirect stdlib logger to Go kit logger.
|
|
||||||
|
|
||||||
```go
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
stdlog "log"
|
|
||||||
kitlog "github.com/go-kit/kit/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
logger := kitlog.NewJSONLogger(kitlog.NewSyncWriter(os.Stdout))
|
|
||||||
stdlog.SetOutput(kitlog.NewStdlibAdapter(logger))
|
|
||||||
stdlog.Print("I sure like pie")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Output:
|
|
||||||
// {"msg":"I sure like pie","ts":"2016/01/01 12:34:56"}
|
|
||||||
```
|
|
||||||
|
|
||||||
Or, if, for legacy reasons, you need to pipe all of your logging through the
|
|
||||||
stdlib log package, you can redirect Go kit logger to the stdlib logger.
|
|
||||||
|
|
||||||
```go
|
|
||||||
logger := kitlog.NewLogfmtLogger(kitlog.StdlibWriter{})
|
|
||||||
logger.Log("legacy", true, "msg", "at least it's something")
|
|
||||||
|
|
||||||
// Output:
|
|
||||||
// 2016/01/01 12:34:56 legacy=true msg="at least it's something"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Timestamps and callers
|
|
||||||
|
|
||||||
```go
|
|
||||||
var logger log.Logger
|
|
||||||
logger = log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr))
|
|
||||||
logger = log.With(logger, "ts", log.DefaultTimestampUTC, "caller", log.DefaultCaller)
|
|
||||||
|
|
||||||
logger.Log("msg", "hello")
|
|
||||||
|
|
||||||
// Output:
|
|
||||||
// ts=2016-01-01T12:34:56Z caller=main.go:15 msg=hello
|
|
||||||
```
|
|
||||||
|
|
||||||
## Levels
|
|
||||||
|
|
||||||
Log levels are supported via the [level package](https://godoc.org/github.com/go-kit/kit/log/level).
|
|
||||||
|
|
||||||
## Supported output formats
|
|
||||||
|
|
||||||
- [Logfmt](https://brandur.org/logfmt) ([see also](https://blog.codeship.com/logfmt-a-log-format-thats-easy-to-read-and-write))
|
|
||||||
- JSON
|
|
||||||
|
|
||||||
## Enhancements
|
|
||||||
|
|
||||||
`package log` is centered on the one-method Logger interface.
|
|
||||||
|
|
||||||
```go
|
|
||||||
type Logger interface {
|
|
||||||
Log(keyvals ...interface{}) error
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
This interface, and its supporting code like is the product of much iteration
|
|
||||||
and evaluation. For more details on the evolution of the Logger interface,
|
|
||||||
see [The Hunt for a Logger Interface](http://go-talks.appspot.com/github.com/ChrisHines/talks/structured-logging/structured-logging.slide#1),
|
|
||||||
a talk by [Chris Hines](https://github.com/ChrisHines).
|
|
||||||
Also, please see
|
|
||||||
[#63](https://github.com/go-kit/kit/issues/63),
|
|
||||||
[#76](https://github.com/go-kit/kit/pull/76),
|
|
||||||
[#131](https://github.com/go-kit/kit/issues/131),
|
|
||||||
[#157](https://github.com/go-kit/kit/pull/157),
|
|
||||||
[#164](https://github.com/go-kit/kit/issues/164), and
|
|
||||||
[#252](https://github.com/go-kit/kit/pull/252)
|
|
||||||
to review historical conversations about package log and the Logger interface.
|
|
||||||
|
|
||||||
Value-add packages and suggestions,
|
|
||||||
like improvements to [the leveled logger](https://godoc.org/github.com/go-kit/kit/log/level),
|
|
||||||
are of course welcome. Good proposals should
|
|
||||||
|
|
||||||
- Be composable with [contextual loggers](https://godoc.org/github.com/go-kit/kit/log#With),
|
|
||||||
- Not break the behavior of [log.Caller](https://godoc.org/github.com/go-kit/kit/log#Caller) in any wrapped contextual loggers, and
|
|
||||||
- Be friendly to packages that accept only an unadorned log.Logger.
|
|
||||||
|
|
||||||
## Benchmarks & comparisons
|
|
||||||
|
|
||||||
There are a few Go logging benchmarks and comparisons that include Go kit's package log.
|
|
||||||
|
|
||||||
- [imkira/go-loggers-bench](https://github.com/imkira/go-loggers-bench) includes kit/log
|
|
||||||
- [uber-common/zap](https://github.com/uber-common/zap), a zero-alloc logging library, includes a comparison with kit/log
|
|
116
vendor/github.com/go-kit/kit/log/doc.go
generated
vendored
116
vendor/github.com/go-kit/kit/log/doc.go
generated
vendored
|
@ -1,116 +0,0 @@
|
||||||
// Package log provides a structured logger.
|
|
||||||
//
|
|
||||||
// Structured logging produces logs easily consumed later by humans or
|
|
||||||
// machines. Humans might be interested in debugging errors, or tracing
|
|
||||||
// specific requests. Machines might be interested in counting interesting
|
|
||||||
// events, or aggregating information for off-line processing. In both cases,
|
|
||||||
// it is important that the log messages are structured and actionable.
|
|
||||||
// Package log is designed to encourage both of these best practices.
|
|
||||||
//
|
|
||||||
// Basic Usage
|
|
||||||
//
|
|
||||||
// The fundamental interface is Logger. Loggers create log events from
|
|
||||||
// key/value data. The Logger interface has a single method, Log, which
|
|
||||||
// accepts a sequence of alternating key/value pairs, which this package names
|
|
||||||
// keyvals.
|
|
||||||
//
|
|
||||||
// type Logger interface {
|
|
||||||
// Log(keyvals ...interface{}) error
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Here is an example of a function using a Logger to create log events.
|
|
||||||
//
|
|
||||||
// func RunTask(task Task, logger log.Logger) string {
|
|
||||||
// logger.Log("taskID", task.ID, "event", "starting task")
|
|
||||||
// ...
|
|
||||||
// logger.Log("taskID", task.ID, "event", "task complete")
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// The keys in the above example are "taskID" and "event". The values are
|
|
||||||
// task.ID, "starting task", and "task complete". Every key is followed
|
|
||||||
// immediately by its value.
|
|
||||||
//
|
|
||||||
// Keys are usually plain strings. Values may be any type that has a sensible
|
|
||||||
// encoding in the chosen log format. With structured logging it is a good
|
|
||||||
// idea to log simple values without formatting them. This practice allows
|
|
||||||
// the chosen logger to encode values in the most appropriate way.
|
|
||||||
//
|
|
||||||
// Contextual Loggers
|
|
||||||
//
|
|
||||||
// A contextual logger stores keyvals that it includes in all log events.
|
|
||||||
// Building appropriate contextual loggers reduces repetition and aids
|
|
||||||
// consistency in the resulting log output. With and WithPrefix add context to
|
|
||||||
// a logger. We can use With to improve the RunTask example.
|
|
||||||
//
|
|
||||||
// func RunTask(task Task, logger log.Logger) string {
|
|
||||||
// logger = log.With(logger, "taskID", task.ID)
|
|
||||||
// logger.Log("event", "starting task")
|
|
||||||
// ...
|
|
||||||
// taskHelper(task.Cmd, logger)
|
|
||||||
// ...
|
|
||||||
// logger.Log("event", "task complete")
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// The improved version emits the same log events as the original for the
|
|
||||||
// first and last calls to Log. Passing the contextual logger to taskHelper
|
|
||||||
// enables each log event created by taskHelper to include the task.ID even
|
|
||||||
// though taskHelper does not have access to that value. Using contextual
|
|
||||||
// loggers this way simplifies producing log output that enables tracing the
|
|
||||||
// life cycle of individual tasks. (See the Contextual example for the full
|
|
||||||
// code of the above snippet.)
|
|
||||||
//
|
|
||||||
// Dynamic Contextual Values
|
|
||||||
//
|
|
||||||
// A Valuer function stored in a contextual logger generates a new value each
|
|
||||||
// time an event is logged. The Valuer example demonstrates how this feature
|
|
||||||
// works.
|
|
||||||
//
|
|
||||||
// Valuers provide the basis for consistently logging timestamps and source
|
|
||||||
// code location. The log package defines several valuers for that purpose.
|
|
||||||
// See Timestamp, DefaultTimestamp, DefaultTimestampUTC, Caller, and
|
|
||||||
// DefaultCaller. A common logger initialization sequence that ensures all log
|
|
||||||
// entries contain a timestamp and source location looks like this:
|
|
||||||
//
|
|
||||||
// logger := log.NewLogfmtLogger(log.NewSyncWriter(os.Stdout))
|
|
||||||
// logger = log.With(logger, "ts", log.DefaultTimestampUTC, "caller", log.DefaultCaller)
|
|
||||||
//
|
|
||||||
// Concurrent Safety
|
|
||||||
//
|
|
||||||
// Applications with multiple goroutines want each log event written to the
|
|
||||||
// same logger to remain separate from other log events. Package log provides
|
|
||||||
// two simple solutions for concurrent safe logging.
|
|
||||||
//
|
|
||||||
// NewSyncWriter wraps an io.Writer and serializes each call to its Write
|
|
||||||
// method. Using a SyncWriter has the benefit that the smallest practical
|
|
||||||
// portion of the logging logic is performed within a mutex, but it requires
|
|
||||||
// the formatting Logger to make only one call to Write per log event.
|
|
||||||
//
|
|
||||||
// NewSyncLogger wraps any Logger and serializes each call to its Log method.
|
|
||||||
// Using a SyncLogger has the benefit that it guarantees each log event is
|
|
||||||
// handled atomically within the wrapped logger, but it typically serializes
|
|
||||||
// both the formatting and output logic. Use a SyncLogger if the formatting
|
|
||||||
// logger may perform multiple writes per log event.
|
|
||||||
//
|
|
||||||
// Error Handling
|
|
||||||
//
|
|
||||||
// This package relies on the practice of wrapping or decorating loggers with
|
|
||||||
// other loggers to provide composable pieces of functionality. It also means
|
|
||||||
// that Logger.Log must return an error because some
|
|
||||||
// implementations—especially those that output log data to an io.Writer—may
|
|
||||||
// encounter errors that cannot be handled locally. This in turn means that
|
|
||||||
// Loggers that wrap other loggers should return errors from the wrapped
|
|
||||||
// logger up the stack.
|
|
||||||
//
|
|
||||||
// Fortunately, the decorator pattern also provides a way to avoid the
|
|
||||||
// necessity to check for errors every time an application calls Logger.Log.
|
|
||||||
// An application required to panic whenever its Logger encounters
|
|
||||||
// an error could initialize its logger as follows.
|
|
||||||
//
|
|
||||||
// fmtlogger := log.NewLogfmtLogger(log.NewSyncWriter(os.Stdout))
|
|
||||||
// logger := log.LoggerFunc(func(keyvals ...interface{}) error {
|
|
||||||
// if err := fmtlogger.Log(keyvals...); err != nil {
|
|
||||||
// panic(err)
|
|
||||||
// }
|
|
||||||
// return nil
|
|
||||||
// })
|
|
||||||
package log
|
|
91
vendor/github.com/go-kit/kit/log/json_logger.go
generated
vendored
91
vendor/github.com/go-kit/kit/log/json_logger.go
generated
vendored
|
@ -1,91 +0,0 @@
|
||||||
package log
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"reflect"
|
|
||||||
)
|
|
||||||
|
|
||||||
type jsonLogger struct {
|
|
||||||
io.Writer
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewJSONLogger returns a Logger that encodes keyvals to the Writer as a
|
|
||||||
// single JSON object. Each log event produces no more than one call to
|
|
||||||
// w.Write. The passed Writer must be safe for concurrent use by multiple
|
|
||||||
// goroutines if the returned Logger will be used concurrently.
|
|
||||||
func NewJSONLogger(w io.Writer) Logger {
|
|
||||||
return &jsonLogger{w}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *jsonLogger) Log(keyvals ...interface{}) error {
|
|
||||||
n := (len(keyvals) + 1) / 2 // +1 to handle case when len is odd
|
|
||||||
m := make(map[string]interface{}, n)
|
|
||||||
for i := 0; i < len(keyvals); i += 2 {
|
|
||||||
k := keyvals[i]
|
|
||||||
var v interface{} = ErrMissingValue
|
|
||||||
if i+1 < len(keyvals) {
|
|
||||||
v = keyvals[i+1]
|
|
||||||
}
|
|
||||||
merge(m, k, v)
|
|
||||||
}
|
|
||||||
enc := json.NewEncoder(l.Writer)
|
|
||||||
enc.SetEscapeHTML(false)
|
|
||||||
return enc.Encode(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
func merge(dst map[string]interface{}, k, v interface{}) {
|
|
||||||
var key string
|
|
||||||
switch x := k.(type) {
|
|
||||||
case string:
|
|
||||||
key = x
|
|
||||||
case fmt.Stringer:
|
|
||||||
key = safeString(x)
|
|
||||||
default:
|
|
||||||
key = fmt.Sprint(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// We want json.Marshaler and encoding.TextMarshaller to take priority over
|
|
||||||
// err.Error() and v.String(). But json.Marshall (called later) does that by
|
|
||||||
// default so we force a no-op if it's one of those 2 case.
|
|
||||||
switch x := v.(type) {
|
|
||||||
case json.Marshaler:
|
|
||||||
case encoding.TextMarshaler:
|
|
||||||
case error:
|
|
||||||
v = safeError(x)
|
|
||||||
case fmt.Stringer:
|
|
||||||
v = safeString(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
dst[key] = v
|
|
||||||
}
|
|
||||||
|
|
||||||
func safeString(str fmt.Stringer) (s string) {
|
|
||||||
defer func() {
|
|
||||||
if panicVal := recover(); panicVal != nil {
|
|
||||||
if v := reflect.ValueOf(str); v.Kind() == reflect.Ptr && v.IsNil() {
|
|
||||||
s = "NULL"
|
|
||||||
} else {
|
|
||||||
panic(panicVal)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
s = str.String()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func safeError(err error) (s interface{}) {
|
|
||||||
defer func() {
|
|
||||||
if panicVal := recover(); panicVal != nil {
|
|
||||||
if v := reflect.ValueOf(err); v.Kind() == reflect.Ptr && v.IsNil() {
|
|
||||||
s = nil
|
|
||||||
} else {
|
|
||||||
panic(panicVal)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
s = err.Error()
|
|
||||||
return
|
|
||||||
}
|
|
22
vendor/github.com/go-kit/kit/log/level/doc.go
generated
vendored
22
vendor/github.com/go-kit/kit/log/level/doc.go
generated
vendored
|
@ -1,22 +0,0 @@
|
||||||
// Package level implements leveled logging on top of Go kit's log package. To
|
|
||||||
// use the level package, create a logger as per normal in your func main, and
|
|
||||||
// wrap it with level.NewFilter.
|
|
||||||
//
|
|
||||||
// var logger log.Logger
|
|
||||||
// logger = log.NewLogfmtLogger(os.Stderr)
|
|
||||||
// logger = level.NewFilter(logger, level.AllowInfo()) // <--
|
|
||||||
// logger = log.With(logger, "ts", log.DefaultTimestampUTC)
|
|
||||||
//
|
|
||||||
// Then, at the callsites, use one of the level.Debug, Info, Warn, or Error
|
|
||||||
// helper methods to emit leveled log events.
|
|
||||||
//
|
|
||||||
// logger.Log("foo", "bar") // as normal, no level
|
|
||||||
// level.Debug(logger).Log("request_id", reqID, "trace_data", trace.Get())
|
|
||||||
// if value > 100 {
|
|
||||||
// level.Error(logger).Log("value", value)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// NewFilter allows precise control over what happens when a log event is
|
|
||||||
// emitted without a level key, or if a squelched level is used. Check the
|
|
||||||
// Option functions for details.
|
|
||||||
package level
|
|
205
vendor/github.com/go-kit/kit/log/level/level.go
generated
vendored
205
vendor/github.com/go-kit/kit/log/level/level.go
generated
vendored
|
@ -1,205 +0,0 @@
|
||||||
package level
|
|
||||||
|
|
||||||
import "github.com/go-kit/kit/log"
|
|
||||||
|
|
||||||
// Error returns a logger that includes a Key/ErrorValue pair.
|
|
||||||
func Error(logger log.Logger) log.Logger {
|
|
||||||
return log.WithPrefix(logger, Key(), ErrorValue())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Warn returns a logger that includes a Key/WarnValue pair.
|
|
||||||
func Warn(logger log.Logger) log.Logger {
|
|
||||||
return log.WithPrefix(logger, Key(), WarnValue())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Info returns a logger that includes a Key/InfoValue pair.
|
|
||||||
func Info(logger log.Logger) log.Logger {
|
|
||||||
return log.WithPrefix(logger, Key(), InfoValue())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Debug returns a logger that includes a Key/DebugValue pair.
|
|
||||||
func Debug(logger log.Logger) log.Logger {
|
|
||||||
return log.WithPrefix(logger, Key(), DebugValue())
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewFilter wraps next and implements level filtering. See the commentary on
|
|
||||||
// the Option functions for a detailed description of how to configure levels.
|
|
||||||
// If no options are provided, all leveled log events created with Debug,
|
|
||||||
// Info, Warn or Error helper methods are squelched and non-leveled log
|
|
||||||
// events are passed to next unmodified.
|
|
||||||
func NewFilter(next log.Logger, options ...Option) log.Logger {
|
|
||||||
l := &logger{
|
|
||||||
next: next,
|
|
||||||
}
|
|
||||||
for _, option := range options {
|
|
||||||
option(l)
|
|
||||||
}
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
|
|
||||||
type logger struct {
|
|
||||||
next log.Logger
|
|
||||||
allowed level
|
|
||||||
squelchNoLevel bool
|
|
||||||
errNotAllowed error
|
|
||||||
errNoLevel error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *logger) Log(keyvals ...interface{}) error {
|
|
||||||
var hasLevel, levelAllowed bool
|
|
||||||
for i := 1; i < len(keyvals); i += 2 {
|
|
||||||
if v, ok := keyvals[i].(*levelValue); ok {
|
|
||||||
hasLevel = true
|
|
||||||
levelAllowed = l.allowed&v.level != 0
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !hasLevel && l.squelchNoLevel {
|
|
||||||
return l.errNoLevel
|
|
||||||
}
|
|
||||||
if hasLevel && !levelAllowed {
|
|
||||||
return l.errNotAllowed
|
|
||||||
}
|
|
||||||
return l.next.Log(keyvals...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Option sets a parameter for the leveled logger.
|
|
||||||
type Option func(*logger)
|
|
||||||
|
|
||||||
// AllowAll is an alias for AllowDebug.
|
|
||||||
func AllowAll() Option {
|
|
||||||
return AllowDebug()
|
|
||||||
}
|
|
||||||
|
|
||||||
// AllowDebug allows error, warn, info and debug level log events to pass.
|
|
||||||
func AllowDebug() Option {
|
|
||||||
return allowed(levelError | levelWarn | levelInfo | levelDebug)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AllowInfo allows error, warn and info level log events to pass.
|
|
||||||
func AllowInfo() Option {
|
|
||||||
return allowed(levelError | levelWarn | levelInfo)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AllowWarn allows error and warn level log events to pass.
|
|
||||||
func AllowWarn() Option {
|
|
||||||
return allowed(levelError | levelWarn)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AllowError allows only error level log events to pass.
|
|
||||||
func AllowError() Option {
|
|
||||||
return allowed(levelError)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AllowNone allows no leveled log events to pass.
|
|
||||||
func AllowNone() Option {
|
|
||||||
return allowed(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func allowed(allowed level) Option {
|
|
||||||
return func(l *logger) { l.allowed = allowed }
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrNotAllowed sets the error to return from Log when it squelches a log
|
|
||||||
// event disallowed by the configured Allow[Level] option. By default,
|
|
||||||
// ErrNotAllowed is nil; in this case the log event is squelched with no
|
|
||||||
// error.
|
|
||||||
func ErrNotAllowed(err error) Option {
|
|
||||||
return func(l *logger) { l.errNotAllowed = err }
|
|
||||||
}
|
|
||||||
|
|
||||||
// SquelchNoLevel instructs Log to squelch log events with no level, so that
|
|
||||||
// they don't proceed through to the wrapped logger. If SquelchNoLevel is set
|
|
||||||
// to true and a log event is squelched in this way, the error value
|
|
||||||
// configured with ErrNoLevel is returned to the caller.
|
|
||||||
func SquelchNoLevel(squelch bool) Option {
|
|
||||||
return func(l *logger) { l.squelchNoLevel = squelch }
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrNoLevel sets the error to return from Log when it squelches a log event
|
|
||||||
// with no level. By default, ErrNoLevel is nil; in this case the log event is
|
|
||||||
// squelched with no error.
|
|
||||||
func ErrNoLevel(err error) Option {
|
|
||||||
return func(l *logger) { l.errNoLevel = err }
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewInjector wraps next and returns a logger that adds a Key/level pair to
|
|
||||||
// the beginning of log events that don't already contain a level. In effect,
|
|
||||||
// this gives a default level to logs without a level.
|
|
||||||
func NewInjector(next log.Logger, level Value) log.Logger {
|
|
||||||
return &injector{
|
|
||||||
next: next,
|
|
||||||
level: level,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type injector struct {
|
|
||||||
next log.Logger
|
|
||||||
level interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *injector) Log(keyvals ...interface{}) error {
|
|
||||||
for i := 1; i < len(keyvals); i += 2 {
|
|
||||||
if _, ok := keyvals[i].(*levelValue); ok {
|
|
||||||
return l.next.Log(keyvals...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
kvs := make([]interface{}, len(keyvals)+2)
|
|
||||||
kvs[0], kvs[1] = key, l.level
|
|
||||||
copy(kvs[2:], keyvals)
|
|
||||||
return l.next.Log(kvs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Value is the interface that each of the canonical level values implement.
|
|
||||||
// It contains unexported methods that prevent types from other packages from
|
|
||||||
// implementing it and guaranteeing that NewFilter can distinguish the levels
|
|
||||||
// defined in this package from all other values.
|
|
||||||
type Value interface {
|
|
||||||
String() string
|
|
||||||
levelVal()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Key returns the unique key added to log events by the loggers in this
|
|
||||||
// package.
|
|
||||||
func Key() interface{} { return key }
|
|
||||||
|
|
||||||
// ErrorValue returns the unique value added to log events by Error.
|
|
||||||
func ErrorValue() Value { return errorValue }
|
|
||||||
|
|
||||||
// WarnValue returns the unique value added to log events by Warn.
|
|
||||||
func WarnValue() Value { return warnValue }
|
|
||||||
|
|
||||||
// InfoValue returns the unique value added to log events by Info.
|
|
||||||
func InfoValue() Value { return infoValue }
|
|
||||||
|
|
||||||
// DebugValue returns the unique value added to log events by Warn.
|
|
||||||
func DebugValue() Value { return debugValue }
|
|
||||||
|
|
||||||
var (
|
|
||||||
// key is of type interface{} so that it allocates once during package
|
|
||||||
// initialization and avoids allocating every time the value is added to a
|
|
||||||
// []interface{} later.
|
|
||||||
key interface{} = "level"
|
|
||||||
|
|
||||||
errorValue = &levelValue{level: levelError, name: "error"}
|
|
||||||
warnValue = &levelValue{level: levelWarn, name: "warn"}
|
|
||||||
infoValue = &levelValue{level: levelInfo, name: "info"}
|
|
||||||
debugValue = &levelValue{level: levelDebug, name: "debug"}
|
|
||||||
)
|
|
||||||
|
|
||||||
type level byte
|
|
||||||
|
|
||||||
const (
|
|
||||||
levelDebug level = 1 << iota
|
|
||||||
levelInfo
|
|
||||||
levelWarn
|
|
||||||
levelError
|
|
||||||
)
|
|
||||||
|
|
||||||
type levelValue struct {
|
|
||||||
name string
|
|
||||||
level
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *levelValue) String() string { return v.name }
|
|
||||||
func (v *levelValue) levelVal() {}
|
|
135
vendor/github.com/go-kit/kit/log/log.go
generated
vendored
135
vendor/github.com/go-kit/kit/log/log.go
generated
vendored
|
@ -1,135 +0,0 @@
|
||||||
package log
|
|
||||||
|
|
||||||
import "errors"
|
|
||||||
|
|
||||||
// Logger is the fundamental interface for all log operations. Log creates a
|
|
||||||
// log event from keyvals, a variadic sequence of alternating keys and values.
|
|
||||||
// Implementations must be safe for concurrent use by multiple goroutines. In
|
|
||||||
// particular, any implementation of Logger that appends to keyvals or
|
|
||||||
// modifies or retains any of its elements must make a copy first.
|
|
||||||
type Logger interface {
|
|
||||||
Log(keyvals ...interface{}) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrMissingValue is appended to keyvals slices with odd length to substitute
|
|
||||||
// the missing value.
|
|
||||||
var ErrMissingValue = errors.New("(MISSING)")
|
|
||||||
|
|
||||||
// With returns a new contextual logger with keyvals prepended to those passed
|
|
||||||
// to calls to Log. If logger is also a contextual logger created by With or
|
|
||||||
// WithPrefix, keyvals is appended to the existing context.
|
|
||||||
//
|
|
||||||
// The returned Logger replaces all value elements (odd indexes) containing a
|
|
||||||
// Valuer with their generated value for each call to its Log method.
|
|
||||||
func With(logger Logger, keyvals ...interface{}) Logger {
|
|
||||||
if len(keyvals) == 0 {
|
|
||||||
return logger
|
|
||||||
}
|
|
||||||
l := newContext(logger)
|
|
||||||
kvs := append(l.keyvals, keyvals...)
|
|
||||||
if len(kvs)%2 != 0 {
|
|
||||||
kvs = append(kvs, ErrMissingValue)
|
|
||||||
}
|
|
||||||
return &context{
|
|
||||||
logger: l.logger,
|
|
||||||
// Limiting the capacity of the stored keyvals ensures that a new
|
|
||||||
// backing array is created if the slice must grow in Log or With.
|
|
||||||
// Using the extra capacity without copying risks a data race that
|
|
||||||
// would violate the Logger interface contract.
|
|
||||||
keyvals: kvs[:len(kvs):len(kvs)],
|
|
||||||
hasValuer: l.hasValuer || containsValuer(keyvals),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithPrefix returns a new contextual logger with keyvals prepended to those
|
|
||||||
// passed to calls to Log. If logger is also a contextual logger created by
|
|
||||||
// With or WithPrefix, keyvals is prepended to the existing context.
|
|
||||||
//
|
|
||||||
// The returned Logger replaces all value elements (odd indexes) containing a
|
|
||||||
// Valuer with their generated value for each call to its Log method.
|
|
||||||
func WithPrefix(logger Logger, keyvals ...interface{}) Logger {
|
|
||||||
if len(keyvals) == 0 {
|
|
||||||
return logger
|
|
||||||
}
|
|
||||||
l := newContext(logger)
|
|
||||||
// Limiting the capacity of the stored keyvals ensures that a new
|
|
||||||
// backing array is created if the slice must grow in Log or With.
|
|
||||||
// Using the extra capacity without copying risks a data race that
|
|
||||||
// would violate the Logger interface contract.
|
|
||||||
n := len(l.keyvals) + len(keyvals)
|
|
||||||
if len(keyvals)%2 != 0 {
|
|
||||||
n++
|
|
||||||
}
|
|
||||||
kvs := make([]interface{}, 0, n)
|
|
||||||
kvs = append(kvs, keyvals...)
|
|
||||||
if len(kvs)%2 != 0 {
|
|
||||||
kvs = append(kvs, ErrMissingValue)
|
|
||||||
}
|
|
||||||
kvs = append(kvs, l.keyvals...)
|
|
||||||
return &context{
|
|
||||||
logger: l.logger,
|
|
||||||
keyvals: kvs,
|
|
||||||
hasValuer: l.hasValuer || containsValuer(keyvals),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// context is the Logger implementation returned by With and WithPrefix. It
|
|
||||||
// wraps a Logger and holds keyvals that it includes in all log events. Its
|
|
||||||
// Log method calls bindValues to generate values for each Valuer in the
|
|
||||||
// context keyvals.
|
|
||||||
//
|
|
||||||
// A context must always have the same number of stack frames between calls to
|
|
||||||
// its Log method and the eventual binding of Valuers to their value. This
|
|
||||||
// requirement comes from the functional requirement to allow a context to
|
|
||||||
// resolve application call site information for a Caller stored in the
|
|
||||||
// context. To do this we must be able to predict the number of logging
|
|
||||||
// functions on the stack when bindValues is called.
|
|
||||||
//
|
|
||||||
// Two implementation details provide the needed stack depth consistency.
|
|
||||||
//
|
|
||||||
// 1. newContext avoids introducing an additional layer when asked to
|
|
||||||
// wrap another context.
|
|
||||||
// 2. With and WithPrefix avoid introducing an additional layer by
|
|
||||||
// returning a newly constructed context with a merged keyvals rather
|
|
||||||
// than simply wrapping the existing context.
|
|
||||||
type context struct {
|
|
||||||
logger Logger
|
|
||||||
keyvals []interface{}
|
|
||||||
hasValuer bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func newContext(logger Logger) *context {
|
|
||||||
if c, ok := logger.(*context); ok {
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
return &context{logger: logger}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log replaces all value elements (odd indexes) containing a Valuer in the
|
|
||||||
// stored context with their generated value, appends keyvals, and passes the
|
|
||||||
// result to the wrapped Logger.
|
|
||||||
func (l *context) Log(keyvals ...interface{}) error {
|
|
||||||
kvs := append(l.keyvals, keyvals...)
|
|
||||||
if len(kvs)%2 != 0 {
|
|
||||||
kvs = append(kvs, ErrMissingValue)
|
|
||||||
}
|
|
||||||
if l.hasValuer {
|
|
||||||
// If no keyvals were appended above then we must copy l.keyvals so
|
|
||||||
// that future log events will reevaluate the stored Valuers.
|
|
||||||
if len(keyvals) == 0 {
|
|
||||||
kvs = append([]interface{}{}, l.keyvals...)
|
|
||||||
}
|
|
||||||
bindValues(kvs[:len(l.keyvals)])
|
|
||||||
}
|
|
||||||
return l.logger.Log(kvs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoggerFunc is an adapter to allow use of ordinary functions as Loggers. If
|
|
||||||
// f is a function with the appropriate signature, LoggerFunc(f) is a Logger
|
|
||||||
// object that calls f.
|
|
||||||
type LoggerFunc func(...interface{}) error
|
|
||||||
|
|
||||||
// Log implements Logger by calling f(keyvals...).
|
|
||||||
func (f LoggerFunc) Log(keyvals ...interface{}) error {
|
|
||||||
return f(keyvals...)
|
|
||||||
}
|
|
62
vendor/github.com/go-kit/kit/log/logfmt_logger.go
generated
vendored
62
vendor/github.com/go-kit/kit/log/logfmt_logger.go
generated
vendored
|
@ -1,62 +0,0 @@
|
||||||
package log
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"io"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/go-logfmt/logfmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
type logfmtEncoder struct {
|
|
||||||
*logfmt.Encoder
|
|
||||||
buf bytes.Buffer
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *logfmtEncoder) Reset() {
|
|
||||||
l.Encoder.Reset()
|
|
||||||
l.buf.Reset()
|
|
||||||
}
|
|
||||||
|
|
||||||
var logfmtEncoderPool = sync.Pool{
|
|
||||||
New: func() interface{} {
|
|
||||||
var enc logfmtEncoder
|
|
||||||
enc.Encoder = logfmt.NewEncoder(&enc.buf)
|
|
||||||
return &enc
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
type logfmtLogger struct {
|
|
||||||
w io.Writer
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewLogfmtLogger returns a logger that encodes keyvals to the Writer in
|
|
||||||
// logfmt format. Each log event produces no more than one call to w.Write.
|
|
||||||
// The passed Writer must be safe for concurrent use by multiple goroutines if
|
|
||||||
// the returned Logger will be used concurrently.
|
|
||||||
func NewLogfmtLogger(w io.Writer) Logger {
|
|
||||||
return &logfmtLogger{w}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l logfmtLogger) Log(keyvals ...interface{}) error {
|
|
||||||
enc := logfmtEncoderPool.Get().(*logfmtEncoder)
|
|
||||||
enc.Reset()
|
|
||||||
defer logfmtEncoderPool.Put(enc)
|
|
||||||
|
|
||||||
if err := enc.EncodeKeyvals(keyvals...); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add newline to the end of the buffer
|
|
||||||
if err := enc.EndRecord(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// The Logger interface requires implementations to be safe for concurrent
|
|
||||||
// use by multiple goroutines. For this implementation that means making
|
|
||||||
// only one call to l.w.Write() for each call to Log.
|
|
||||||
if _, err := l.w.Write(enc.buf.Bytes()); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
8
vendor/github.com/go-kit/kit/log/nop_logger.go
generated
vendored
8
vendor/github.com/go-kit/kit/log/nop_logger.go
generated
vendored
|
@ -1,8 +0,0 @@
|
||||||
package log
|
|
||||||
|
|
||||||
type nopLogger struct{}
|
|
||||||
|
|
||||||
// NewNopLogger returns a logger that doesn't do anything.
|
|
||||||
func NewNopLogger() Logger { return nopLogger{} }
|
|
||||||
|
|
||||||
func (nopLogger) Log(...interface{}) error { return nil }
|
|
116
vendor/github.com/go-kit/kit/log/stdlib.go
generated
vendored
116
vendor/github.com/go-kit/kit/log/stdlib.go
generated
vendored
|
@ -1,116 +0,0 @@
|
||||||
package log
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// StdlibWriter implements io.Writer by invoking the stdlib log.Print. It's
|
|
||||||
// designed to be passed to a Go kit logger as the writer, for cases where
|
|
||||||
// it's necessary to redirect all Go kit log output to the stdlib logger.
|
|
||||||
//
|
|
||||||
// If you have any choice in the matter, you shouldn't use this. Prefer to
|
|
||||||
// redirect the stdlib log to the Go kit logger via NewStdlibAdapter.
|
|
||||||
type StdlibWriter struct{}
|
|
||||||
|
|
||||||
// Write implements io.Writer.
|
|
||||||
func (w StdlibWriter) Write(p []byte) (int, error) {
|
|
||||||
log.Print(strings.TrimSpace(string(p)))
|
|
||||||
return len(p), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// StdlibAdapter wraps a Logger and allows it to be passed to the stdlib
|
|
||||||
// logger's SetOutput. It will extract date/timestamps, filenames, and
|
|
||||||
// messages, and place them under relevant keys.
|
|
||||||
type StdlibAdapter struct {
|
|
||||||
Logger
|
|
||||||
timestampKey string
|
|
||||||
fileKey string
|
|
||||||
messageKey string
|
|
||||||
}
|
|
||||||
|
|
||||||
// StdlibAdapterOption sets a parameter for the StdlibAdapter.
|
|
||||||
type StdlibAdapterOption func(*StdlibAdapter)
|
|
||||||
|
|
||||||
// TimestampKey sets the key for the timestamp field. By default, it's "ts".
|
|
||||||
func TimestampKey(key string) StdlibAdapterOption {
|
|
||||||
return func(a *StdlibAdapter) { a.timestampKey = key }
|
|
||||||
}
|
|
||||||
|
|
||||||
// FileKey sets the key for the file and line field. By default, it's "caller".
|
|
||||||
func FileKey(key string) StdlibAdapterOption {
|
|
||||||
return func(a *StdlibAdapter) { a.fileKey = key }
|
|
||||||
}
|
|
||||||
|
|
||||||
// MessageKey sets the key for the actual log message. By default, it's "msg".
|
|
||||||
func MessageKey(key string) StdlibAdapterOption {
|
|
||||||
return func(a *StdlibAdapter) { a.messageKey = key }
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewStdlibAdapter returns a new StdlibAdapter wrapper around the passed
|
|
||||||
// logger. It's designed to be passed to log.SetOutput.
|
|
||||||
func NewStdlibAdapter(logger Logger, options ...StdlibAdapterOption) io.Writer {
|
|
||||||
a := StdlibAdapter{
|
|
||||||
Logger: logger,
|
|
||||||
timestampKey: "ts",
|
|
||||||
fileKey: "caller",
|
|
||||||
messageKey: "msg",
|
|
||||||
}
|
|
||||||
for _, option := range options {
|
|
||||||
option(&a)
|
|
||||||
}
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a StdlibAdapter) Write(p []byte) (int, error) {
|
|
||||||
result := subexps(p)
|
|
||||||
keyvals := []interface{}{}
|
|
||||||
var timestamp string
|
|
||||||
if date, ok := result["date"]; ok && date != "" {
|
|
||||||
timestamp = date
|
|
||||||
}
|
|
||||||
if time, ok := result["time"]; ok && time != "" {
|
|
||||||
if timestamp != "" {
|
|
||||||
timestamp += " "
|
|
||||||
}
|
|
||||||
timestamp += time
|
|
||||||
}
|
|
||||||
if timestamp != "" {
|
|
||||||
keyvals = append(keyvals, a.timestampKey, timestamp)
|
|
||||||
}
|
|
||||||
if file, ok := result["file"]; ok && file != "" {
|
|
||||||
keyvals = append(keyvals, a.fileKey, file)
|
|
||||||
}
|
|
||||||
if msg, ok := result["msg"]; ok {
|
|
||||||
keyvals = append(keyvals, a.messageKey, msg)
|
|
||||||
}
|
|
||||||
if err := a.Logger.Log(keyvals...); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return len(p), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
logRegexpDate = `(?P<date>[0-9]{4}/[0-9]{2}/[0-9]{2})?[ ]?`
|
|
||||||
logRegexpTime = `(?P<time>[0-9]{2}:[0-9]{2}:[0-9]{2}(\.[0-9]+)?)?[ ]?`
|
|
||||||
logRegexpFile = `(?P<file>.+?:[0-9]+)?`
|
|
||||||
logRegexpMsg = `(: )?(?P<msg>.*)`
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
logRegexp = regexp.MustCompile(logRegexpDate + logRegexpTime + logRegexpFile + logRegexpMsg)
|
|
||||||
)
|
|
||||||
|
|
||||||
func subexps(line []byte) map[string]string {
|
|
||||||
m := logRegexp.FindSubmatch(line)
|
|
||||||
if len(m) < len(logRegexp.SubexpNames()) {
|
|
||||||
return map[string]string{}
|
|
||||||
}
|
|
||||||
result := map[string]string{}
|
|
||||||
for i, name := range logRegexp.SubexpNames() {
|
|
||||||
result[name] = string(m[i])
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
116
vendor/github.com/go-kit/kit/log/sync.go
generated
vendored
116
vendor/github.com/go-kit/kit/log/sync.go
generated
vendored
|
@ -1,116 +0,0 @@
|
||||||
package log
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"sync"
|
|
||||||
"sync/atomic"
|
|
||||||
)
|
|
||||||
|
|
||||||
// SwapLogger wraps another logger that may be safely replaced while other
|
|
||||||
// goroutines use the SwapLogger concurrently. The zero value for a SwapLogger
|
|
||||||
// will discard all log events without error.
|
|
||||||
//
|
|
||||||
// SwapLogger serves well as a package global logger that can be changed by
|
|
||||||
// importers.
|
|
||||||
type SwapLogger struct {
|
|
||||||
logger atomic.Value
|
|
||||||
}
|
|
||||||
|
|
||||||
type loggerStruct struct {
|
|
||||||
Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log implements the Logger interface by forwarding keyvals to the currently
|
|
||||||
// wrapped logger. It does not log anything if the wrapped logger is nil.
|
|
||||||
func (l *SwapLogger) Log(keyvals ...interface{}) error {
|
|
||||||
s, ok := l.logger.Load().(loggerStruct)
|
|
||||||
if !ok || s.Logger == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return s.Log(keyvals...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Swap replaces the currently wrapped logger with logger. Swap may be called
|
|
||||||
// concurrently with calls to Log from other goroutines.
|
|
||||||
func (l *SwapLogger) Swap(logger Logger) {
|
|
||||||
l.logger.Store(loggerStruct{logger})
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewSyncWriter returns a new writer that is safe for concurrent use by
|
|
||||||
// multiple goroutines. Writes to the returned writer are passed on to w. If
|
|
||||||
// another write is already in progress, the calling goroutine blocks until
|
|
||||||
// the writer is available.
|
|
||||||
//
|
|
||||||
// If w implements the following interface, so does the returned writer.
|
|
||||||
//
|
|
||||||
// interface {
|
|
||||||
// Fd() uintptr
|
|
||||||
// }
|
|
||||||
func NewSyncWriter(w io.Writer) io.Writer {
|
|
||||||
switch w := w.(type) {
|
|
||||||
case fdWriter:
|
|
||||||
return &fdSyncWriter{fdWriter: w}
|
|
||||||
default:
|
|
||||||
return &syncWriter{Writer: w}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// syncWriter synchronizes concurrent writes to an io.Writer.
|
|
||||||
type syncWriter struct {
|
|
||||||
sync.Mutex
|
|
||||||
io.Writer
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write writes p to the underlying io.Writer. If another write is already in
|
|
||||||
// progress, the calling goroutine blocks until the syncWriter is available.
|
|
||||||
func (w *syncWriter) Write(p []byte) (n int, err error) {
|
|
||||||
w.Lock()
|
|
||||||
n, err = w.Writer.Write(p)
|
|
||||||
w.Unlock()
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// fdWriter is an io.Writer that also has an Fd method. The most common
|
|
||||||
// example of an fdWriter is an *os.File.
|
|
||||||
type fdWriter interface {
|
|
||||||
io.Writer
|
|
||||||
Fd() uintptr
|
|
||||||
}
|
|
||||||
|
|
||||||
// fdSyncWriter synchronizes concurrent writes to an fdWriter.
|
|
||||||
type fdSyncWriter struct {
|
|
||||||
sync.Mutex
|
|
||||||
fdWriter
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write writes p to the underlying io.Writer. If another write is already in
|
|
||||||
// progress, the calling goroutine blocks until the fdSyncWriter is available.
|
|
||||||
func (w *fdSyncWriter) Write(p []byte) (n int, err error) {
|
|
||||||
w.Lock()
|
|
||||||
n, err = w.fdWriter.Write(p)
|
|
||||||
w.Unlock()
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// syncLogger provides concurrent safe logging for another Logger.
|
|
||||||
type syncLogger struct {
|
|
||||||
mu sync.Mutex
|
|
||||||
logger Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewSyncLogger returns a logger that synchronizes concurrent use of the
|
|
||||||
// wrapped logger. When multiple goroutines use the SyncLogger concurrently
|
|
||||||
// only one goroutine will be allowed to log to the wrapped logger at a time.
|
|
||||||
// The other goroutines will block until the logger is available.
|
|
||||||
func NewSyncLogger(logger Logger) Logger {
|
|
||||||
return &syncLogger{logger: logger}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log logs keyvals to the underlying Logger. If another log is already in
|
|
||||||
// progress, the calling goroutine blocks until the syncLogger is available.
|
|
||||||
func (l *syncLogger) Log(keyvals ...interface{}) error {
|
|
||||||
l.mu.Lock()
|
|
||||||
err := l.logger.Log(keyvals...)
|
|
||||||
l.mu.Unlock()
|
|
||||||
return err
|
|
||||||
}
|
|
110
vendor/github.com/go-kit/kit/log/value.go
generated
vendored
110
vendor/github.com/go-kit/kit/log/value.go
generated
vendored
|
@ -1,110 +0,0 @@
|
||||||
package log
|
|
||||||
|
|
||||||
import (
|
|
||||||
"runtime"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A Valuer generates a log value. When passed to With or WithPrefix in a
|
|
||||||
// value element (odd indexes), it represents a dynamic value which is re-
|
|
||||||
// evaluated with each log event.
|
|
||||||
type Valuer func() interface{}
|
|
||||||
|
|
||||||
// bindValues replaces all value elements (odd indexes) containing a Valuer
|
|
||||||
// with their generated value.
|
|
||||||
func bindValues(keyvals []interface{}) {
|
|
||||||
for i := 1; i < len(keyvals); i += 2 {
|
|
||||||
if v, ok := keyvals[i].(Valuer); ok {
|
|
||||||
keyvals[i] = v()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// containsValuer returns true if any of the value elements (odd indexes)
|
|
||||||
// contain a Valuer.
|
|
||||||
func containsValuer(keyvals []interface{}) bool {
|
|
||||||
for i := 1; i < len(keyvals); i += 2 {
|
|
||||||
if _, ok := keyvals[i].(Valuer); ok {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Timestamp returns a timestamp Valuer. It invokes the t function to get the
|
|
||||||
// time; unless you are doing something tricky, pass time.Now.
|
|
||||||
//
|
|
||||||
// Most users will want to use DefaultTimestamp or DefaultTimestampUTC, which
|
|
||||||
// are TimestampFormats that use the RFC3339Nano format.
|
|
||||||
func Timestamp(t func() time.Time) Valuer {
|
|
||||||
return func() interface{} { return t() }
|
|
||||||
}
|
|
||||||
|
|
||||||
// TimestampFormat returns a timestamp Valuer with a custom time format. It
|
|
||||||
// invokes the t function to get the time to format; unless you are doing
|
|
||||||
// something tricky, pass time.Now. The layout string is passed to
|
|
||||||
// Time.Format.
|
|
||||||
//
|
|
||||||
// Most users will want to use DefaultTimestamp or DefaultTimestampUTC, which
|
|
||||||
// are TimestampFormats that use the RFC3339Nano format.
|
|
||||||
func TimestampFormat(t func() time.Time, layout string) Valuer {
|
|
||||||
return func() interface{} {
|
|
||||||
return timeFormat{
|
|
||||||
time: t(),
|
|
||||||
layout: layout,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// A timeFormat represents an instant in time and a layout used when
|
|
||||||
// marshaling to a text format.
|
|
||||||
type timeFormat struct {
|
|
||||||
time time.Time
|
|
||||||
layout string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tf timeFormat) String() string {
|
|
||||||
return tf.time.Format(tf.layout)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarshalText implements encoding.TextMarshaller.
|
|
||||||
func (tf timeFormat) MarshalText() (text []byte, err error) {
|
|
||||||
// The following code adapted from the standard library time.Time.Format
|
|
||||||
// method. Using the same undocumented magic constant to extend the size
|
|
||||||
// of the buffer as seen there.
|
|
||||||
b := make([]byte, 0, len(tf.layout)+10)
|
|
||||||
b = tf.time.AppendFormat(b, tf.layout)
|
|
||||||
return b, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Caller returns a Valuer that returns a file and line from a specified depth
|
|
||||||
// in the callstack. Users will probably want to use DefaultCaller.
|
|
||||||
func Caller(depth int) Valuer {
|
|
||||||
return func() interface{} {
|
|
||||||
_, file, line, _ := runtime.Caller(depth)
|
|
||||||
idx := strings.LastIndexByte(file, '/')
|
|
||||||
// using idx+1 below handles both of following cases:
|
|
||||||
// idx == -1 because no "/" was found, or
|
|
||||||
// idx >= 0 and we want to start at the character after the found "/".
|
|
||||||
return file[idx+1:] + ":" + strconv.Itoa(line)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
// DefaultTimestamp is a Valuer that returns the current wallclock time,
|
|
||||||
// respecting time zones, when bound.
|
|
||||||
DefaultTimestamp = TimestampFormat(time.Now, time.RFC3339Nano)
|
|
||||||
|
|
||||||
// DefaultTimestampUTC is a Valuer that returns the current time in UTC
|
|
||||||
// when bound.
|
|
||||||
DefaultTimestampUTC = TimestampFormat(
|
|
||||||
func() time.Time { return time.Now().UTC() },
|
|
||||||
time.RFC3339Nano,
|
|
||||||
)
|
|
||||||
|
|
||||||
// DefaultCaller is a Valuer that returns the file and line where the Log
|
|
||||||
// method was invoked. It can only be used with log.With.
|
|
||||||
DefaultCaller = Caller(3)
|
|
||||||
)
|
|
1
vendor/github.com/go-logfmt/logfmt/.gitignore
generated
vendored
1
vendor/github.com/go-logfmt/logfmt/.gitignore
generated
vendored
|
@ -1 +0,0 @@
|
||||||
.vscode/
|
|
18
vendor/github.com/go-logfmt/logfmt/.travis.yml
generated
vendored
18
vendor/github.com/go-logfmt/logfmt/.travis.yml
generated
vendored
|
@ -1,18 +0,0 @@
|
||||||
language: go
|
|
||||||
sudo: false
|
|
||||||
go:
|
|
||||||
- "1.7.x"
|
|
||||||
- "1.8.x"
|
|
||||||
- "1.9.x"
|
|
||||||
- "1.10.x"
|
|
||||||
- "1.11.x"
|
|
||||||
- "1.12.x"
|
|
||||||
- "1.13.x"
|
|
||||||
- "tip"
|
|
||||||
|
|
||||||
before_install:
|
|
||||||
- go get github.com/mattn/goveralls
|
|
||||||
- go get golang.org/x/tools/cmd/cover
|
|
||||||
|
|
||||||
script:
|
|
||||||
- goveralls -service=travis-ci
|
|
48
vendor/github.com/go-logfmt/logfmt/CHANGELOG.md
generated
vendored
48
vendor/github.com/go-logfmt/logfmt/CHANGELOG.md
generated
vendored
|
@ -1,48 +0,0 @@
|
||||||
# Changelog
|
|
||||||
All notable changes to this project will be documented in this file.
|
|
||||||
|
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
||||||
|
|
||||||
## [0.5.0] - 2020-01-03
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
- Remove the dependency on github.com/kr/logfmt by [@ChrisHines]
|
|
||||||
- Move fuzz code to github.com/go-logfmt/fuzzlogfmt by [@ChrisHines]
|
|
||||||
|
|
||||||
## [0.4.0] - 2018-11-21
|
|
||||||
|
|
||||||
### Added
|
|
||||||
- Go module support by [@ChrisHines]
|
|
||||||
- CHANGELOG by [@ChrisHines]
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
- Drop invalid runes from keys instead of returning ErrInvalidKey by [@ChrisHines]
|
|
||||||
- On panic while printing, attempt to print panic value by [@bboreham]
|
|
||||||
|
|
||||||
## [0.3.0] - 2016-11-15
|
|
||||||
### Added
|
|
||||||
- Pool buffers for quoted strings and byte slices by [@nussjustin]
|
|
||||||
### Fixed
|
|
||||||
- Fuzz fix, quote invalid UTF-8 values by [@judwhite]
|
|
||||||
|
|
||||||
## [0.2.0] - 2016-05-08
|
|
||||||
### Added
|
|
||||||
- Encoder.EncodeKeyvals by [@ChrisHines]
|
|
||||||
|
|
||||||
## [0.1.0] - 2016-03-28
|
|
||||||
### Added
|
|
||||||
- Encoder by [@ChrisHines]
|
|
||||||
- Decoder by [@ChrisHines]
|
|
||||||
- MarshalKeyvals by [@ChrisHines]
|
|
||||||
|
|
||||||
[0.5.0]: https://github.com/go-logfmt/logfmt/compare/v0.4.0...v0.5.0
|
|
||||||
[0.4.0]: https://github.com/go-logfmt/logfmt/compare/v0.3.0...v0.4.0
|
|
||||||
[0.3.0]: https://github.com/go-logfmt/logfmt/compare/v0.2.0...v0.3.0
|
|
||||||
[0.2.0]: https://github.com/go-logfmt/logfmt/compare/v0.1.0...v0.2.0
|
|
||||||
[0.1.0]: https://github.com/go-logfmt/logfmt/commits/v0.1.0
|
|
||||||
|
|
||||||
[@ChrisHines]: https://github.com/ChrisHines
|
|
||||||
[@bboreham]: https://github.com/bboreham
|
|
||||||
[@judwhite]: https://github.com/judwhite
|
|
||||||
[@nussjustin]: https://github.com/nussjustin
|
|
22
vendor/github.com/go-logfmt/logfmt/LICENSE
generated
vendored
22
vendor/github.com/go-logfmt/logfmt/LICENSE
generated
vendored
|
@ -1,22 +0,0 @@
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2015 go-logfmt
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
|
|
33
vendor/github.com/go-logfmt/logfmt/README.md
generated
vendored
33
vendor/github.com/go-logfmt/logfmt/README.md
generated
vendored
|
@ -1,33 +0,0 @@
|
||||||
[![GoDoc](https://godoc.org/github.com/go-logfmt/logfmt?status.svg)](https://godoc.org/github.com/go-logfmt/logfmt)
|
|
||||||
[![Go Report Card](https://goreportcard.com/badge/go-logfmt/logfmt)](https://goreportcard.com/report/go-logfmt/logfmt)
|
|
||||||
[![TravisCI](https://travis-ci.org/go-logfmt/logfmt.svg?branch=master)](https://travis-ci.org/go-logfmt/logfmt)
|
|
||||||
[![Coverage Status](https://coveralls.io/repos/github/go-logfmt/logfmt/badge.svg?branch=master)](https://coveralls.io/github/go-logfmt/logfmt?branch=master)
|
|
||||||
|
|
||||||
# logfmt
|
|
||||||
|
|
||||||
Package logfmt implements utilities to marshal and unmarshal data in the [logfmt
|
|
||||||
format](https://brandur.org/logfmt). It provides an API similar to
|
|
||||||
[encoding/json](http://golang.org/pkg/encoding/json/) and
|
|
||||||
[encoding/xml](http://golang.org/pkg/encoding/xml/).
|
|
||||||
|
|
||||||
The logfmt format was first documented by Brandur Leach in [this
|
|
||||||
article](https://brandur.org/logfmt). The format has not been formally
|
|
||||||
standardized. The most authoritative public specification to date has been the
|
|
||||||
documentation of a Go Language [package](http://godoc.org/github.com/kr/logfmt)
|
|
||||||
written by Blake Mizerany and Keith Rarick.
|
|
||||||
|
|
||||||
## Goals
|
|
||||||
|
|
||||||
This project attempts to conform as closely as possible to the prior art, while
|
|
||||||
also removing ambiguity where necessary to provide well behaved encoder and
|
|
||||||
decoder implementations.
|
|
||||||
|
|
||||||
## Non-goals
|
|
||||||
|
|
||||||
This project does not attempt to formally standardize the logfmt format. In the
|
|
||||||
event that logfmt is standardized this project would take conforming to the
|
|
||||||
standard as a goal.
|
|
||||||
|
|
||||||
## Versioning
|
|
||||||
|
|
||||||
Package logfmt publishes releases via [semver](http://semver.org/) compatible Git tags prefixed with a single 'v'.
|
|
237
vendor/github.com/go-logfmt/logfmt/decode.go
generated
vendored
237
vendor/github.com/go-logfmt/logfmt/decode.go
generated
vendored
|
@ -1,237 +0,0 @@
|
||||||
package logfmt
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"unicode/utf8"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A Decoder reads and decodes logfmt records from an input stream.
|
|
||||||
type Decoder struct {
|
|
||||||
pos int
|
|
||||||
key []byte
|
|
||||||
value []byte
|
|
||||||
lineNum int
|
|
||||||
s *bufio.Scanner
|
|
||||||
err error
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewDecoder returns a new decoder that reads from r.
|
|
||||||
//
|
|
||||||
// The decoder introduces its own buffering and may read data from r beyond
|
|
||||||
// the logfmt records requested.
|
|
||||||
func NewDecoder(r io.Reader) *Decoder {
|
|
||||||
dec := &Decoder{
|
|
||||||
s: bufio.NewScanner(r),
|
|
||||||
}
|
|
||||||
return dec
|
|
||||||
}
|
|
||||||
|
|
||||||
// ScanRecord advances the Decoder to the next record, which can then be
|
|
||||||
// parsed with the ScanKeyval method. It returns false when decoding stops,
|
|
||||||
// either by reaching the end of the input or an error. After ScanRecord
|
|
||||||
// returns false, the Err method will return any error that occurred during
|
|
||||||
// decoding, except that if it was io.EOF, Err will return nil.
|
|
||||||
func (dec *Decoder) ScanRecord() bool {
|
|
||||||
if dec.err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if !dec.s.Scan() {
|
|
||||||
dec.err = dec.s.Err()
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
dec.lineNum++
|
|
||||||
dec.pos = 0
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// ScanKeyval advances the Decoder to the next key/value pair of the current
|
|
||||||
// record, which can then be retrieved with the Key and Value methods. It
|
|
||||||
// returns false when decoding stops, either by reaching the end of the
|
|
||||||
// current record or an error.
|
|
||||||
func (dec *Decoder) ScanKeyval() bool {
|
|
||||||
dec.key, dec.value = nil, nil
|
|
||||||
if dec.err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
line := dec.s.Bytes()
|
|
||||||
|
|
||||||
// garbage
|
|
||||||
for p, c := range line[dec.pos:] {
|
|
||||||
if c > ' ' {
|
|
||||||
dec.pos += p
|
|
||||||
goto key
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dec.pos = len(line)
|
|
||||||
return false
|
|
||||||
|
|
||||||
key:
|
|
||||||
const invalidKeyError = "invalid key"
|
|
||||||
|
|
||||||
start, multibyte := dec.pos, false
|
|
||||||
for p, c := range line[dec.pos:] {
|
|
||||||
switch {
|
|
||||||
case c == '=':
|
|
||||||
dec.pos += p
|
|
||||||
if dec.pos > start {
|
|
||||||
dec.key = line[start:dec.pos]
|
|
||||||
if multibyte && bytes.ContainsRune(dec.key, utf8.RuneError) {
|
|
||||||
dec.syntaxError(invalidKeyError)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if dec.key == nil {
|
|
||||||
dec.unexpectedByte(c)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
goto equal
|
|
||||||
case c == '"':
|
|
||||||
dec.pos += p
|
|
||||||
dec.unexpectedByte(c)
|
|
||||||
return false
|
|
||||||
case c <= ' ':
|
|
||||||
dec.pos += p
|
|
||||||
if dec.pos > start {
|
|
||||||
dec.key = line[start:dec.pos]
|
|
||||||
if multibyte && bytes.ContainsRune(dec.key, utf8.RuneError) {
|
|
||||||
dec.syntaxError(invalidKeyError)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
case c >= utf8.RuneSelf:
|
|
||||||
multibyte = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dec.pos = len(line)
|
|
||||||
if dec.pos > start {
|
|
||||||
dec.key = line[start:dec.pos]
|
|
||||||
if multibyte && bytes.ContainsRune(dec.key, utf8.RuneError) {
|
|
||||||
dec.syntaxError(invalidKeyError)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
|
|
||||||
equal:
|
|
||||||
dec.pos++
|
|
||||||
if dec.pos >= len(line) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
switch c := line[dec.pos]; {
|
|
||||||
case c <= ' ':
|
|
||||||
return true
|
|
||||||
case c == '"':
|
|
||||||
goto qvalue
|
|
||||||
}
|
|
||||||
|
|
||||||
// value
|
|
||||||
start = dec.pos
|
|
||||||
for p, c := range line[dec.pos:] {
|
|
||||||
switch {
|
|
||||||
case c == '=' || c == '"':
|
|
||||||
dec.pos += p
|
|
||||||
dec.unexpectedByte(c)
|
|
||||||
return false
|
|
||||||
case c <= ' ':
|
|
||||||
dec.pos += p
|
|
||||||
if dec.pos > start {
|
|
||||||
dec.value = line[start:dec.pos]
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dec.pos = len(line)
|
|
||||||
if dec.pos > start {
|
|
||||||
dec.value = line[start:dec.pos]
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
|
|
||||||
qvalue:
|
|
||||||
const (
|
|
||||||
untermQuote = "unterminated quoted value"
|
|
||||||
invalidQuote = "invalid quoted value"
|
|
||||||
)
|
|
||||||
|
|
||||||
hasEsc, esc := false, false
|
|
||||||
start = dec.pos
|
|
||||||
for p, c := range line[dec.pos+1:] {
|
|
||||||
switch {
|
|
||||||
case esc:
|
|
||||||
esc = false
|
|
||||||
case c == '\\':
|
|
||||||
hasEsc, esc = true, true
|
|
||||||
case c == '"':
|
|
||||||
dec.pos += p + 2
|
|
||||||
if hasEsc {
|
|
||||||
v, ok := unquoteBytes(line[start:dec.pos])
|
|
||||||
if !ok {
|
|
||||||
dec.syntaxError(invalidQuote)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
dec.value = v
|
|
||||||
} else {
|
|
||||||
start++
|
|
||||||
end := dec.pos - 1
|
|
||||||
if end > start {
|
|
||||||
dec.value = line[start:end]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dec.pos = len(line)
|
|
||||||
dec.syntaxError(untermQuote)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Key returns the most recent key found by a call to ScanKeyval. The returned
|
|
||||||
// slice may point to internal buffers and is only valid until the next call
|
|
||||||
// to ScanRecord. It does no allocation.
|
|
||||||
func (dec *Decoder) Key() []byte {
|
|
||||||
return dec.key
|
|
||||||
}
|
|
||||||
|
|
||||||
// Value returns the most recent value found by a call to ScanKeyval. The
|
|
||||||
// returned slice may point to internal buffers and is only valid until the
|
|
||||||
// next call to ScanRecord. It does no allocation when the value has no
|
|
||||||
// escape sequences.
|
|
||||||
func (dec *Decoder) Value() []byte {
|
|
||||||
return dec.value
|
|
||||||
}
|
|
||||||
|
|
||||||
// Err returns the first non-EOF error that was encountered by the Scanner.
|
|
||||||
func (dec *Decoder) Err() error {
|
|
||||||
return dec.err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (dec *Decoder) syntaxError(msg string) {
|
|
||||||
dec.err = &SyntaxError{
|
|
||||||
Msg: msg,
|
|
||||||
Line: dec.lineNum,
|
|
||||||
Pos: dec.pos + 1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (dec *Decoder) unexpectedByte(c byte) {
|
|
||||||
dec.err = &SyntaxError{
|
|
||||||
Msg: fmt.Sprintf("unexpected %q", c),
|
|
||||||
Line: dec.lineNum,
|
|
||||||
Pos: dec.pos + 1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// A SyntaxError represents a syntax error in the logfmt input stream.
|
|
||||||
type SyntaxError struct {
|
|
||||||
Msg string
|
|
||||||
Line int
|
|
||||||
Pos int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *SyntaxError) Error() string {
|
|
||||||
return fmt.Sprintf("logfmt syntax error at pos %d on line %d: %s", e.Pos, e.Line, e.Msg)
|
|
||||||
}
|
|
6
vendor/github.com/go-logfmt/logfmt/doc.go
generated
vendored
6
vendor/github.com/go-logfmt/logfmt/doc.go
generated
vendored
|
@ -1,6 +0,0 @@
|
||||||
// Package logfmt implements utilities to marshal and unmarshal data in the
|
|
||||||
// logfmt format. The logfmt format records key/value pairs in a way that
|
|
||||||
// balances readability for humans and simplicity of computer parsing. It is
|
|
||||||
// most commonly used as a more human friendly alternative to JSON for
|
|
||||||
// structured logging.
|
|
||||||
package logfmt
|
|
322
vendor/github.com/go-logfmt/logfmt/encode.go
generated
vendored
322
vendor/github.com/go-logfmt/logfmt/encode.go
generated
vendored
|
@ -1,322 +0,0 @@
|
||||||
package logfmt
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
"unicode/utf8"
|
|
||||||
)
|
|
||||||
|
|
||||||
// MarshalKeyvals returns the logfmt encoding of keyvals, a variadic sequence
|
|
||||||
// of alternating keys and values.
|
|
||||||
func MarshalKeyvals(keyvals ...interface{}) ([]byte, error) {
|
|
||||||
buf := &bytes.Buffer{}
|
|
||||||
if err := NewEncoder(buf).EncodeKeyvals(keyvals...); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return buf.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// An Encoder writes logfmt data to an output stream.
|
|
||||||
type Encoder struct {
|
|
||||||
w io.Writer
|
|
||||||
scratch bytes.Buffer
|
|
||||||
needSep bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewEncoder returns a new encoder that writes to w.
|
|
||||||
func NewEncoder(w io.Writer) *Encoder {
|
|
||||||
return &Encoder{
|
|
||||||
w: w,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
space = []byte(" ")
|
|
||||||
equals = []byte("=")
|
|
||||||
newline = []byte("\n")
|
|
||||||
null = []byte("null")
|
|
||||||
)
|
|
||||||
|
|
||||||
// EncodeKeyval writes the logfmt encoding of key and value to the stream. A
|
|
||||||
// single space is written before the second and subsequent keys in a record.
|
|
||||||
// Nothing is written if a non-nil error is returned.
|
|
||||||
func (enc *Encoder) EncodeKeyval(key, value interface{}) error {
|
|
||||||
enc.scratch.Reset()
|
|
||||||
if enc.needSep {
|
|
||||||
if _, err := enc.scratch.Write(space); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err := writeKey(&enc.scratch, key); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if _, err := enc.scratch.Write(equals); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := writeValue(&enc.scratch, value); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_, err := enc.w.Write(enc.scratch.Bytes())
|
|
||||||
enc.needSep = true
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// EncodeKeyvals writes the logfmt encoding of keyvals to the stream. Keyvals
|
|
||||||
// is a variadic sequence of alternating keys and values. Keys of unsupported
|
|
||||||
// type are skipped along with their corresponding value. Values of
|
|
||||||
// unsupported type or that cause a MarshalerError are replaced by their error
|
|
||||||
// but do not cause EncodeKeyvals to return an error. If a non-nil error is
|
|
||||||
// returned some key/value pairs may not have be written.
|
|
||||||
func (enc *Encoder) EncodeKeyvals(keyvals ...interface{}) error {
|
|
||||||
if len(keyvals) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if len(keyvals)%2 == 1 {
|
|
||||||
keyvals = append(keyvals, nil)
|
|
||||||
}
|
|
||||||
for i := 0; i < len(keyvals); i += 2 {
|
|
||||||
k, v := keyvals[i], keyvals[i+1]
|
|
||||||
err := enc.EncodeKeyval(k, v)
|
|
||||||
if err == ErrUnsupportedKeyType {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if _, ok := err.(*MarshalerError); ok || err == ErrUnsupportedValueType {
|
|
||||||
v = err
|
|
||||||
err = enc.EncodeKeyval(k, v)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarshalerError represents an error encountered while marshaling a value.
|
|
||||||
type MarshalerError struct {
|
|
||||||
Type reflect.Type
|
|
||||||
Err error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *MarshalerError) Error() string {
|
|
||||||
return "error marshaling value of type " + e.Type.String() + ": " + e.Err.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrNilKey is returned by Marshal functions and Encoder methods if a key is
|
|
||||||
// a nil interface or pointer value.
|
|
||||||
var ErrNilKey = errors.New("nil key")
|
|
||||||
|
|
||||||
// ErrInvalidKey is returned by Marshal functions and Encoder methods if, after
|
|
||||||
// dropping invalid runes, a key is empty.
|
|
||||||
var ErrInvalidKey = errors.New("invalid key")
|
|
||||||
|
|
||||||
// ErrUnsupportedKeyType is returned by Encoder methods if a key has an
|
|
||||||
// unsupported type.
|
|
||||||
var ErrUnsupportedKeyType = errors.New("unsupported key type")
|
|
||||||
|
|
||||||
// ErrUnsupportedValueType is returned by Encoder methods if a value has an
|
|
||||||
// unsupported type.
|
|
||||||
var ErrUnsupportedValueType = errors.New("unsupported value type")
|
|
||||||
|
|
||||||
func writeKey(w io.Writer, key interface{}) error {
|
|
||||||
if key == nil {
|
|
||||||
return ErrNilKey
|
|
||||||
}
|
|
||||||
|
|
||||||
switch k := key.(type) {
|
|
||||||
case string:
|
|
||||||
return writeStringKey(w, k)
|
|
||||||
case []byte:
|
|
||||||
if k == nil {
|
|
||||||
return ErrNilKey
|
|
||||||
}
|
|
||||||
return writeBytesKey(w, k)
|
|
||||||
case encoding.TextMarshaler:
|
|
||||||
kb, err := safeMarshal(k)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if kb == nil {
|
|
||||||
return ErrNilKey
|
|
||||||
}
|
|
||||||
return writeBytesKey(w, kb)
|
|
||||||
case fmt.Stringer:
|
|
||||||
ks, ok := safeString(k)
|
|
||||||
if !ok {
|
|
||||||
return ErrNilKey
|
|
||||||
}
|
|
||||||
return writeStringKey(w, ks)
|
|
||||||
default:
|
|
||||||
rkey := reflect.ValueOf(key)
|
|
||||||
switch rkey.Kind() {
|
|
||||||
case reflect.Array, reflect.Chan, reflect.Func, reflect.Map, reflect.Slice, reflect.Struct:
|
|
||||||
return ErrUnsupportedKeyType
|
|
||||||
case reflect.Ptr:
|
|
||||||
if rkey.IsNil() {
|
|
||||||
return ErrNilKey
|
|
||||||
}
|
|
||||||
return writeKey(w, rkey.Elem().Interface())
|
|
||||||
}
|
|
||||||
return writeStringKey(w, fmt.Sprint(k))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// keyRuneFilter returns r for all valid key runes, and -1 for all invalid key
|
|
||||||
// runes. When used as the mapping function for strings.Map and bytes.Map
|
|
||||||
// functions it causes them to remove invalid key runes from strings or byte
|
|
||||||
// slices respectively.
|
|
||||||
func keyRuneFilter(r rune) rune {
|
|
||||||
if r <= ' ' || r == '=' || r == '"' || r == utf8.RuneError {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeStringKey(w io.Writer, key string) error {
|
|
||||||
k := strings.Map(keyRuneFilter, key)
|
|
||||||
if k == "" {
|
|
||||||
return ErrInvalidKey
|
|
||||||
}
|
|
||||||
_, err := io.WriteString(w, k)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeBytesKey(w io.Writer, key []byte) error {
|
|
||||||
k := bytes.Map(keyRuneFilter, key)
|
|
||||||
if len(k) == 0 {
|
|
||||||
return ErrInvalidKey
|
|
||||||
}
|
|
||||||
_, err := w.Write(k)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeValue(w io.Writer, value interface{}) error {
|
|
||||||
switch v := value.(type) {
|
|
||||||
case nil:
|
|
||||||
return writeBytesValue(w, null)
|
|
||||||
case string:
|
|
||||||
return writeStringValue(w, v, true)
|
|
||||||
case []byte:
|
|
||||||
return writeBytesValue(w, v)
|
|
||||||
case encoding.TextMarshaler:
|
|
||||||
vb, err := safeMarshal(v)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if vb == nil {
|
|
||||||
vb = null
|
|
||||||
}
|
|
||||||
return writeBytesValue(w, vb)
|
|
||||||
case error:
|
|
||||||
se, ok := safeError(v)
|
|
||||||
return writeStringValue(w, se, ok)
|
|
||||||
case fmt.Stringer:
|
|
||||||
ss, ok := safeString(v)
|
|
||||||
return writeStringValue(w, ss, ok)
|
|
||||||
default:
|
|
||||||
rvalue := reflect.ValueOf(value)
|
|
||||||
switch rvalue.Kind() {
|
|
||||||
case reflect.Array, reflect.Chan, reflect.Func, reflect.Map, reflect.Slice, reflect.Struct:
|
|
||||||
return ErrUnsupportedValueType
|
|
||||||
case reflect.Ptr:
|
|
||||||
if rvalue.IsNil() {
|
|
||||||
return writeBytesValue(w, null)
|
|
||||||
}
|
|
||||||
return writeValue(w, rvalue.Elem().Interface())
|
|
||||||
}
|
|
||||||
return writeStringValue(w, fmt.Sprint(v), true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func needsQuotedValueRune(r rune) bool {
|
|
||||||
return r <= ' ' || r == '=' || r == '"' || r == utf8.RuneError
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeStringValue(w io.Writer, value string, ok bool) error {
|
|
||||||
var err error
|
|
||||||
if ok && value == "null" {
|
|
||||||
_, err = io.WriteString(w, `"null"`)
|
|
||||||
} else if strings.IndexFunc(value, needsQuotedValueRune) != -1 {
|
|
||||||
_, err = writeQuotedString(w, value)
|
|
||||||
} else {
|
|
||||||
_, err = io.WriteString(w, value)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeBytesValue(w io.Writer, value []byte) error {
|
|
||||||
var err error
|
|
||||||
if bytes.IndexFunc(value, needsQuotedValueRune) != -1 {
|
|
||||||
_, err = writeQuotedBytes(w, value)
|
|
||||||
} else {
|
|
||||||
_, err = w.Write(value)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// EndRecord writes a newline character to the stream and resets the encoder
|
|
||||||
// to the beginning of a new record.
|
|
||||||
func (enc *Encoder) EndRecord() error {
|
|
||||||
_, err := enc.w.Write(newline)
|
|
||||||
if err == nil {
|
|
||||||
enc.needSep = false
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset resets the encoder to the beginning of a new record.
|
|
||||||
func (enc *Encoder) Reset() {
|
|
||||||
enc.needSep = false
|
|
||||||
}
|
|
||||||
|
|
||||||
func safeError(err error) (s string, ok bool) {
|
|
||||||
defer func() {
|
|
||||||
if panicVal := recover(); panicVal != nil {
|
|
||||||
if v := reflect.ValueOf(err); v.Kind() == reflect.Ptr && v.IsNil() {
|
|
||||||
s, ok = "null", false
|
|
||||||
} else {
|
|
||||||
s, ok = fmt.Sprintf("PANIC:%v", panicVal), false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
s, ok = err.Error(), true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func safeString(str fmt.Stringer) (s string, ok bool) {
|
|
||||||
defer func() {
|
|
||||||
if panicVal := recover(); panicVal != nil {
|
|
||||||
if v := reflect.ValueOf(str); v.Kind() == reflect.Ptr && v.IsNil() {
|
|
||||||
s, ok = "null", false
|
|
||||||
} else {
|
|
||||||
s, ok = fmt.Sprintf("PANIC:%v", panicVal), true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
s, ok = str.String(), true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func safeMarshal(tm encoding.TextMarshaler) (b []byte, err error) {
|
|
||||||
defer func() {
|
|
||||||
if panicVal := recover(); panicVal != nil {
|
|
||||||
if v := reflect.ValueOf(tm); v.Kind() == reflect.Ptr && v.IsNil() {
|
|
||||||
b, err = nil, nil
|
|
||||||
} else {
|
|
||||||
b, err = nil, fmt.Errorf("panic when marshalling: %s", panicVal)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
b, err = tm.MarshalText()
|
|
||||||
if err != nil {
|
|
||||||
return nil, &MarshalerError{
|
|
||||||
Type: reflect.TypeOf(tm),
|
|
||||||
Err: err,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
3
vendor/github.com/go-logfmt/logfmt/go.mod
generated
vendored
3
vendor/github.com/go-logfmt/logfmt/go.mod
generated
vendored
|
@ -1,3 +0,0 @@
|
||||||
module github.com/go-logfmt/logfmt
|
|
||||||
|
|
||||||
go 1.13
|
|
277
vendor/github.com/go-logfmt/logfmt/jsonstring.go
generated
vendored
277
vendor/github.com/go-logfmt/logfmt/jsonstring.go
generated
vendored
|
@ -1,277 +0,0 @@
|
||||||
package logfmt
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"io"
|
|
||||||
"strconv"
|
|
||||||
"sync"
|
|
||||||
"unicode"
|
|
||||||
"unicode/utf16"
|
|
||||||
"unicode/utf8"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Taken from Go's encoding/json and modified for use here.
|
|
||||||
|
|
||||||
// Copyright 2010 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
var hex = "0123456789abcdef"
|
|
||||||
|
|
||||||
var bufferPool = sync.Pool{
|
|
||||||
New: func() interface{} {
|
|
||||||
return &bytes.Buffer{}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func getBuffer() *bytes.Buffer {
|
|
||||||
return bufferPool.Get().(*bytes.Buffer)
|
|
||||||
}
|
|
||||||
|
|
||||||
func poolBuffer(buf *bytes.Buffer) {
|
|
||||||
buf.Reset()
|
|
||||||
bufferPool.Put(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: keep in sync with writeQuotedBytes below.
|
|
||||||
func writeQuotedString(w io.Writer, s string) (int, error) {
|
|
||||||
buf := getBuffer()
|
|
||||||
buf.WriteByte('"')
|
|
||||||
start := 0
|
|
||||||
for i := 0; i < len(s); {
|
|
||||||
if b := s[i]; b < utf8.RuneSelf {
|
|
||||||
if 0x20 <= b && b != '\\' && b != '"' {
|
|
||||||
i++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if start < i {
|
|
||||||
buf.WriteString(s[start:i])
|
|
||||||
}
|
|
||||||
switch b {
|
|
||||||
case '\\', '"':
|
|
||||||
buf.WriteByte('\\')
|
|
||||||
buf.WriteByte(b)
|
|
||||||
case '\n':
|
|
||||||
buf.WriteByte('\\')
|
|
||||||
buf.WriteByte('n')
|
|
||||||
case '\r':
|
|
||||||
buf.WriteByte('\\')
|
|
||||||
buf.WriteByte('r')
|
|
||||||
case '\t':
|
|
||||||
buf.WriteByte('\\')
|
|
||||||
buf.WriteByte('t')
|
|
||||||
default:
|
|
||||||
// This encodes bytes < 0x20 except for \n, \r, and \t.
|
|
||||||
buf.WriteString(`\u00`)
|
|
||||||
buf.WriteByte(hex[b>>4])
|
|
||||||
buf.WriteByte(hex[b&0xF])
|
|
||||||
}
|
|
||||||
i++
|
|
||||||
start = i
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
c, size := utf8.DecodeRuneInString(s[i:])
|
|
||||||
if c == utf8.RuneError {
|
|
||||||
if start < i {
|
|
||||||
buf.WriteString(s[start:i])
|
|
||||||
}
|
|
||||||
buf.WriteString(`\ufffd`)
|
|
||||||
i += size
|
|
||||||
start = i
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
i += size
|
|
||||||
}
|
|
||||||
if start < len(s) {
|
|
||||||
buf.WriteString(s[start:])
|
|
||||||
}
|
|
||||||
buf.WriteByte('"')
|
|
||||||
n, err := w.Write(buf.Bytes())
|
|
||||||
poolBuffer(buf)
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: keep in sync with writeQuoteString above.
|
|
||||||
func writeQuotedBytes(w io.Writer, s []byte) (int, error) {
|
|
||||||
buf := getBuffer()
|
|
||||||
buf.WriteByte('"')
|
|
||||||
start := 0
|
|
||||||
for i := 0; i < len(s); {
|
|
||||||
if b := s[i]; b < utf8.RuneSelf {
|
|
||||||
if 0x20 <= b && b != '\\' && b != '"' {
|
|
||||||
i++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if start < i {
|
|
||||||
buf.Write(s[start:i])
|
|
||||||
}
|
|
||||||
switch b {
|
|
||||||
case '\\', '"':
|
|
||||||
buf.WriteByte('\\')
|
|
||||||
buf.WriteByte(b)
|
|
||||||
case '\n':
|
|
||||||
buf.WriteByte('\\')
|
|
||||||
buf.WriteByte('n')
|
|
||||||
case '\r':
|
|
||||||
buf.WriteByte('\\')
|
|
||||||
buf.WriteByte('r')
|
|
||||||
case '\t':
|
|
||||||
buf.WriteByte('\\')
|
|
||||||
buf.WriteByte('t')
|
|
||||||
default:
|
|
||||||
// This encodes bytes < 0x20 except for \n, \r, and \t.
|
|
||||||
buf.WriteString(`\u00`)
|
|
||||||
buf.WriteByte(hex[b>>4])
|
|
||||||
buf.WriteByte(hex[b&0xF])
|
|
||||||
}
|
|
||||||
i++
|
|
||||||
start = i
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
c, size := utf8.DecodeRune(s[i:])
|
|
||||||
if c == utf8.RuneError {
|
|
||||||
if start < i {
|
|
||||||
buf.Write(s[start:i])
|
|
||||||
}
|
|
||||||
buf.WriteString(`\ufffd`)
|
|
||||||
i += size
|
|
||||||
start = i
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
i += size
|
|
||||||
}
|
|
||||||
if start < len(s) {
|
|
||||||
buf.Write(s[start:])
|
|
||||||
}
|
|
||||||
buf.WriteByte('"')
|
|
||||||
n, err := w.Write(buf.Bytes())
|
|
||||||
poolBuffer(buf)
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// getu4 decodes \uXXXX from the beginning of s, returning the hex value,
|
|
||||||
// or it returns -1.
|
|
||||||
func getu4(s []byte) rune {
|
|
||||||
if len(s) < 6 || s[0] != '\\' || s[1] != 'u' {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
r, err := strconv.ParseUint(string(s[2:6]), 16, 64)
|
|
||||||
if err != nil {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
return rune(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func unquoteBytes(s []byte) (t []byte, ok bool) {
|
|
||||||
if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s = s[1 : len(s)-1]
|
|
||||||
|
|
||||||
// Check for unusual characters. If there are none,
|
|
||||||
// then no unquoting is needed, so return a slice of the
|
|
||||||
// original bytes.
|
|
||||||
r := 0
|
|
||||||
for r < len(s) {
|
|
||||||
c := s[r]
|
|
||||||
if c == '\\' || c == '"' || c < ' ' {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if c < utf8.RuneSelf {
|
|
||||||
r++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
rr, size := utf8.DecodeRune(s[r:])
|
|
||||||
if rr == utf8.RuneError {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
r += size
|
|
||||||
}
|
|
||||||
if r == len(s) {
|
|
||||||
return s, true
|
|
||||||
}
|
|
||||||
|
|
||||||
b := make([]byte, len(s)+2*utf8.UTFMax)
|
|
||||||
w := copy(b, s[0:r])
|
|
||||||
for r < len(s) {
|
|
||||||
// Out of room? Can only happen if s is full of
|
|
||||||
// malformed UTF-8 and we're replacing each
|
|
||||||
// byte with RuneError.
|
|
||||||
if w >= len(b)-2*utf8.UTFMax {
|
|
||||||
nb := make([]byte, (len(b)+utf8.UTFMax)*2)
|
|
||||||
copy(nb, b[0:w])
|
|
||||||
b = nb
|
|
||||||
}
|
|
||||||
switch c := s[r]; {
|
|
||||||
case c == '\\':
|
|
||||||
r++
|
|
||||||
if r >= len(s) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
switch s[r] {
|
|
||||||
default:
|
|
||||||
return
|
|
||||||
case '"', '\\', '/', '\'':
|
|
||||||
b[w] = s[r]
|
|
||||||
r++
|
|
||||||
w++
|
|
||||||
case 'b':
|
|
||||||
b[w] = '\b'
|
|
||||||
r++
|
|
||||||
w++
|
|
||||||
case 'f':
|
|
||||||
b[w] = '\f'
|
|
||||||
r++
|
|
||||||
w++
|
|
||||||
case 'n':
|
|
||||||
b[w] = '\n'
|
|
||||||
r++
|
|
||||||
w++
|
|
||||||
case 'r':
|
|
||||||
b[w] = '\r'
|
|
||||||
r++
|
|
||||||
w++
|
|
||||||
case 't':
|
|
||||||
b[w] = '\t'
|
|
||||||
r++
|
|
||||||
w++
|
|
||||||
case 'u':
|
|
||||||
r--
|
|
||||||
rr := getu4(s[r:])
|
|
||||||
if rr < 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
r += 6
|
|
||||||
if utf16.IsSurrogate(rr) {
|
|
||||||
rr1 := getu4(s[r:])
|
|
||||||
if dec := utf16.DecodeRune(rr, rr1); dec != unicode.ReplacementChar {
|
|
||||||
// A valid pair; consume.
|
|
||||||
r += 6
|
|
||||||
w += utf8.EncodeRune(b[w:], dec)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
// Invalid surrogate; fall back to replacement rune.
|
|
||||||
rr = unicode.ReplacementChar
|
|
||||||
}
|
|
||||||
w += utf8.EncodeRune(b[w:], rr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Quote, control characters are invalid.
|
|
||||||
case c == '"', c < ' ':
|
|
||||||
return
|
|
||||||
|
|
||||||
// ASCII
|
|
||||||
case c < utf8.RuneSelf:
|
|
||||||
b[w] = c
|
|
||||||
r++
|
|
||||||
w++
|
|
||||||
|
|
||||||
// Coerce to well-formed UTF-8.
|
|
||||||
default:
|
|
||||||
rr, size := utf8.DecodeRune(s[r:])
|
|
||||||
r += size
|
|
||||||
w += utf8.EncodeRune(b[w:], rr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return b[0:w], true
|
|
||||||
}
|
|
3
vendor/github.com/golang/protobuf/AUTHORS
generated
vendored
3
vendor/github.com/golang/protobuf/AUTHORS
generated
vendored
|
@ -1,3 +0,0 @@
|
||||||
# This source code refers to The Go Authors for copyright purposes.
|
|
||||||
# The master list of authors is in the main Go distribution,
|
|
||||||
# visible at http://tip.golang.org/AUTHORS.
|
|
3
vendor/github.com/golang/protobuf/CONTRIBUTORS
generated
vendored
3
vendor/github.com/golang/protobuf/CONTRIBUTORS
generated
vendored
|
@ -1,3 +0,0 @@
|
||||||
# This source code was written by the Go contributors.
|
|
||||||
# The master list of contributors is in the main Go distribution,
|
|
||||||
# visible at http://tip.golang.org/CONTRIBUTORS.
|
|
28
vendor/github.com/golang/protobuf/LICENSE
generated
vendored
28
vendor/github.com/golang/protobuf/LICENSE
generated
vendored
|
@ -1,28 +0,0 @@
|
||||||
Copyright 2010 The Go Authors. All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are
|
|
||||||
met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above
|
|
||||||
copyright notice, this list of conditions and the following disclaimer
|
|
||||||
in the documentation and/or other materials provided with the
|
|
||||||
distribution.
|
|
||||||
* Neither the name of Google Inc. nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived from
|
|
||||||
this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
324
vendor/github.com/golang/protobuf/proto/buffer.go
generated
vendored
324
vendor/github.com/golang/protobuf/proto/buffer.go
generated
vendored
|
@ -1,324 +0,0 @@
|
||||||
// Copyright 2019 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package proto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"google.golang.org/protobuf/encoding/prototext"
|
|
||||||
"google.golang.org/protobuf/encoding/protowire"
|
|
||||||
"google.golang.org/protobuf/runtime/protoimpl"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
WireVarint = 0
|
|
||||||
WireFixed32 = 5
|
|
||||||
WireFixed64 = 1
|
|
||||||
WireBytes = 2
|
|
||||||
WireStartGroup = 3
|
|
||||||
WireEndGroup = 4
|
|
||||||
)
|
|
||||||
|
|
||||||
// EncodeVarint returns the varint encoded bytes of v.
|
|
||||||
func EncodeVarint(v uint64) []byte {
|
|
||||||
return protowire.AppendVarint(nil, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SizeVarint returns the length of the varint encoded bytes of v.
|
|
||||||
// This is equal to len(EncodeVarint(v)).
|
|
||||||
func SizeVarint(v uint64) int {
|
|
||||||
return protowire.SizeVarint(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DecodeVarint parses a varint encoded integer from b,
|
|
||||||
// returning the integer value and the length of the varint.
|
|
||||||
// It returns (0, 0) if there is a parse error.
|
|
||||||
func DecodeVarint(b []byte) (uint64, int) {
|
|
||||||
v, n := protowire.ConsumeVarint(b)
|
|
||||||
if n < 0 {
|
|
||||||
return 0, 0
|
|
||||||
}
|
|
||||||
return v, n
|
|
||||||
}
|
|
||||||
|
|
||||||
// Buffer is a buffer for encoding and decoding the protobuf wire format.
|
|
||||||
// It may be reused between invocations to reduce memory usage.
|
|
||||||
type Buffer struct {
|
|
||||||
buf []byte
|
|
||||||
idx int
|
|
||||||
deterministic bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewBuffer allocates a new Buffer initialized with buf,
|
|
||||||
// where the contents of buf are considered the unread portion of the buffer.
|
|
||||||
func NewBuffer(buf []byte) *Buffer {
|
|
||||||
return &Buffer{buf: buf}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetDeterministic specifies whether to use deterministic serialization.
|
|
||||||
//
|
|
||||||
// Deterministic serialization guarantees that for a given binary, equal
|
|
||||||
// messages will always be serialized to the same bytes. This implies:
|
|
||||||
//
|
|
||||||
// - Repeated serialization of a message will return the same bytes.
|
|
||||||
// - Different processes of the same binary (which may be executing on
|
|
||||||
// different machines) will serialize equal messages to the same bytes.
|
|
||||||
//
|
|
||||||
// Note that the deterministic serialization is NOT canonical across
|
|
||||||
// languages. It is not guaranteed to remain stable over time. It is unstable
|
|
||||||
// across different builds with schema changes due to unknown fields.
|
|
||||||
// Users who need canonical serialization (e.g., persistent storage in a
|
|
||||||
// canonical form, fingerprinting, etc.) should define their own
|
|
||||||
// canonicalization specification and implement their own serializer rather
|
|
||||||
// than relying on this API.
|
|
||||||
//
|
|
||||||
// If deterministic serialization is requested, map entries will be sorted
|
|
||||||
// by keys in lexographical order. This is an implementation detail and
|
|
||||||
// subject to change.
|
|
||||||
func (b *Buffer) SetDeterministic(deterministic bool) {
|
|
||||||
b.deterministic = deterministic
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetBuf sets buf as the internal buffer,
|
|
||||||
// where the contents of buf are considered the unread portion of the buffer.
|
|
||||||
func (b *Buffer) SetBuf(buf []byte) {
|
|
||||||
b.buf = buf
|
|
||||||
b.idx = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset clears the internal buffer of all written and unread data.
|
|
||||||
func (b *Buffer) Reset() {
|
|
||||||
b.buf = b.buf[:0]
|
|
||||||
b.idx = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bytes returns the internal buffer.
|
|
||||||
func (b *Buffer) Bytes() []byte {
|
|
||||||
return b.buf
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unread returns the unread portion of the buffer.
|
|
||||||
func (b *Buffer) Unread() []byte {
|
|
||||||
return b.buf[b.idx:]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Marshal appends the wire-format encoding of m to the buffer.
|
|
||||||
func (b *Buffer) Marshal(m Message) error {
|
|
||||||
var err error
|
|
||||||
b.buf, err = marshalAppend(b.buf, m, b.deterministic)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unmarshal parses the wire-format message in the buffer and
|
|
||||||
// places the decoded results in m.
|
|
||||||
// It does not reset m before unmarshaling.
|
|
||||||
func (b *Buffer) Unmarshal(m Message) error {
|
|
||||||
err := UnmarshalMerge(b.Unread(), m)
|
|
||||||
b.idx = len(b.buf)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
type unknownFields struct{ XXX_unrecognized protoimpl.UnknownFields }
|
|
||||||
|
|
||||||
func (m *unknownFields) String() string { panic("not implemented") }
|
|
||||||
func (m *unknownFields) Reset() { panic("not implemented") }
|
|
||||||
func (m *unknownFields) ProtoMessage() { panic("not implemented") }
|
|
||||||
|
|
||||||
// DebugPrint dumps the encoded bytes of b with a header and footer including s
|
|
||||||
// to stdout. This is only intended for debugging.
|
|
||||||
func (*Buffer) DebugPrint(s string, b []byte) {
|
|
||||||
m := MessageReflect(new(unknownFields))
|
|
||||||
m.SetUnknown(b)
|
|
||||||
b, _ = prototext.MarshalOptions{AllowPartial: true, Indent: "\t"}.Marshal(m.Interface())
|
|
||||||
fmt.Printf("==== %s ====\n%s==== %s ====\n", s, b, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// EncodeVarint appends an unsigned varint encoding to the buffer.
|
|
||||||
func (b *Buffer) EncodeVarint(v uint64) error {
|
|
||||||
b.buf = protowire.AppendVarint(b.buf, v)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// EncodeZigzag32 appends a 32-bit zig-zag varint encoding to the buffer.
|
|
||||||
func (b *Buffer) EncodeZigzag32(v uint64) error {
|
|
||||||
return b.EncodeVarint(uint64((uint32(v) << 1) ^ uint32((int32(v) >> 31))))
|
|
||||||
}
|
|
||||||
|
|
||||||
// EncodeZigzag64 appends a 64-bit zig-zag varint encoding to the buffer.
|
|
||||||
func (b *Buffer) EncodeZigzag64(v uint64) error {
|
|
||||||
return b.EncodeVarint(uint64((uint64(v) << 1) ^ uint64((int64(v) >> 63))))
|
|
||||||
}
|
|
||||||
|
|
||||||
// EncodeFixed32 appends a 32-bit little-endian integer to the buffer.
|
|
||||||
func (b *Buffer) EncodeFixed32(v uint64) error {
|
|
||||||
b.buf = protowire.AppendFixed32(b.buf, uint32(v))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// EncodeFixed64 appends a 64-bit little-endian integer to the buffer.
|
|
||||||
func (b *Buffer) EncodeFixed64(v uint64) error {
|
|
||||||
b.buf = protowire.AppendFixed64(b.buf, uint64(v))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// EncodeRawBytes appends a length-prefixed raw bytes to the buffer.
|
|
||||||
func (b *Buffer) EncodeRawBytes(v []byte) error {
|
|
||||||
b.buf = protowire.AppendBytes(b.buf, v)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// EncodeStringBytes appends a length-prefixed raw bytes to the buffer.
|
|
||||||
// It does not validate whether v contains valid UTF-8.
|
|
||||||
func (b *Buffer) EncodeStringBytes(v string) error {
|
|
||||||
b.buf = protowire.AppendString(b.buf, v)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// EncodeMessage appends a length-prefixed encoded message to the buffer.
|
|
||||||
func (b *Buffer) EncodeMessage(m Message) error {
|
|
||||||
var err error
|
|
||||||
b.buf = protowire.AppendVarint(b.buf, uint64(Size(m)))
|
|
||||||
b.buf, err = marshalAppend(b.buf, m, b.deterministic)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// DecodeVarint consumes an encoded unsigned varint from the buffer.
|
|
||||||
func (b *Buffer) DecodeVarint() (uint64, error) {
|
|
||||||
v, n := protowire.ConsumeVarint(b.buf[b.idx:])
|
|
||||||
if n < 0 {
|
|
||||||
return 0, protowire.ParseError(n)
|
|
||||||
}
|
|
||||||
b.idx += n
|
|
||||||
return uint64(v), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DecodeZigzag32 consumes an encoded 32-bit zig-zag varint from the buffer.
|
|
||||||
func (b *Buffer) DecodeZigzag32() (uint64, error) {
|
|
||||||
v, err := b.DecodeVarint()
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return uint64((uint32(v) >> 1) ^ uint32((int32(v&1)<<31)>>31)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DecodeZigzag64 consumes an encoded 64-bit zig-zag varint from the buffer.
|
|
||||||
func (b *Buffer) DecodeZigzag64() (uint64, error) {
|
|
||||||
v, err := b.DecodeVarint()
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return uint64((uint64(v) >> 1) ^ uint64((int64(v&1)<<63)>>63)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DecodeFixed32 consumes a 32-bit little-endian integer from the buffer.
|
|
||||||
func (b *Buffer) DecodeFixed32() (uint64, error) {
|
|
||||||
v, n := protowire.ConsumeFixed32(b.buf[b.idx:])
|
|
||||||
if n < 0 {
|
|
||||||
return 0, protowire.ParseError(n)
|
|
||||||
}
|
|
||||||
b.idx += n
|
|
||||||
return uint64(v), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DecodeFixed64 consumes a 64-bit little-endian integer from the buffer.
|
|
||||||
func (b *Buffer) DecodeFixed64() (uint64, error) {
|
|
||||||
v, n := protowire.ConsumeFixed64(b.buf[b.idx:])
|
|
||||||
if n < 0 {
|
|
||||||
return 0, protowire.ParseError(n)
|
|
||||||
}
|
|
||||||
b.idx += n
|
|
||||||
return uint64(v), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DecodeRawBytes consumes a length-prefixed raw bytes from the buffer.
|
|
||||||
// If alloc is specified, it returns a copy the raw bytes
|
|
||||||
// rather than a sub-slice of the buffer.
|
|
||||||
func (b *Buffer) DecodeRawBytes(alloc bool) ([]byte, error) {
|
|
||||||
v, n := protowire.ConsumeBytes(b.buf[b.idx:])
|
|
||||||
if n < 0 {
|
|
||||||
return nil, protowire.ParseError(n)
|
|
||||||
}
|
|
||||||
b.idx += n
|
|
||||||
if alloc {
|
|
||||||
v = append([]byte(nil), v...)
|
|
||||||
}
|
|
||||||
return v, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DecodeStringBytes consumes a length-prefixed raw bytes from the buffer.
|
|
||||||
// It does not validate whether the raw bytes contain valid UTF-8.
|
|
||||||
func (b *Buffer) DecodeStringBytes() (string, error) {
|
|
||||||
v, n := protowire.ConsumeString(b.buf[b.idx:])
|
|
||||||
if n < 0 {
|
|
||||||
return "", protowire.ParseError(n)
|
|
||||||
}
|
|
||||||
b.idx += n
|
|
||||||
return v, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DecodeMessage consumes a length-prefixed message from the buffer.
|
|
||||||
// It does not reset m before unmarshaling.
|
|
||||||
func (b *Buffer) DecodeMessage(m Message) error {
|
|
||||||
v, err := b.DecodeRawBytes(false)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return UnmarshalMerge(v, m)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DecodeGroup consumes a message group from the buffer.
|
|
||||||
// It assumes that the start group marker has already been consumed and
|
|
||||||
// consumes all bytes until (and including the end group marker).
|
|
||||||
// It does not reset m before unmarshaling.
|
|
||||||
func (b *Buffer) DecodeGroup(m Message) error {
|
|
||||||
v, n, err := consumeGroup(b.buf[b.idx:])
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
b.idx += n
|
|
||||||
return UnmarshalMerge(v, m)
|
|
||||||
}
|
|
||||||
|
|
||||||
// consumeGroup parses b until it finds an end group marker, returning
|
|
||||||
// the raw bytes of the message (excluding the end group marker) and the
|
|
||||||
// the total length of the message (including the end group marker).
|
|
||||||
func consumeGroup(b []byte) ([]byte, int, error) {
|
|
||||||
b0 := b
|
|
||||||
depth := 1 // assume this follows a start group marker
|
|
||||||
for {
|
|
||||||
_, wtyp, tagLen := protowire.ConsumeTag(b)
|
|
||||||
if tagLen < 0 {
|
|
||||||
return nil, 0, protowire.ParseError(tagLen)
|
|
||||||
}
|
|
||||||
b = b[tagLen:]
|
|
||||||
|
|
||||||
var valLen int
|
|
||||||
switch wtyp {
|
|
||||||
case protowire.VarintType:
|
|
||||||
_, valLen = protowire.ConsumeVarint(b)
|
|
||||||
case protowire.Fixed32Type:
|
|
||||||
_, valLen = protowire.ConsumeFixed32(b)
|
|
||||||
case protowire.Fixed64Type:
|
|
||||||
_, valLen = protowire.ConsumeFixed64(b)
|
|
||||||
case protowire.BytesType:
|
|
||||||
_, valLen = protowire.ConsumeBytes(b)
|
|
||||||
case protowire.StartGroupType:
|
|
||||||
depth++
|
|
||||||
case protowire.EndGroupType:
|
|
||||||
depth--
|
|
||||||
default:
|
|
||||||
return nil, 0, errors.New("proto: cannot parse reserved wire type")
|
|
||||||
}
|
|
||||||
if valLen < 0 {
|
|
||||||
return nil, 0, protowire.ParseError(valLen)
|
|
||||||
}
|
|
||||||
b = b[valLen:]
|
|
||||||
|
|
||||||
if depth == 0 {
|
|
||||||
return b0[:len(b0)-len(b)-tagLen], len(b0) - len(b), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
63
vendor/github.com/golang/protobuf/proto/defaults.go
generated
vendored
63
vendor/github.com/golang/protobuf/proto/defaults.go
generated
vendored
|
@ -1,63 +0,0 @@
|
||||||
// Copyright 2019 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package proto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"google.golang.org/protobuf/reflect/protoreflect"
|
|
||||||
)
|
|
||||||
|
|
||||||
// SetDefaults sets unpopulated scalar fields to their default values.
|
|
||||||
// Fields within a oneof are not set even if they have a default value.
|
|
||||||
// SetDefaults is recursively called upon any populated message fields.
|
|
||||||
func SetDefaults(m Message) {
|
|
||||||
if m != nil {
|
|
||||||
setDefaults(MessageReflect(m))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func setDefaults(m protoreflect.Message) {
|
|
||||||
fds := m.Descriptor().Fields()
|
|
||||||
for i := 0; i < fds.Len(); i++ {
|
|
||||||
fd := fds.Get(i)
|
|
||||||
if !m.Has(fd) {
|
|
||||||
if fd.HasDefault() && fd.ContainingOneof() == nil {
|
|
||||||
v := fd.Default()
|
|
||||||
if fd.Kind() == protoreflect.BytesKind {
|
|
||||||
v = protoreflect.ValueOf(append([]byte(nil), v.Bytes()...)) // copy the default bytes
|
|
||||||
}
|
|
||||||
m.Set(fd, v)
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
|
|
||||||
switch {
|
|
||||||
// Handle singular message.
|
|
||||||
case fd.Cardinality() != protoreflect.Repeated:
|
|
||||||
if fd.Message() != nil {
|
|
||||||
setDefaults(m.Get(fd).Message())
|
|
||||||
}
|
|
||||||
// Handle list of messages.
|
|
||||||
case fd.IsList():
|
|
||||||
if fd.Message() != nil {
|
|
||||||
ls := m.Get(fd).List()
|
|
||||||
for i := 0; i < ls.Len(); i++ {
|
|
||||||
setDefaults(ls.Get(i).Message())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Handle map of messages.
|
|
||||||
case fd.IsMap():
|
|
||||||
if fd.MapValue().Message() != nil {
|
|
||||||
ms := m.Get(fd).Map()
|
|
||||||
ms.Range(func(_ protoreflect.MapKey, v protoreflect.Value) bool {
|
|
||||||
setDefaults(v.Message())
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
}
|
|
113
vendor/github.com/golang/protobuf/proto/deprecated.go
generated
vendored
113
vendor/github.com/golang/protobuf/proto/deprecated.go
generated
vendored
|
@ -1,113 +0,0 @@
|
||||||
// Copyright 2018 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package proto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
protoV2 "google.golang.org/protobuf/proto"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// Deprecated: No longer returned.
|
|
||||||
ErrNil = errors.New("proto: Marshal called with nil")
|
|
||||||
|
|
||||||
// Deprecated: No longer returned.
|
|
||||||
ErrTooLarge = errors.New("proto: message encodes to over 2 GB")
|
|
||||||
|
|
||||||
// Deprecated: No longer returned.
|
|
||||||
ErrInternalBadWireType = errors.New("proto: internal error: bad wiretype for oneof")
|
|
||||||
)
|
|
||||||
|
|
||||||
// Deprecated: Do not use.
|
|
||||||
type Stats struct{ Emalloc, Dmalloc, Encode, Decode, Chit, Cmiss, Size uint64 }
|
|
||||||
|
|
||||||
// Deprecated: Do not use.
|
|
||||||
func GetStats() Stats { return Stats{} }
|
|
||||||
|
|
||||||
// Deprecated: Do not use.
|
|
||||||
func MarshalMessageSet(interface{}) ([]byte, error) {
|
|
||||||
return nil, errors.New("proto: not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Do not use.
|
|
||||||
func UnmarshalMessageSet([]byte, interface{}) error {
|
|
||||||
return errors.New("proto: not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Do not use.
|
|
||||||
func MarshalMessageSetJSON(interface{}) ([]byte, error) {
|
|
||||||
return nil, errors.New("proto: not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Do not use.
|
|
||||||
func UnmarshalMessageSetJSON([]byte, interface{}) error {
|
|
||||||
return errors.New("proto: not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Do not use.
|
|
||||||
func RegisterMessageSetType(Message, int32, string) {}
|
|
||||||
|
|
||||||
// Deprecated: Do not use.
|
|
||||||
func EnumName(m map[int32]string, v int32) string {
|
|
||||||
s, ok := m[v]
|
|
||||||
if ok {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
return strconv.Itoa(int(v))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Do not use.
|
|
||||||
func UnmarshalJSONEnum(m map[string]int32, data []byte, enumName string) (int32, error) {
|
|
||||||
if data[0] == '"' {
|
|
||||||
// New style: enums are strings.
|
|
||||||
var repr string
|
|
||||||
if err := json.Unmarshal(data, &repr); err != nil {
|
|
||||||
return -1, err
|
|
||||||
}
|
|
||||||
val, ok := m[repr]
|
|
||||||
if !ok {
|
|
||||||
return 0, fmt.Errorf("unrecognized enum %s value %q", enumName, repr)
|
|
||||||
}
|
|
||||||
return val, nil
|
|
||||||
}
|
|
||||||
// Old style: enums are ints.
|
|
||||||
var val int32
|
|
||||||
if err := json.Unmarshal(data, &val); err != nil {
|
|
||||||
return 0, fmt.Errorf("cannot unmarshal %#q into enum %s", data, enumName)
|
|
||||||
}
|
|
||||||
return val, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Do not use; this type existed for intenal-use only.
|
|
||||||
type InternalMessageInfo struct{}
|
|
||||||
|
|
||||||
// Deprecated: Do not use; this method existed for intenal-use only.
|
|
||||||
func (*InternalMessageInfo) DiscardUnknown(m Message) {
|
|
||||||
DiscardUnknown(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Do not use; this method existed for intenal-use only.
|
|
||||||
func (*InternalMessageInfo) Marshal(b []byte, m Message, deterministic bool) ([]byte, error) {
|
|
||||||
return protoV2.MarshalOptions{Deterministic: deterministic}.MarshalAppend(b, MessageV2(m))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Do not use; this method existed for intenal-use only.
|
|
||||||
func (*InternalMessageInfo) Merge(dst, src Message) {
|
|
||||||
protoV2.Merge(MessageV2(dst), MessageV2(src))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Do not use; this method existed for intenal-use only.
|
|
||||||
func (*InternalMessageInfo) Size(m Message) int {
|
|
||||||
return protoV2.Size(MessageV2(m))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Do not use; this method existed for intenal-use only.
|
|
||||||
func (*InternalMessageInfo) Unmarshal(m Message, b []byte) error {
|
|
||||||
return protoV2.UnmarshalOptions{Merge: true}.Unmarshal(b, MessageV2(m))
|
|
||||||
}
|
|
58
vendor/github.com/golang/protobuf/proto/discard.go
generated
vendored
58
vendor/github.com/golang/protobuf/proto/discard.go
generated
vendored
|
@ -1,58 +0,0 @@
|
||||||
// Copyright 2019 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package proto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"google.golang.org/protobuf/reflect/protoreflect"
|
|
||||||
)
|
|
||||||
|
|
||||||
// DiscardUnknown recursively discards all unknown fields from this message
|
|
||||||
// and all embedded messages.
|
|
||||||
//
|
|
||||||
// When unmarshaling a message with unrecognized fields, the tags and values
|
|
||||||
// of such fields are preserved in the Message. This allows a later call to
|
|
||||||
// marshal to be able to produce a message that continues to have those
|
|
||||||
// unrecognized fields. To avoid this, DiscardUnknown is used to
|
|
||||||
// explicitly clear the unknown fields after unmarshaling.
|
|
||||||
func DiscardUnknown(m Message) {
|
|
||||||
if m != nil {
|
|
||||||
discardUnknown(MessageReflect(m))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func discardUnknown(m protoreflect.Message) {
|
|
||||||
m.Range(func(fd protoreflect.FieldDescriptor, val protoreflect.Value) bool {
|
|
||||||
switch {
|
|
||||||
// Handle singular message.
|
|
||||||
case fd.Cardinality() != protoreflect.Repeated:
|
|
||||||
if fd.Message() != nil {
|
|
||||||
discardUnknown(m.Get(fd).Message())
|
|
||||||
}
|
|
||||||
// Handle list of messages.
|
|
||||||
case fd.IsList():
|
|
||||||
if fd.Message() != nil {
|
|
||||||
ls := m.Get(fd).List()
|
|
||||||
for i := 0; i < ls.Len(); i++ {
|
|
||||||
discardUnknown(ls.Get(i).Message())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Handle map of messages.
|
|
||||||
case fd.IsMap():
|
|
||||||
if fd.MapValue().Message() != nil {
|
|
||||||
ms := m.Get(fd).Map()
|
|
||||||
ms.Range(func(_ protoreflect.MapKey, v protoreflect.Value) bool {
|
|
||||||
discardUnknown(v.Message())
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
|
|
||||||
// Discard unknown fields.
|
|
||||||
if len(m.GetUnknown()) > 0 {
|
|
||||||
m.SetUnknown(nil)
|
|
||||||
}
|
|
||||||
}
|
|
356
vendor/github.com/golang/protobuf/proto/extensions.go
generated
vendored
356
vendor/github.com/golang/protobuf/proto/extensions.go
generated
vendored
|
@ -1,356 +0,0 @@
|
||||||
// Copyright 2010 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package proto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
|
|
||||||
"google.golang.org/protobuf/encoding/protowire"
|
|
||||||
"google.golang.org/protobuf/proto"
|
|
||||||
"google.golang.org/protobuf/reflect/protoreflect"
|
|
||||||
"google.golang.org/protobuf/reflect/protoregistry"
|
|
||||||
"google.golang.org/protobuf/runtime/protoiface"
|
|
||||||
"google.golang.org/protobuf/runtime/protoimpl"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
// ExtensionDesc represents an extension descriptor and
|
|
||||||
// is used to interact with an extension field in a message.
|
|
||||||
//
|
|
||||||
// Variables of this type are generated in code by protoc-gen-go.
|
|
||||||
ExtensionDesc = protoimpl.ExtensionInfo
|
|
||||||
|
|
||||||
// ExtensionRange represents a range of message extensions.
|
|
||||||
// Used in code generated by protoc-gen-go.
|
|
||||||
ExtensionRange = protoiface.ExtensionRangeV1
|
|
||||||
|
|
||||||
// Deprecated: Do not use; this is an internal type.
|
|
||||||
Extension = protoimpl.ExtensionFieldV1
|
|
||||||
|
|
||||||
// Deprecated: Do not use; this is an internal type.
|
|
||||||
XXX_InternalExtensions = protoimpl.ExtensionFields
|
|
||||||
)
|
|
||||||
|
|
||||||
// ErrMissingExtension reports whether the extension was not present.
|
|
||||||
var ErrMissingExtension = errors.New("proto: missing extension")
|
|
||||||
|
|
||||||
var errNotExtendable = errors.New("proto: not an extendable proto.Message")
|
|
||||||
|
|
||||||
// HasExtension reports whether the extension field is present in m
|
|
||||||
// either as an explicitly populated field or as an unknown field.
|
|
||||||
func HasExtension(m Message, xt *ExtensionDesc) (has bool) {
|
|
||||||
mr := MessageReflect(m)
|
|
||||||
if mr == nil || !mr.IsValid() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check whether any populated known field matches the field number.
|
|
||||||
xtd := xt.TypeDescriptor()
|
|
||||||
if isValidExtension(mr.Descriptor(), xtd) {
|
|
||||||
has = mr.Has(xtd)
|
|
||||||
} else {
|
|
||||||
mr.Range(func(fd protoreflect.FieldDescriptor, _ protoreflect.Value) bool {
|
|
||||||
has = int32(fd.Number()) == xt.Field
|
|
||||||
return !has
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check whether any unknown field matches the field number.
|
|
||||||
for b := mr.GetUnknown(); !has && len(b) > 0; {
|
|
||||||
num, _, n := protowire.ConsumeField(b)
|
|
||||||
has = int32(num) == xt.Field
|
|
||||||
b = b[n:]
|
|
||||||
}
|
|
||||||
return has
|
|
||||||
}
|
|
||||||
|
|
||||||
// ClearExtension removes the extension field from m
|
|
||||||
// either as an explicitly populated field or as an unknown field.
|
|
||||||
func ClearExtension(m Message, xt *ExtensionDesc) {
|
|
||||||
mr := MessageReflect(m)
|
|
||||||
if mr == nil || !mr.IsValid() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
xtd := xt.TypeDescriptor()
|
|
||||||
if isValidExtension(mr.Descriptor(), xtd) {
|
|
||||||
mr.Clear(xtd)
|
|
||||||
} else {
|
|
||||||
mr.Range(func(fd protoreflect.FieldDescriptor, _ protoreflect.Value) bool {
|
|
||||||
if int32(fd.Number()) == xt.Field {
|
|
||||||
mr.Clear(fd)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
clearUnknown(mr, fieldNum(xt.Field))
|
|
||||||
}
|
|
||||||
|
|
||||||
// ClearAllExtensions clears all extensions from m.
|
|
||||||
// This includes populated fields and unknown fields in the extension range.
|
|
||||||
func ClearAllExtensions(m Message) {
|
|
||||||
mr := MessageReflect(m)
|
|
||||||
if mr == nil || !mr.IsValid() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
mr.Range(func(fd protoreflect.FieldDescriptor, _ protoreflect.Value) bool {
|
|
||||||
if fd.IsExtension() {
|
|
||||||
mr.Clear(fd)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
clearUnknown(mr, mr.Descriptor().ExtensionRanges())
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetExtension retrieves a proto2 extended field from m.
|
|
||||||
//
|
|
||||||
// If the descriptor is type complete (i.e., ExtensionDesc.ExtensionType is non-nil),
|
|
||||||
// then GetExtension parses the encoded field and returns a Go value of the specified type.
|
|
||||||
// If the field is not present, then the default value is returned (if one is specified),
|
|
||||||
// otherwise ErrMissingExtension is reported.
|
|
||||||
//
|
|
||||||
// If the descriptor is type incomplete (i.e., ExtensionDesc.ExtensionType is nil),
|
|
||||||
// then GetExtension returns the raw encoded bytes for the extension field.
|
|
||||||
func GetExtension(m Message, xt *ExtensionDesc) (interface{}, error) {
|
|
||||||
mr := MessageReflect(m)
|
|
||||||
if mr == nil || !mr.IsValid() || mr.Descriptor().ExtensionRanges().Len() == 0 {
|
|
||||||
return nil, errNotExtendable
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the unknown fields for this extension field.
|
|
||||||
var bo protoreflect.RawFields
|
|
||||||
for bi := mr.GetUnknown(); len(bi) > 0; {
|
|
||||||
num, _, n := protowire.ConsumeField(bi)
|
|
||||||
if int32(num) == xt.Field {
|
|
||||||
bo = append(bo, bi[:n]...)
|
|
||||||
}
|
|
||||||
bi = bi[n:]
|
|
||||||
}
|
|
||||||
|
|
||||||
// For type incomplete descriptors, only retrieve the unknown fields.
|
|
||||||
if xt.ExtensionType == nil {
|
|
||||||
return []byte(bo), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the extension field only exists as unknown fields, unmarshal it.
|
|
||||||
// This is rarely done since proto.Unmarshal eagerly unmarshals extensions.
|
|
||||||
xtd := xt.TypeDescriptor()
|
|
||||||
if !isValidExtension(mr.Descriptor(), xtd) {
|
|
||||||
return nil, fmt.Errorf("proto: bad extended type; %T does not extend %T", xt.ExtendedType, m)
|
|
||||||
}
|
|
||||||
if !mr.Has(xtd) && len(bo) > 0 {
|
|
||||||
m2 := mr.New()
|
|
||||||
if err := (proto.UnmarshalOptions{
|
|
||||||
Resolver: extensionResolver{xt},
|
|
||||||
}.Unmarshal(bo, m2.Interface())); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if m2.Has(xtd) {
|
|
||||||
mr.Set(xtd, m2.Get(xtd))
|
|
||||||
clearUnknown(mr, fieldNum(xt.Field))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check whether the message has the extension field set or a default.
|
|
||||||
var pv protoreflect.Value
|
|
||||||
switch {
|
|
||||||
case mr.Has(xtd):
|
|
||||||
pv = mr.Get(xtd)
|
|
||||||
case xtd.HasDefault():
|
|
||||||
pv = xtd.Default()
|
|
||||||
default:
|
|
||||||
return nil, ErrMissingExtension
|
|
||||||
}
|
|
||||||
|
|
||||||
v := xt.InterfaceOf(pv)
|
|
||||||
rv := reflect.ValueOf(v)
|
|
||||||
if isScalarKind(rv.Kind()) {
|
|
||||||
rv2 := reflect.New(rv.Type())
|
|
||||||
rv2.Elem().Set(rv)
|
|
||||||
v = rv2.Interface()
|
|
||||||
}
|
|
||||||
return v, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// extensionResolver is a custom extension resolver that stores a single
|
|
||||||
// extension type that takes precedence over the global registry.
|
|
||||||
type extensionResolver struct{ xt protoreflect.ExtensionType }
|
|
||||||
|
|
||||||
func (r extensionResolver) FindExtensionByName(field protoreflect.FullName) (protoreflect.ExtensionType, error) {
|
|
||||||
if xtd := r.xt.TypeDescriptor(); xtd.FullName() == field {
|
|
||||||
return r.xt, nil
|
|
||||||
}
|
|
||||||
return protoregistry.GlobalTypes.FindExtensionByName(field)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r extensionResolver) FindExtensionByNumber(message protoreflect.FullName, field protoreflect.FieldNumber) (protoreflect.ExtensionType, error) {
|
|
||||||
if xtd := r.xt.TypeDescriptor(); xtd.ContainingMessage().FullName() == message && xtd.Number() == field {
|
|
||||||
return r.xt, nil
|
|
||||||
}
|
|
||||||
return protoregistry.GlobalTypes.FindExtensionByNumber(message, field)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetExtensions returns a list of the extensions values present in m,
|
|
||||||
// corresponding with the provided list of extension descriptors, xts.
|
|
||||||
// If an extension is missing in m, the corresponding value is nil.
|
|
||||||
func GetExtensions(m Message, xts []*ExtensionDesc) ([]interface{}, error) {
|
|
||||||
mr := MessageReflect(m)
|
|
||||||
if mr == nil || !mr.IsValid() {
|
|
||||||
return nil, errNotExtendable
|
|
||||||
}
|
|
||||||
|
|
||||||
vs := make([]interface{}, len(xts))
|
|
||||||
for i, xt := range xts {
|
|
||||||
v, err := GetExtension(m, xt)
|
|
||||||
if err != nil {
|
|
||||||
if err == ErrMissingExtension {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return vs, err
|
|
||||||
}
|
|
||||||
vs[i] = v
|
|
||||||
}
|
|
||||||
return vs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetExtension sets an extension field in m to the provided value.
|
|
||||||
func SetExtension(m Message, xt *ExtensionDesc, v interface{}) error {
|
|
||||||
mr := MessageReflect(m)
|
|
||||||
if mr == nil || !mr.IsValid() || mr.Descriptor().ExtensionRanges().Len() == 0 {
|
|
||||||
return errNotExtendable
|
|
||||||
}
|
|
||||||
|
|
||||||
rv := reflect.ValueOf(v)
|
|
||||||
if reflect.TypeOf(v) != reflect.TypeOf(xt.ExtensionType) {
|
|
||||||
return fmt.Errorf("proto: bad extension value type. got: %T, want: %T", v, xt.ExtensionType)
|
|
||||||
}
|
|
||||||
if rv.Kind() == reflect.Ptr {
|
|
||||||
if rv.IsNil() {
|
|
||||||
return fmt.Errorf("proto: SetExtension called with nil value of type %T", v)
|
|
||||||
}
|
|
||||||
if isScalarKind(rv.Elem().Kind()) {
|
|
||||||
v = rv.Elem().Interface()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
xtd := xt.TypeDescriptor()
|
|
||||||
if !isValidExtension(mr.Descriptor(), xtd) {
|
|
||||||
return fmt.Errorf("proto: bad extended type; %T does not extend %T", xt.ExtendedType, m)
|
|
||||||
}
|
|
||||||
mr.Set(xtd, xt.ValueOf(v))
|
|
||||||
clearUnknown(mr, fieldNum(xt.Field))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetRawExtension inserts b into the unknown fields of m.
|
|
||||||
//
|
|
||||||
// Deprecated: Use Message.ProtoReflect.SetUnknown instead.
|
|
||||||
func SetRawExtension(m Message, fnum int32, b []byte) {
|
|
||||||
mr := MessageReflect(m)
|
|
||||||
if mr == nil || !mr.IsValid() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify that the raw field is valid.
|
|
||||||
for b0 := b; len(b0) > 0; {
|
|
||||||
num, _, n := protowire.ConsumeField(b0)
|
|
||||||
if int32(num) != fnum {
|
|
||||||
panic(fmt.Sprintf("mismatching field number: got %d, want %d", num, fnum))
|
|
||||||
}
|
|
||||||
b0 = b0[n:]
|
|
||||||
}
|
|
||||||
|
|
||||||
ClearExtension(m, &ExtensionDesc{Field: fnum})
|
|
||||||
mr.SetUnknown(append(mr.GetUnknown(), b...))
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExtensionDescs returns a list of extension descriptors found in m,
|
|
||||||
// containing descriptors for both populated extension fields in m and
|
|
||||||
// also unknown fields of m that are in the extension range.
|
|
||||||
// For the later case, an type incomplete descriptor is provided where only
|
|
||||||
// the ExtensionDesc.Field field is populated.
|
|
||||||
// The order of the extension descriptors is undefined.
|
|
||||||
func ExtensionDescs(m Message) ([]*ExtensionDesc, error) {
|
|
||||||
mr := MessageReflect(m)
|
|
||||||
if mr == nil || !mr.IsValid() || mr.Descriptor().ExtensionRanges().Len() == 0 {
|
|
||||||
return nil, errNotExtendable
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collect a set of known extension descriptors.
|
|
||||||
extDescs := make(map[protoreflect.FieldNumber]*ExtensionDesc)
|
|
||||||
mr.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
|
|
||||||
if fd.IsExtension() {
|
|
||||||
xt := fd.(protoreflect.ExtensionTypeDescriptor)
|
|
||||||
if xd, ok := xt.Type().(*ExtensionDesc); ok {
|
|
||||||
extDescs[fd.Number()] = xd
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
|
|
||||||
// Collect a set of unknown extension descriptors.
|
|
||||||
extRanges := mr.Descriptor().ExtensionRanges()
|
|
||||||
for b := mr.GetUnknown(); len(b) > 0; {
|
|
||||||
num, _, n := protowire.ConsumeField(b)
|
|
||||||
if extRanges.Has(num) && extDescs[num] == nil {
|
|
||||||
extDescs[num] = nil
|
|
||||||
}
|
|
||||||
b = b[n:]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transpose the set of descriptors into a list.
|
|
||||||
var xts []*ExtensionDesc
|
|
||||||
for num, xt := range extDescs {
|
|
||||||
if xt == nil {
|
|
||||||
xt = &ExtensionDesc{Field: int32(num)}
|
|
||||||
}
|
|
||||||
xts = append(xts, xt)
|
|
||||||
}
|
|
||||||
return xts, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// isValidExtension reports whether xtd is a valid extension descriptor for md.
|
|
||||||
func isValidExtension(md protoreflect.MessageDescriptor, xtd protoreflect.ExtensionTypeDescriptor) bool {
|
|
||||||
return xtd.ContainingMessage() == md && md.ExtensionRanges().Has(xtd.Number())
|
|
||||||
}
|
|
||||||
|
|
||||||
// isScalarKind reports whether k is a protobuf scalar kind (except bytes).
|
|
||||||
// This function exists for historical reasons since the representation of
|
|
||||||
// scalars differs between v1 and v2, where v1 uses *T and v2 uses T.
|
|
||||||
func isScalarKind(k reflect.Kind) bool {
|
|
||||||
switch k {
|
|
||||||
case reflect.Bool, reflect.Int32, reflect.Int64, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.String:
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// clearUnknown removes unknown fields from m where remover.Has reports true.
|
|
||||||
func clearUnknown(m protoreflect.Message, remover interface {
|
|
||||||
Has(protoreflect.FieldNumber) bool
|
|
||||||
}) {
|
|
||||||
var bo protoreflect.RawFields
|
|
||||||
for bi := m.GetUnknown(); len(bi) > 0; {
|
|
||||||
num, _, n := protowire.ConsumeField(bi)
|
|
||||||
if !remover.Has(num) {
|
|
||||||
bo = append(bo, bi[:n]...)
|
|
||||||
}
|
|
||||||
bi = bi[n:]
|
|
||||||
}
|
|
||||||
if bi := m.GetUnknown(); len(bi) != len(bo) {
|
|
||||||
m.SetUnknown(bo)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type fieldNum protoreflect.FieldNumber
|
|
||||||
|
|
||||||
func (n1 fieldNum) Has(n2 protoreflect.FieldNumber) bool {
|
|
||||||
return protoreflect.FieldNumber(n1) == n2
|
|
||||||
}
|
|
306
vendor/github.com/golang/protobuf/proto/properties.go
generated
vendored
306
vendor/github.com/golang/protobuf/proto/properties.go
generated
vendored
|
@ -1,306 +0,0 @@
|
||||||
// Copyright 2010 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package proto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"google.golang.org/protobuf/reflect/protoreflect"
|
|
||||||
"google.golang.org/protobuf/runtime/protoimpl"
|
|
||||||
)
|
|
||||||
|
|
||||||
// StructProperties represents protocol buffer type information for a
|
|
||||||
// generated protobuf message in the open-struct API.
|
|
||||||
//
|
|
||||||
// Deprecated: Do not use.
|
|
||||||
type StructProperties struct {
|
|
||||||
// Prop are the properties for each field.
|
|
||||||
//
|
|
||||||
// Fields belonging to a oneof are stored in OneofTypes instead, with a
|
|
||||||
// single Properties representing the parent oneof held here.
|
|
||||||
//
|
|
||||||
// The order of Prop matches the order of fields in the Go struct.
|
|
||||||
// Struct fields that are not related to protobufs have a "XXX_" prefix
|
|
||||||
// in the Properties.Name and must be ignored by the user.
|
|
||||||
Prop []*Properties
|
|
||||||
|
|
||||||
// OneofTypes contains information about the oneof fields in this message.
|
|
||||||
// It is keyed by the protobuf field name.
|
|
||||||
OneofTypes map[string]*OneofProperties
|
|
||||||
}
|
|
||||||
|
|
||||||
// Properties represents the type information for a protobuf message field.
|
|
||||||
//
|
|
||||||
// Deprecated: Do not use.
|
|
||||||
type Properties struct {
|
|
||||||
// Name is a placeholder name with little meaningful semantic value.
|
|
||||||
// If the name has an "XXX_" prefix, the entire Properties must be ignored.
|
|
||||||
Name string
|
|
||||||
// OrigName is the protobuf field name or oneof name.
|
|
||||||
OrigName string
|
|
||||||
// JSONName is the JSON name for the protobuf field.
|
|
||||||
JSONName string
|
|
||||||
// Enum is a placeholder name for enums.
|
|
||||||
// For historical reasons, this is neither the Go name for the enum,
|
|
||||||
// nor the protobuf name for the enum.
|
|
||||||
Enum string // Deprecated: Do not use.
|
|
||||||
// Weak contains the full name of the weakly referenced message.
|
|
||||||
Weak string
|
|
||||||
// Wire is a string representation of the wire type.
|
|
||||||
Wire string
|
|
||||||
// WireType is the protobuf wire type for the field.
|
|
||||||
WireType int
|
|
||||||
// Tag is the protobuf field number.
|
|
||||||
Tag int
|
|
||||||
// Required reports whether this is a required field.
|
|
||||||
Required bool
|
|
||||||
// Optional reports whether this is a optional field.
|
|
||||||
Optional bool
|
|
||||||
// Repeated reports whether this is a repeated field.
|
|
||||||
Repeated bool
|
|
||||||
// Packed reports whether this is a packed repeated field of scalars.
|
|
||||||
Packed bool
|
|
||||||
// Proto3 reports whether this field operates under the proto3 syntax.
|
|
||||||
Proto3 bool
|
|
||||||
// Oneof reports whether this field belongs within a oneof.
|
|
||||||
Oneof bool
|
|
||||||
|
|
||||||
// Default is the default value in string form.
|
|
||||||
Default string
|
|
||||||
// HasDefault reports whether the field has a default value.
|
|
||||||
HasDefault bool
|
|
||||||
|
|
||||||
// MapKeyProp is the properties for the key field for a map field.
|
|
||||||
MapKeyProp *Properties
|
|
||||||
// MapValProp is the properties for the value field for a map field.
|
|
||||||
MapValProp *Properties
|
|
||||||
}
|
|
||||||
|
|
||||||
// OneofProperties represents the type information for a protobuf oneof.
|
|
||||||
//
|
|
||||||
// Deprecated: Do not use.
|
|
||||||
type OneofProperties struct {
|
|
||||||
// Type is a pointer to the generated wrapper type for the field value.
|
|
||||||
// This is nil for messages that are not in the open-struct API.
|
|
||||||
Type reflect.Type
|
|
||||||
// Field is the index into StructProperties.Prop for the containing oneof.
|
|
||||||
Field int
|
|
||||||
// Prop is the properties for the field.
|
|
||||||
Prop *Properties
|
|
||||||
}
|
|
||||||
|
|
||||||
// String formats the properties in the protobuf struct field tag style.
|
|
||||||
func (p *Properties) String() string {
|
|
||||||
s := p.Wire
|
|
||||||
s += "," + strconv.Itoa(p.Tag)
|
|
||||||
if p.Required {
|
|
||||||
s += ",req"
|
|
||||||
}
|
|
||||||
if p.Optional {
|
|
||||||
s += ",opt"
|
|
||||||
}
|
|
||||||
if p.Repeated {
|
|
||||||
s += ",rep"
|
|
||||||
}
|
|
||||||
if p.Packed {
|
|
||||||
s += ",packed"
|
|
||||||
}
|
|
||||||
s += ",name=" + p.OrigName
|
|
||||||
if p.JSONName != "" {
|
|
||||||
s += ",json=" + p.JSONName
|
|
||||||
}
|
|
||||||
if len(p.Enum) > 0 {
|
|
||||||
s += ",enum=" + p.Enum
|
|
||||||
}
|
|
||||||
if len(p.Weak) > 0 {
|
|
||||||
s += ",weak=" + p.Weak
|
|
||||||
}
|
|
||||||
if p.Proto3 {
|
|
||||||
s += ",proto3"
|
|
||||||
}
|
|
||||||
if p.Oneof {
|
|
||||||
s += ",oneof"
|
|
||||||
}
|
|
||||||
if p.HasDefault {
|
|
||||||
s += ",def=" + p.Default
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse populates p by parsing a string in the protobuf struct field tag style.
|
|
||||||
func (p *Properties) Parse(tag string) {
|
|
||||||
// For example: "bytes,49,opt,name=foo,def=hello!"
|
|
||||||
for len(tag) > 0 {
|
|
||||||
i := strings.IndexByte(tag, ',')
|
|
||||||
if i < 0 {
|
|
||||||
i = len(tag)
|
|
||||||
}
|
|
||||||
switch s := tag[:i]; {
|
|
||||||
case strings.HasPrefix(s, "name="):
|
|
||||||
p.OrigName = s[len("name="):]
|
|
||||||
case strings.HasPrefix(s, "json="):
|
|
||||||
p.JSONName = s[len("json="):]
|
|
||||||
case strings.HasPrefix(s, "enum="):
|
|
||||||
p.Enum = s[len("enum="):]
|
|
||||||
case strings.HasPrefix(s, "weak="):
|
|
||||||
p.Weak = s[len("weak="):]
|
|
||||||
case strings.Trim(s, "0123456789") == "":
|
|
||||||
n, _ := strconv.ParseUint(s, 10, 32)
|
|
||||||
p.Tag = int(n)
|
|
||||||
case s == "opt":
|
|
||||||
p.Optional = true
|
|
||||||
case s == "req":
|
|
||||||
p.Required = true
|
|
||||||
case s == "rep":
|
|
||||||
p.Repeated = true
|
|
||||||
case s == "varint" || s == "zigzag32" || s == "zigzag64":
|
|
||||||
p.Wire = s
|
|
||||||
p.WireType = WireVarint
|
|
||||||
case s == "fixed32":
|
|
||||||
p.Wire = s
|
|
||||||
p.WireType = WireFixed32
|
|
||||||
case s == "fixed64":
|
|
||||||
p.Wire = s
|
|
||||||
p.WireType = WireFixed64
|
|
||||||
case s == "bytes":
|
|
||||||
p.Wire = s
|
|
||||||
p.WireType = WireBytes
|
|
||||||
case s == "group":
|
|
||||||
p.Wire = s
|
|
||||||
p.WireType = WireStartGroup
|
|
||||||
case s == "packed":
|
|
||||||
p.Packed = true
|
|
||||||
case s == "proto3":
|
|
||||||
p.Proto3 = true
|
|
||||||
case s == "oneof":
|
|
||||||
p.Oneof = true
|
|
||||||
case strings.HasPrefix(s, "def="):
|
|
||||||
// The default tag is special in that everything afterwards is the
|
|
||||||
// default regardless of the presence of commas.
|
|
||||||
p.HasDefault = true
|
|
||||||
p.Default, i = tag[len("def="):], len(tag)
|
|
||||||
}
|
|
||||||
tag = strings.TrimPrefix(tag[i:], ",")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Init populates the properties from a protocol buffer struct tag.
|
|
||||||
//
|
|
||||||
// Deprecated: Do not use.
|
|
||||||
func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) {
|
|
||||||
p.Name = name
|
|
||||||
p.OrigName = name
|
|
||||||
if tag == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
p.Parse(tag)
|
|
||||||
|
|
||||||
if typ != nil && typ.Kind() == reflect.Map {
|
|
||||||
p.MapKeyProp = new(Properties)
|
|
||||||
p.MapKeyProp.Init(nil, "Key", f.Tag.Get("protobuf_key"), nil)
|
|
||||||
p.MapValProp = new(Properties)
|
|
||||||
p.MapValProp.Init(nil, "Value", f.Tag.Get("protobuf_val"), nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var propertiesCache sync.Map // map[reflect.Type]*StructProperties
|
|
||||||
|
|
||||||
// GetProperties returns the list of properties for the type represented by t,
|
|
||||||
// which must be a generated protocol buffer message in the open-struct API,
|
|
||||||
// where protobuf message fields are represented by exported Go struct fields.
|
|
||||||
//
|
|
||||||
// Deprecated: Use protobuf reflection instead.
|
|
||||||
func GetProperties(t reflect.Type) *StructProperties {
|
|
||||||
if p, ok := propertiesCache.Load(t); ok {
|
|
||||||
return p.(*StructProperties)
|
|
||||||
}
|
|
||||||
p, _ := propertiesCache.LoadOrStore(t, newProperties(t))
|
|
||||||
return p.(*StructProperties)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newProperties(t reflect.Type) *StructProperties {
|
|
||||||
if t.Kind() != reflect.Struct {
|
|
||||||
panic(fmt.Sprintf("%v is not a generated message in the open-struct API", t))
|
|
||||||
}
|
|
||||||
|
|
||||||
var hasOneof bool
|
|
||||||
prop := new(StructProperties)
|
|
||||||
|
|
||||||
// Construct a list of properties for each field in the struct.
|
|
||||||
for i := 0; i < t.NumField(); i++ {
|
|
||||||
p := new(Properties)
|
|
||||||
f := t.Field(i)
|
|
||||||
tagField := f.Tag.Get("protobuf")
|
|
||||||
p.Init(f.Type, f.Name, tagField, &f)
|
|
||||||
|
|
||||||
tagOneof := f.Tag.Get("protobuf_oneof")
|
|
||||||
if tagOneof != "" {
|
|
||||||
hasOneof = true
|
|
||||||
p.OrigName = tagOneof
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rename unrelated struct fields with the "XXX_" prefix since so much
|
|
||||||
// user code simply checks for this to exclude special fields.
|
|
||||||
if tagField == "" && tagOneof == "" && !strings.HasPrefix(p.Name, "XXX_") {
|
|
||||||
p.Name = "XXX_" + p.Name
|
|
||||||
p.OrigName = "XXX_" + p.OrigName
|
|
||||||
} else if p.Weak != "" {
|
|
||||||
p.Name = p.OrigName // avoid possible "XXX_" prefix on weak field
|
|
||||||
}
|
|
||||||
|
|
||||||
prop.Prop = append(prop.Prop, p)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Construct a mapping of oneof field names to properties.
|
|
||||||
if hasOneof {
|
|
||||||
var oneofWrappers []interface{}
|
|
||||||
if fn, ok := reflect.PtrTo(t).MethodByName("XXX_OneofFuncs"); ok {
|
|
||||||
oneofWrappers = fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))})[3].Interface().([]interface{})
|
|
||||||
}
|
|
||||||
if fn, ok := reflect.PtrTo(t).MethodByName("XXX_OneofWrappers"); ok {
|
|
||||||
oneofWrappers = fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))})[0].Interface().([]interface{})
|
|
||||||
}
|
|
||||||
if m, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(protoreflect.ProtoMessage); ok {
|
|
||||||
if m, ok := m.ProtoReflect().(interface{ ProtoMessageInfo() *protoimpl.MessageInfo }); ok {
|
|
||||||
oneofWrappers = m.ProtoMessageInfo().OneofWrappers
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
prop.OneofTypes = make(map[string]*OneofProperties)
|
|
||||||
for _, wrapper := range oneofWrappers {
|
|
||||||
p := &OneofProperties{
|
|
||||||
Type: reflect.ValueOf(wrapper).Type(), // *T
|
|
||||||
Prop: new(Properties),
|
|
||||||
}
|
|
||||||
f := p.Type.Elem().Field(0)
|
|
||||||
p.Prop.Name = f.Name
|
|
||||||
p.Prop.Parse(f.Tag.Get("protobuf"))
|
|
||||||
|
|
||||||
// Determine the struct field that contains this oneof.
|
|
||||||
// Each wrapper is assignable to exactly one parent field.
|
|
||||||
var foundOneof bool
|
|
||||||
for i := 0; i < t.NumField() && !foundOneof; i++ {
|
|
||||||
if p.Type.AssignableTo(t.Field(i).Type) {
|
|
||||||
p.Field = i
|
|
||||||
foundOneof = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !foundOneof {
|
|
||||||
panic(fmt.Sprintf("%v is not a generated message in the open-struct API", t))
|
|
||||||
}
|
|
||||||
prop.OneofTypes[p.Prop.OrigName] = p
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return prop
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sp *StructProperties) Len() int { return len(sp.Prop) }
|
|
||||||
func (sp *StructProperties) Less(i, j int) bool { return false }
|
|
||||||
func (sp *StructProperties) Swap(i, j int) { return }
|
|
167
vendor/github.com/golang/protobuf/proto/proto.go
generated
vendored
167
vendor/github.com/golang/protobuf/proto/proto.go
generated
vendored
|
@ -1,167 +0,0 @@
|
||||||
// Copyright 2019 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// Package proto provides functionality for handling protocol buffer messages.
|
|
||||||
// In particular, it provides marshaling and unmarshaling between a protobuf
|
|
||||||
// message and the binary wire format.
|
|
||||||
//
|
|
||||||
// See https://developers.google.com/protocol-buffers/docs/gotutorial for
|
|
||||||
// more information.
|
|
||||||
//
|
|
||||||
// Deprecated: Use the "google.golang.org/protobuf/proto" package instead.
|
|
||||||
package proto
|
|
||||||
|
|
||||||
import (
|
|
||||||
protoV2 "google.golang.org/protobuf/proto"
|
|
||||||
"google.golang.org/protobuf/reflect/protoreflect"
|
|
||||||
"google.golang.org/protobuf/runtime/protoiface"
|
|
||||||
"google.golang.org/protobuf/runtime/protoimpl"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
ProtoPackageIsVersion1 = true
|
|
||||||
ProtoPackageIsVersion2 = true
|
|
||||||
ProtoPackageIsVersion3 = true
|
|
||||||
ProtoPackageIsVersion4 = true
|
|
||||||
)
|
|
||||||
|
|
||||||
// GeneratedEnum is any enum type generated by protoc-gen-go
|
|
||||||
// which is a named int32 kind.
|
|
||||||
// This type exists for documentation purposes.
|
|
||||||
type GeneratedEnum interface{}
|
|
||||||
|
|
||||||
// GeneratedMessage is any message type generated by protoc-gen-go
|
|
||||||
// which is a pointer to a named struct kind.
|
|
||||||
// This type exists for documentation purposes.
|
|
||||||
type GeneratedMessage interface{}
|
|
||||||
|
|
||||||
// Message is a protocol buffer message.
|
|
||||||
//
|
|
||||||
// This is the v1 version of the message interface and is marginally better
|
|
||||||
// than an empty interface as it lacks any method to programatically interact
|
|
||||||
// with the contents of the message.
|
|
||||||
//
|
|
||||||
// A v2 message is declared in "google.golang.org/protobuf/proto".Message and
|
|
||||||
// exposes protobuf reflection as a first-class feature of the interface.
|
|
||||||
//
|
|
||||||
// To convert a v1 message to a v2 message, use the MessageV2 function.
|
|
||||||
// To convert a v2 message to a v1 message, use the MessageV1 function.
|
|
||||||
type Message = protoiface.MessageV1
|
|
||||||
|
|
||||||
// MessageV1 converts either a v1 or v2 message to a v1 message.
|
|
||||||
// It returns nil if m is nil.
|
|
||||||
func MessageV1(m GeneratedMessage) protoiface.MessageV1 {
|
|
||||||
return protoimpl.X.ProtoMessageV1Of(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MessageV2 converts either a v1 or v2 message to a v2 message.
|
|
||||||
// It returns nil if m is nil.
|
|
||||||
func MessageV2(m GeneratedMessage) protoV2.Message {
|
|
||||||
return protoimpl.X.ProtoMessageV2Of(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MessageReflect returns a reflective view for a message.
|
|
||||||
// It returns nil if m is nil.
|
|
||||||
func MessageReflect(m Message) protoreflect.Message {
|
|
||||||
return protoimpl.X.MessageOf(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Marshaler is implemented by messages that can marshal themselves.
|
|
||||||
// This interface is used by the following functions: Size, Marshal,
|
|
||||||
// Buffer.Marshal, and Buffer.EncodeMessage.
|
|
||||||
//
|
|
||||||
// Deprecated: Do not implement.
|
|
||||||
type Marshaler interface {
|
|
||||||
// Marshal formats the encoded bytes of the message.
|
|
||||||
// It should be deterministic and emit valid protobuf wire data.
|
|
||||||
// The caller takes ownership of the returned buffer.
|
|
||||||
Marshal() ([]byte, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unmarshaler is implemented by messages that can unmarshal themselves.
|
|
||||||
// This interface is used by the following functions: Unmarshal, UnmarshalMerge,
|
|
||||||
// Buffer.Unmarshal, Buffer.DecodeMessage, and Buffer.DecodeGroup.
|
|
||||||
//
|
|
||||||
// Deprecated: Do not implement.
|
|
||||||
type Unmarshaler interface {
|
|
||||||
// Unmarshal parses the encoded bytes of the protobuf wire input.
|
|
||||||
// The provided buffer is only valid for during method call.
|
|
||||||
// It should not reset the receiver message.
|
|
||||||
Unmarshal([]byte) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Merger is implemented by messages that can merge themselves.
|
|
||||||
// This interface is used by the following functions: Clone and Merge.
|
|
||||||
//
|
|
||||||
// Deprecated: Do not implement.
|
|
||||||
type Merger interface {
|
|
||||||
// Merge merges the contents of src into the receiver message.
|
|
||||||
// It clones all data structures in src such that it aliases no mutable
|
|
||||||
// memory referenced by src.
|
|
||||||
Merge(src Message)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RequiredNotSetError is an error type returned when
|
|
||||||
// marshaling or unmarshaling a message with missing required fields.
|
|
||||||
type RequiredNotSetError struct {
|
|
||||||
err error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *RequiredNotSetError) Error() string {
|
|
||||||
if e.err != nil {
|
|
||||||
return e.err.Error()
|
|
||||||
}
|
|
||||||
return "proto: required field not set"
|
|
||||||
}
|
|
||||||
func (e *RequiredNotSetError) RequiredNotSet() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkRequiredNotSet(m protoV2.Message) error {
|
|
||||||
if err := protoV2.CheckInitialized(m); err != nil {
|
|
||||||
return &RequiredNotSetError{err: err}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clone returns a deep copy of src.
|
|
||||||
func Clone(src Message) Message {
|
|
||||||
return MessageV1(protoV2.Clone(MessageV2(src)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Merge merges src into dst, which must be messages of the same type.
|
|
||||||
//
|
|
||||||
// Populated scalar fields in src are copied to dst, while populated
|
|
||||||
// singular messages in src are merged into dst by recursively calling Merge.
|
|
||||||
// The elements of every list field in src is appended to the corresponded
|
|
||||||
// list fields in dst. The entries of every map field in src is copied into
|
|
||||||
// the corresponding map field in dst, possibly replacing existing entries.
|
|
||||||
// The unknown fields of src are appended to the unknown fields of dst.
|
|
||||||
func Merge(dst, src Message) {
|
|
||||||
protoV2.Merge(MessageV2(dst), MessageV2(src))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Equal reports whether two messages are equal.
|
|
||||||
// If two messages marshal to the same bytes under deterministic serialization,
|
|
||||||
// then Equal is guaranteed to report true.
|
|
||||||
//
|
|
||||||
// Two messages are equal if they are the same protobuf message type,
|
|
||||||
// have the same set of populated known and extension field values,
|
|
||||||
// and the same set of unknown fields values.
|
|
||||||
//
|
|
||||||
// Scalar values are compared with the equivalent of the == operator in Go,
|
|
||||||
// except bytes values which are compared using bytes.Equal and
|
|
||||||
// floating point values which specially treat NaNs as equal.
|
|
||||||
// Message values are compared by recursively calling Equal.
|
|
||||||
// Lists are equal if each element value is also equal.
|
|
||||||
// Maps are equal if they have the same set of keys, where the pair of values
|
|
||||||
// for each key is also equal.
|
|
||||||
func Equal(x, y Message) bool {
|
|
||||||
return protoV2.Equal(MessageV2(x), MessageV2(y))
|
|
||||||
}
|
|
||||||
|
|
||||||
func isMessageSet(md protoreflect.MessageDescriptor) bool {
|
|
||||||
ms, ok := md.(interface{ IsMessageSet() bool })
|
|
||||||
return ok && ms.IsMessageSet()
|
|
||||||
}
|
|
323
vendor/github.com/golang/protobuf/proto/registry.go
generated
vendored
323
vendor/github.com/golang/protobuf/proto/registry.go
generated
vendored
|
@ -1,323 +0,0 @@
|
||||||
// Copyright 2019 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package proto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"compress/gzip"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"google.golang.org/protobuf/reflect/protoreflect"
|
|
||||||
"google.golang.org/protobuf/reflect/protoregistry"
|
|
||||||
"google.golang.org/protobuf/runtime/protoimpl"
|
|
||||||
)
|
|
||||||
|
|
||||||
// filePath is the path to the proto source file.
|
|
||||||
type filePath = string // e.g., "google/protobuf/descriptor.proto"
|
|
||||||
|
|
||||||
// fileDescGZIP is the compressed contents of the encoded FileDescriptorProto.
|
|
||||||
type fileDescGZIP = []byte
|
|
||||||
|
|
||||||
var fileCache sync.Map // map[filePath]fileDescGZIP
|
|
||||||
|
|
||||||
// RegisterFile is called from generated code to register the compressed
|
|
||||||
// FileDescriptorProto with the file path for a proto source file.
|
|
||||||
//
|
|
||||||
// Deprecated: Use protoregistry.GlobalFiles.RegisterFile instead.
|
|
||||||
func RegisterFile(s filePath, d fileDescGZIP) {
|
|
||||||
// Decompress the descriptor.
|
|
||||||
zr, err := gzip.NewReader(bytes.NewReader(d))
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("proto: invalid compressed file descriptor: %v", err))
|
|
||||||
}
|
|
||||||
b, err := ioutil.ReadAll(zr)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("proto: invalid compressed file descriptor: %v", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Construct a protoreflect.FileDescriptor from the raw descriptor.
|
|
||||||
// Note that DescBuilder.Build automatically registers the constructed
|
|
||||||
// file descriptor with the v2 registry.
|
|
||||||
protoimpl.DescBuilder{RawDescriptor: b}.Build()
|
|
||||||
|
|
||||||
// Locally cache the raw descriptor form for the file.
|
|
||||||
fileCache.Store(s, d)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FileDescriptor returns the compressed FileDescriptorProto given the file path
|
|
||||||
// for a proto source file. It returns nil if not found.
|
|
||||||
//
|
|
||||||
// Deprecated: Use protoregistry.GlobalFiles.FindFileByPath instead.
|
|
||||||
func FileDescriptor(s filePath) fileDescGZIP {
|
|
||||||
if v, ok := fileCache.Load(s); ok {
|
|
||||||
return v.(fileDescGZIP)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the descriptor in the v2 registry.
|
|
||||||
var b []byte
|
|
||||||
if fd, _ := protoregistry.GlobalFiles.FindFileByPath(s); fd != nil {
|
|
||||||
if fd, ok := fd.(interface{ ProtoLegacyRawDesc() []byte }); ok {
|
|
||||||
b = fd.ProtoLegacyRawDesc()
|
|
||||||
} else {
|
|
||||||
// TODO: Use protodesc.ToFileDescriptorProto to construct
|
|
||||||
// a descriptorpb.FileDescriptorProto and marshal it.
|
|
||||||
// However, doing so causes the proto package to have a dependency
|
|
||||||
// on descriptorpb, leading to cyclic dependency issues.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Locally cache the raw descriptor form for the file.
|
|
||||||
if len(b) > 0 {
|
|
||||||
v, _ := fileCache.LoadOrStore(s, protoimpl.X.CompressGZIP(b))
|
|
||||||
return v.(fileDescGZIP)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// enumName is the name of an enum. For historical reasons, the enum name is
|
|
||||||
// neither the full Go name nor the full protobuf name of the enum.
|
|
||||||
// The name is the dot-separated combination of just the proto package that the
|
|
||||||
// enum is declared within followed by the Go type name of the generated enum.
|
|
||||||
type enumName = string // e.g., "my.proto.package.GoMessage_GoEnum"
|
|
||||||
|
|
||||||
// enumsByName maps enum values by name to their numeric counterpart.
|
|
||||||
type enumsByName = map[string]int32
|
|
||||||
|
|
||||||
// enumsByNumber maps enum values by number to their name counterpart.
|
|
||||||
type enumsByNumber = map[int32]string
|
|
||||||
|
|
||||||
var enumCache sync.Map // map[enumName]enumsByName
|
|
||||||
var numFilesCache sync.Map // map[protoreflect.FullName]int
|
|
||||||
|
|
||||||
// RegisterEnum is called from the generated code to register the mapping of
|
|
||||||
// enum value names to enum numbers for the enum identified by s.
|
|
||||||
//
|
|
||||||
// Deprecated: Use protoregistry.GlobalTypes.RegisterEnum instead.
|
|
||||||
func RegisterEnum(s enumName, _ enumsByNumber, m enumsByName) {
|
|
||||||
if _, ok := enumCache.Load(s); ok {
|
|
||||||
panic("proto: duplicate enum registered: " + s)
|
|
||||||
}
|
|
||||||
enumCache.Store(s, m)
|
|
||||||
|
|
||||||
// This does not forward registration to the v2 registry since this API
|
|
||||||
// lacks sufficient information to construct a complete v2 enum descriptor.
|
|
||||||
}
|
|
||||||
|
|
||||||
// EnumValueMap returns the mapping from enum value names to enum numbers for
|
|
||||||
// the enum of the given name. It returns nil if not found.
|
|
||||||
//
|
|
||||||
// Deprecated: Use protoregistry.GlobalTypes.FindEnumByName instead.
|
|
||||||
func EnumValueMap(s enumName) enumsByName {
|
|
||||||
if v, ok := enumCache.Load(s); ok {
|
|
||||||
return v.(enumsByName)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check whether the cache is stale. If the number of files in the current
|
|
||||||
// package differs, then it means that some enums may have been recently
|
|
||||||
// registered upstream that we do not know about.
|
|
||||||
var protoPkg protoreflect.FullName
|
|
||||||
if i := strings.LastIndexByte(s, '.'); i >= 0 {
|
|
||||||
protoPkg = protoreflect.FullName(s[:i])
|
|
||||||
}
|
|
||||||
v, _ := numFilesCache.Load(protoPkg)
|
|
||||||
numFiles, _ := v.(int)
|
|
||||||
if protoregistry.GlobalFiles.NumFilesByPackage(protoPkg) == numFiles {
|
|
||||||
return nil // cache is up-to-date; was not found earlier
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the enum cache for all enums declared in the given proto package.
|
|
||||||
numFiles = 0
|
|
||||||
protoregistry.GlobalFiles.RangeFilesByPackage(protoPkg, func(fd protoreflect.FileDescriptor) bool {
|
|
||||||
walkEnums(fd, func(ed protoreflect.EnumDescriptor) {
|
|
||||||
name := protoimpl.X.LegacyEnumName(ed)
|
|
||||||
if _, ok := enumCache.Load(name); !ok {
|
|
||||||
m := make(enumsByName)
|
|
||||||
evs := ed.Values()
|
|
||||||
for i := evs.Len() - 1; i >= 0; i-- {
|
|
||||||
ev := evs.Get(i)
|
|
||||||
m[string(ev.Name())] = int32(ev.Number())
|
|
||||||
}
|
|
||||||
enumCache.LoadOrStore(name, m)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
numFiles++
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
numFilesCache.Store(protoPkg, numFiles)
|
|
||||||
|
|
||||||
// Check cache again for enum map.
|
|
||||||
if v, ok := enumCache.Load(s); ok {
|
|
||||||
return v.(enumsByName)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// walkEnums recursively walks all enums declared in d.
|
|
||||||
func walkEnums(d interface {
|
|
||||||
Enums() protoreflect.EnumDescriptors
|
|
||||||
Messages() protoreflect.MessageDescriptors
|
|
||||||
}, f func(protoreflect.EnumDescriptor)) {
|
|
||||||
eds := d.Enums()
|
|
||||||
for i := eds.Len() - 1; i >= 0; i-- {
|
|
||||||
f(eds.Get(i))
|
|
||||||
}
|
|
||||||
mds := d.Messages()
|
|
||||||
for i := mds.Len() - 1; i >= 0; i-- {
|
|
||||||
walkEnums(mds.Get(i), f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// messageName is the full name of protobuf message.
|
|
||||||
type messageName = string
|
|
||||||
|
|
||||||
var messageTypeCache sync.Map // map[messageName]reflect.Type
|
|
||||||
|
|
||||||
// RegisterType is called from generated code to register the message Go type
|
|
||||||
// for a message of the given name.
|
|
||||||
//
|
|
||||||
// Deprecated: Use protoregistry.GlobalTypes.RegisterMessage instead.
|
|
||||||
func RegisterType(m Message, s messageName) {
|
|
||||||
mt := protoimpl.X.LegacyMessageTypeOf(m, protoreflect.FullName(s))
|
|
||||||
if err := protoregistry.GlobalTypes.RegisterMessage(mt); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
messageTypeCache.Store(s, reflect.TypeOf(m))
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterMapType is called from generated code to register the Go map type
|
|
||||||
// for a protobuf message representing a map entry.
|
|
||||||
//
|
|
||||||
// Deprecated: Do not use.
|
|
||||||
func RegisterMapType(m interface{}, s messageName) {
|
|
||||||
t := reflect.TypeOf(m)
|
|
||||||
if t.Kind() != reflect.Map {
|
|
||||||
panic(fmt.Sprintf("invalid map kind: %v", t))
|
|
||||||
}
|
|
||||||
if _, ok := messageTypeCache.Load(s); ok {
|
|
||||||
panic(fmt.Errorf("proto: duplicate proto message registered: %s", s))
|
|
||||||
}
|
|
||||||
messageTypeCache.Store(s, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MessageType returns the message type for a named message.
|
|
||||||
// It returns nil if not found.
|
|
||||||
//
|
|
||||||
// Deprecated: Use protoregistry.GlobalTypes.FindMessageByName instead.
|
|
||||||
func MessageType(s messageName) reflect.Type {
|
|
||||||
if v, ok := messageTypeCache.Load(s); ok {
|
|
||||||
return v.(reflect.Type)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Derive the message type from the v2 registry.
|
|
||||||
var t reflect.Type
|
|
||||||
if mt, _ := protoregistry.GlobalTypes.FindMessageByName(protoreflect.FullName(s)); mt != nil {
|
|
||||||
t = messageGoType(mt)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we could not get a concrete type, it is possible that it is a
|
|
||||||
// pseudo-message for a map entry.
|
|
||||||
if t == nil {
|
|
||||||
d, _ := protoregistry.GlobalFiles.FindDescriptorByName(protoreflect.FullName(s))
|
|
||||||
if md, _ := d.(protoreflect.MessageDescriptor); md != nil && md.IsMapEntry() {
|
|
||||||
kt := goTypeForField(md.Fields().ByNumber(1))
|
|
||||||
vt := goTypeForField(md.Fields().ByNumber(2))
|
|
||||||
t = reflect.MapOf(kt, vt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Locally cache the message type for the given name.
|
|
||||||
if t != nil {
|
|
||||||
v, _ := messageTypeCache.LoadOrStore(s, t)
|
|
||||||
return v.(reflect.Type)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func goTypeForField(fd protoreflect.FieldDescriptor) reflect.Type {
|
|
||||||
switch k := fd.Kind(); k {
|
|
||||||
case protoreflect.EnumKind:
|
|
||||||
if et, _ := protoregistry.GlobalTypes.FindEnumByName(fd.Enum().FullName()); et != nil {
|
|
||||||
return enumGoType(et)
|
|
||||||
}
|
|
||||||
return reflect.TypeOf(protoreflect.EnumNumber(0))
|
|
||||||
case protoreflect.MessageKind, protoreflect.GroupKind:
|
|
||||||
if mt, _ := protoregistry.GlobalTypes.FindMessageByName(fd.Message().FullName()); mt != nil {
|
|
||||||
return messageGoType(mt)
|
|
||||||
}
|
|
||||||
return reflect.TypeOf((*protoreflect.Message)(nil)).Elem()
|
|
||||||
default:
|
|
||||||
return reflect.TypeOf(fd.Default().Interface())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func enumGoType(et protoreflect.EnumType) reflect.Type {
|
|
||||||
return reflect.TypeOf(et.New(0))
|
|
||||||
}
|
|
||||||
|
|
||||||
func messageGoType(mt protoreflect.MessageType) reflect.Type {
|
|
||||||
return reflect.TypeOf(MessageV1(mt.Zero().Interface()))
|
|
||||||
}
|
|
||||||
|
|
||||||
// MessageName returns the full protobuf name for the given message type.
|
|
||||||
//
|
|
||||||
// Deprecated: Use protoreflect.MessageDescriptor.FullName instead.
|
|
||||||
func MessageName(m Message) messageName {
|
|
||||||
if m == nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
if m, ok := m.(interface{ XXX_MessageName() messageName }); ok {
|
|
||||||
return m.XXX_MessageName()
|
|
||||||
}
|
|
||||||
return messageName(protoimpl.X.MessageDescriptorOf(m).FullName())
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterExtension is called from the generated code to register
|
|
||||||
// the extension descriptor.
|
|
||||||
//
|
|
||||||
// Deprecated: Use protoregistry.GlobalTypes.RegisterExtension instead.
|
|
||||||
func RegisterExtension(d *ExtensionDesc) {
|
|
||||||
if err := protoregistry.GlobalTypes.RegisterExtension(d); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type extensionsByNumber = map[int32]*ExtensionDesc
|
|
||||||
|
|
||||||
var extensionCache sync.Map // map[messageName]extensionsByNumber
|
|
||||||
|
|
||||||
// RegisteredExtensions returns a map of the registered extensions for the
|
|
||||||
// provided protobuf message, indexed by the extension field number.
|
|
||||||
//
|
|
||||||
// Deprecated: Use protoregistry.GlobalTypes.RangeExtensionsByMessage instead.
|
|
||||||
func RegisteredExtensions(m Message) extensionsByNumber {
|
|
||||||
// Check whether the cache is stale. If the number of extensions for
|
|
||||||
// the given message differs, then it means that some extensions were
|
|
||||||
// recently registered upstream that we do not know about.
|
|
||||||
s := MessageName(m)
|
|
||||||
v, _ := extensionCache.Load(s)
|
|
||||||
xs, _ := v.(extensionsByNumber)
|
|
||||||
if protoregistry.GlobalTypes.NumExtensionsByMessage(protoreflect.FullName(s)) == len(xs) {
|
|
||||||
return xs // cache is up-to-date
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cache is stale, re-compute the extensions map.
|
|
||||||
xs = make(extensionsByNumber)
|
|
||||||
protoregistry.GlobalTypes.RangeExtensionsByMessage(protoreflect.FullName(s), func(xt protoreflect.ExtensionType) bool {
|
|
||||||
if xd, ok := xt.(*ExtensionDesc); ok {
|
|
||||||
xs[int32(xt.TypeDescriptor().Number())] = xd
|
|
||||||
} else {
|
|
||||||
// TODO: This implies that the protoreflect.ExtensionType is a
|
|
||||||
// custom type not generated by protoc-gen-go. We could try and
|
|
||||||
// convert the type to an ExtensionDesc.
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
extensionCache.Store(s, xs)
|
|
||||||
return xs
|
|
||||||
}
|
|
801
vendor/github.com/golang/protobuf/proto/text_decode.go
generated
vendored
801
vendor/github.com/golang/protobuf/proto/text_decode.go
generated
vendored
|
@ -1,801 +0,0 @@
|
||||||
// Copyright 2010 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package proto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"unicode/utf8"
|
|
||||||
|
|
||||||
"google.golang.org/protobuf/encoding/prototext"
|
|
||||||
protoV2 "google.golang.org/protobuf/proto"
|
|
||||||
"google.golang.org/protobuf/reflect/protoreflect"
|
|
||||||
"google.golang.org/protobuf/reflect/protoregistry"
|
|
||||||
)
|
|
||||||
|
|
||||||
const wrapTextUnmarshalV2 = false
|
|
||||||
|
|
||||||
// ParseError is returned by UnmarshalText.
|
|
||||||
type ParseError struct {
|
|
||||||
Message string
|
|
||||||
|
|
||||||
// Deprecated: Do not use.
|
|
||||||
Line, Offset int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ParseError) Error() string {
|
|
||||||
if wrapTextUnmarshalV2 {
|
|
||||||
return e.Message
|
|
||||||
}
|
|
||||||
if e.Line == 1 {
|
|
||||||
return fmt.Sprintf("line 1.%d: %v", e.Offset, e.Message)
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("line %d: %v", e.Line, e.Message)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalText parses a proto text formatted string into m.
|
|
||||||
func UnmarshalText(s string, m Message) error {
|
|
||||||
if u, ok := m.(encoding.TextUnmarshaler); ok {
|
|
||||||
return u.UnmarshalText([]byte(s))
|
|
||||||
}
|
|
||||||
|
|
||||||
m.Reset()
|
|
||||||
mi := MessageV2(m)
|
|
||||||
|
|
||||||
if wrapTextUnmarshalV2 {
|
|
||||||
err := prototext.UnmarshalOptions{
|
|
||||||
AllowPartial: true,
|
|
||||||
}.Unmarshal([]byte(s), mi)
|
|
||||||
if err != nil {
|
|
||||||
return &ParseError{Message: err.Error()}
|
|
||||||
}
|
|
||||||
return checkRequiredNotSet(mi)
|
|
||||||
} else {
|
|
||||||
if err := newTextParser(s).unmarshalMessage(mi.ProtoReflect(), ""); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return checkRequiredNotSet(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type textParser struct {
|
|
||||||
s string // remaining input
|
|
||||||
done bool // whether the parsing is finished (success or error)
|
|
||||||
backed bool // whether back() was called
|
|
||||||
offset, line int
|
|
||||||
cur token
|
|
||||||
}
|
|
||||||
|
|
||||||
type token struct {
|
|
||||||
value string
|
|
||||||
err *ParseError
|
|
||||||
line int // line number
|
|
||||||
offset int // byte number from start of input, not start of line
|
|
||||||
unquoted string // the unquoted version of value, if it was a quoted string
|
|
||||||
}
|
|
||||||
|
|
||||||
func newTextParser(s string) *textParser {
|
|
||||||
p := new(textParser)
|
|
||||||
p.s = s
|
|
||||||
p.line = 1
|
|
||||||
p.cur.line = 1
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *textParser) unmarshalMessage(m protoreflect.Message, terminator string) (err error) {
|
|
||||||
md := m.Descriptor()
|
|
||||||
fds := md.Fields()
|
|
||||||
|
|
||||||
// A struct is a sequence of "name: value", terminated by one of
|
|
||||||
// '>' or '}', or the end of the input. A name may also be
|
|
||||||
// "[extension]" or "[type/url]".
|
|
||||||
//
|
|
||||||
// The whole struct can also be an expanded Any message, like:
|
|
||||||
// [type/url] < ... struct contents ... >
|
|
||||||
seen := make(map[protoreflect.FieldNumber]bool)
|
|
||||||
for {
|
|
||||||
tok := p.next()
|
|
||||||
if tok.err != nil {
|
|
||||||
return tok.err
|
|
||||||
}
|
|
||||||
if tok.value == terminator {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if tok.value == "[" {
|
|
||||||
if err := p.unmarshalExtensionOrAny(m, seen); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is a normal, non-extension field.
|
|
||||||
name := protoreflect.Name(tok.value)
|
|
||||||
fd := fds.ByName(name)
|
|
||||||
switch {
|
|
||||||
case fd == nil:
|
|
||||||
gd := fds.ByName(protoreflect.Name(strings.ToLower(string(name))))
|
|
||||||
if gd != nil && gd.Kind() == protoreflect.GroupKind && gd.Message().Name() == name {
|
|
||||||
fd = gd
|
|
||||||
}
|
|
||||||
case fd.Kind() == protoreflect.GroupKind && fd.Message().Name() != name:
|
|
||||||
fd = nil
|
|
||||||
case fd.IsWeak() && fd.Message().IsPlaceholder():
|
|
||||||
fd = nil
|
|
||||||
}
|
|
||||||
if fd == nil {
|
|
||||||
typeName := string(md.FullName())
|
|
||||||
if m, ok := m.Interface().(Message); ok {
|
|
||||||
t := reflect.TypeOf(m)
|
|
||||||
if t.Kind() == reflect.Ptr {
|
|
||||||
typeName = t.Elem().String()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return p.errorf("unknown field name %q in %v", name, typeName)
|
|
||||||
}
|
|
||||||
if od := fd.ContainingOneof(); od != nil && m.WhichOneof(od) != nil {
|
|
||||||
return p.errorf("field '%s' would overwrite already parsed oneof '%s'", name, od.Name())
|
|
||||||
}
|
|
||||||
if fd.Cardinality() != protoreflect.Repeated && seen[fd.Number()] {
|
|
||||||
return p.errorf("non-repeated field %q was repeated", fd.Name())
|
|
||||||
}
|
|
||||||
seen[fd.Number()] = true
|
|
||||||
|
|
||||||
// Consume any colon.
|
|
||||||
if err := p.checkForColon(fd); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse into the field.
|
|
||||||
v := m.Get(fd)
|
|
||||||
if !m.Has(fd) && (fd.IsList() || fd.IsMap() || fd.Message() != nil) {
|
|
||||||
v = m.Mutable(fd)
|
|
||||||
}
|
|
||||||
if v, err = p.unmarshalValue(v, fd); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
m.Set(fd, v)
|
|
||||||
|
|
||||||
if err := p.consumeOptionalSeparator(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *textParser) unmarshalExtensionOrAny(m protoreflect.Message, seen map[protoreflect.FieldNumber]bool) error {
|
|
||||||
name, err := p.consumeExtensionOrAnyName()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// If it contains a slash, it's an Any type URL.
|
|
||||||
if slashIdx := strings.LastIndex(name, "/"); slashIdx >= 0 {
|
|
||||||
tok := p.next()
|
|
||||||
if tok.err != nil {
|
|
||||||
return tok.err
|
|
||||||
}
|
|
||||||
// consume an optional colon
|
|
||||||
if tok.value == ":" {
|
|
||||||
tok = p.next()
|
|
||||||
if tok.err != nil {
|
|
||||||
return tok.err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var terminator string
|
|
||||||
switch tok.value {
|
|
||||||
case "<":
|
|
||||||
terminator = ">"
|
|
||||||
case "{":
|
|
||||||
terminator = "}"
|
|
||||||
default:
|
|
||||||
return p.errorf("expected '{' or '<', found %q", tok.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
mt, err := protoregistry.GlobalTypes.FindMessageByURL(name)
|
|
||||||
if err != nil {
|
|
||||||
return p.errorf("unrecognized message %q in google.protobuf.Any", name[slashIdx+len("/"):])
|
|
||||||
}
|
|
||||||
m2 := mt.New()
|
|
||||||
if err := p.unmarshalMessage(m2, terminator); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
b, err := protoV2.Marshal(m2.Interface())
|
|
||||||
if err != nil {
|
|
||||||
return p.errorf("failed to marshal message of type %q: %v", name[slashIdx+len("/"):], err)
|
|
||||||
}
|
|
||||||
|
|
||||||
urlFD := m.Descriptor().Fields().ByName("type_url")
|
|
||||||
valFD := m.Descriptor().Fields().ByName("value")
|
|
||||||
if seen[urlFD.Number()] {
|
|
||||||
return p.errorf("Any message unpacked multiple times, or %q already set", urlFD.Name())
|
|
||||||
}
|
|
||||||
if seen[valFD.Number()] {
|
|
||||||
return p.errorf("Any message unpacked multiple times, or %q already set", valFD.Name())
|
|
||||||
}
|
|
||||||
m.Set(urlFD, protoreflect.ValueOfString(name))
|
|
||||||
m.Set(valFD, protoreflect.ValueOfBytes(b))
|
|
||||||
seen[urlFD.Number()] = true
|
|
||||||
seen[valFD.Number()] = true
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
xname := protoreflect.FullName(name)
|
|
||||||
xt, _ := protoregistry.GlobalTypes.FindExtensionByName(xname)
|
|
||||||
if xt == nil && isMessageSet(m.Descriptor()) {
|
|
||||||
xt, _ = protoregistry.GlobalTypes.FindExtensionByName(xname.Append("message_set_extension"))
|
|
||||||
}
|
|
||||||
if xt == nil {
|
|
||||||
return p.errorf("unrecognized extension %q", name)
|
|
||||||
}
|
|
||||||
fd := xt.TypeDescriptor()
|
|
||||||
if fd.ContainingMessage().FullName() != m.Descriptor().FullName() {
|
|
||||||
return p.errorf("extension field %q does not extend message %q", name, m.Descriptor().FullName())
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := p.checkForColon(fd); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
v := m.Get(fd)
|
|
||||||
if !m.Has(fd) && (fd.IsList() || fd.IsMap() || fd.Message() != nil) {
|
|
||||||
v = m.Mutable(fd)
|
|
||||||
}
|
|
||||||
v, err = p.unmarshalValue(v, fd)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
m.Set(fd, v)
|
|
||||||
return p.consumeOptionalSeparator()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *textParser) unmarshalValue(v protoreflect.Value, fd protoreflect.FieldDescriptor) (protoreflect.Value, error) {
|
|
||||||
tok := p.next()
|
|
||||||
if tok.err != nil {
|
|
||||||
return v, tok.err
|
|
||||||
}
|
|
||||||
if tok.value == "" {
|
|
||||||
return v, p.errorf("unexpected EOF")
|
|
||||||
}
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case fd.IsList():
|
|
||||||
lv := v.List()
|
|
||||||
var err error
|
|
||||||
if tok.value == "[" {
|
|
||||||
// Repeated field with list notation, like [1,2,3].
|
|
||||||
for {
|
|
||||||
vv := lv.NewElement()
|
|
||||||
vv, err = p.unmarshalSingularValue(vv, fd)
|
|
||||||
if err != nil {
|
|
||||||
return v, err
|
|
||||||
}
|
|
||||||
lv.Append(vv)
|
|
||||||
|
|
||||||
tok := p.next()
|
|
||||||
if tok.err != nil {
|
|
||||||
return v, tok.err
|
|
||||||
}
|
|
||||||
if tok.value == "]" {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if tok.value != "," {
|
|
||||||
return v, p.errorf("Expected ']' or ',' found %q", tok.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return v, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// One value of the repeated field.
|
|
||||||
p.back()
|
|
||||||
vv := lv.NewElement()
|
|
||||||
vv, err = p.unmarshalSingularValue(vv, fd)
|
|
||||||
if err != nil {
|
|
||||||
return v, err
|
|
||||||
}
|
|
||||||
lv.Append(vv)
|
|
||||||
return v, nil
|
|
||||||
case fd.IsMap():
|
|
||||||
// The map entry should be this sequence of tokens:
|
|
||||||
// < key : KEY value : VALUE >
|
|
||||||
// However, implementations may omit key or value, and technically
|
|
||||||
// we should support them in any order.
|
|
||||||
var terminator string
|
|
||||||
switch tok.value {
|
|
||||||
case "<":
|
|
||||||
terminator = ">"
|
|
||||||
case "{":
|
|
||||||
terminator = "}"
|
|
||||||
default:
|
|
||||||
return v, p.errorf("expected '{' or '<', found %q", tok.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
keyFD := fd.MapKey()
|
|
||||||
valFD := fd.MapValue()
|
|
||||||
|
|
||||||
mv := v.Map()
|
|
||||||
kv := keyFD.Default()
|
|
||||||
vv := mv.NewValue()
|
|
||||||
for {
|
|
||||||
tok := p.next()
|
|
||||||
if tok.err != nil {
|
|
||||||
return v, tok.err
|
|
||||||
}
|
|
||||||
if tok.value == terminator {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
var err error
|
|
||||||
switch tok.value {
|
|
||||||
case "key":
|
|
||||||
if err := p.consumeToken(":"); err != nil {
|
|
||||||
return v, err
|
|
||||||
}
|
|
||||||
if kv, err = p.unmarshalSingularValue(kv, keyFD); err != nil {
|
|
||||||
return v, err
|
|
||||||
}
|
|
||||||
if err := p.consumeOptionalSeparator(); err != nil {
|
|
||||||
return v, err
|
|
||||||
}
|
|
||||||
case "value":
|
|
||||||
if err := p.checkForColon(valFD); err != nil {
|
|
||||||
return v, err
|
|
||||||
}
|
|
||||||
if vv, err = p.unmarshalSingularValue(vv, valFD); err != nil {
|
|
||||||
return v, err
|
|
||||||
}
|
|
||||||
if err := p.consumeOptionalSeparator(); err != nil {
|
|
||||||
return v, err
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
p.back()
|
|
||||||
return v, p.errorf(`expected "key", "value", or %q, found %q`, terminator, tok.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mv.Set(kv.MapKey(), vv)
|
|
||||||
return v, nil
|
|
||||||
default:
|
|
||||||
p.back()
|
|
||||||
return p.unmarshalSingularValue(v, fd)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *textParser) unmarshalSingularValue(v protoreflect.Value, fd protoreflect.FieldDescriptor) (protoreflect.Value, error) {
|
|
||||||
tok := p.next()
|
|
||||||
if tok.err != nil {
|
|
||||||
return v, tok.err
|
|
||||||
}
|
|
||||||
if tok.value == "" {
|
|
||||||
return v, p.errorf("unexpected EOF")
|
|
||||||
}
|
|
||||||
|
|
||||||
switch fd.Kind() {
|
|
||||||
case protoreflect.BoolKind:
|
|
||||||
switch tok.value {
|
|
||||||
case "true", "1", "t", "True":
|
|
||||||
return protoreflect.ValueOfBool(true), nil
|
|
||||||
case "false", "0", "f", "False":
|
|
||||||
return protoreflect.ValueOfBool(false), nil
|
|
||||||
}
|
|
||||||
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
|
|
||||||
if x, err := strconv.ParseInt(tok.value, 0, 32); err == nil {
|
|
||||||
return protoreflect.ValueOfInt32(int32(x)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// The C++ parser accepts large positive hex numbers that uses
|
|
||||||
// two's complement arithmetic to represent negative numbers.
|
|
||||||
// This feature is here for backwards compatibility with C++.
|
|
||||||
if strings.HasPrefix(tok.value, "0x") {
|
|
||||||
if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil {
|
|
||||||
return protoreflect.ValueOfInt32(int32(-(int64(^x) + 1))), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
|
|
||||||
if x, err := strconv.ParseInt(tok.value, 0, 64); err == nil {
|
|
||||||
return protoreflect.ValueOfInt64(int64(x)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// The C++ parser accepts large positive hex numbers that uses
|
|
||||||
// two's complement arithmetic to represent negative numbers.
|
|
||||||
// This feature is here for backwards compatibility with C++.
|
|
||||||
if strings.HasPrefix(tok.value, "0x") {
|
|
||||||
if x, err := strconv.ParseUint(tok.value, 0, 64); err == nil {
|
|
||||||
return protoreflect.ValueOfInt64(int64(-(int64(^x) + 1))), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case protoreflect.Uint32Kind, protoreflect.Fixed32Kind:
|
|
||||||
if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil {
|
|
||||||
return protoreflect.ValueOfUint32(uint32(x)), nil
|
|
||||||
}
|
|
||||||
case protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
|
|
||||||
if x, err := strconv.ParseUint(tok.value, 0, 64); err == nil {
|
|
||||||
return protoreflect.ValueOfUint64(uint64(x)), nil
|
|
||||||
}
|
|
||||||
case protoreflect.FloatKind:
|
|
||||||
// Ignore 'f' for compatibility with output generated by C++,
|
|
||||||
// but don't remove 'f' when the value is "-inf" or "inf".
|
|
||||||
v := tok.value
|
|
||||||
if strings.HasSuffix(v, "f") && v != "-inf" && v != "inf" {
|
|
||||||
v = v[:len(v)-len("f")]
|
|
||||||
}
|
|
||||||
if x, err := strconv.ParseFloat(v, 32); err == nil {
|
|
||||||
return protoreflect.ValueOfFloat32(float32(x)), nil
|
|
||||||
}
|
|
||||||
case protoreflect.DoubleKind:
|
|
||||||
// Ignore 'f' for compatibility with output generated by C++,
|
|
||||||
// but don't remove 'f' when the value is "-inf" or "inf".
|
|
||||||
v := tok.value
|
|
||||||
if strings.HasSuffix(v, "f") && v != "-inf" && v != "inf" {
|
|
||||||
v = v[:len(v)-len("f")]
|
|
||||||
}
|
|
||||||
if x, err := strconv.ParseFloat(v, 64); err == nil {
|
|
||||||
return protoreflect.ValueOfFloat64(float64(x)), nil
|
|
||||||
}
|
|
||||||
case protoreflect.StringKind:
|
|
||||||
if isQuote(tok.value[0]) {
|
|
||||||
return protoreflect.ValueOfString(tok.unquoted), nil
|
|
||||||
}
|
|
||||||
case protoreflect.BytesKind:
|
|
||||||
if isQuote(tok.value[0]) {
|
|
||||||
return protoreflect.ValueOfBytes([]byte(tok.unquoted)), nil
|
|
||||||
}
|
|
||||||
case protoreflect.EnumKind:
|
|
||||||
if x, err := strconv.ParseInt(tok.value, 0, 32); err == nil {
|
|
||||||
return protoreflect.ValueOfEnum(protoreflect.EnumNumber(x)), nil
|
|
||||||
}
|
|
||||||
vd := fd.Enum().Values().ByName(protoreflect.Name(tok.value))
|
|
||||||
if vd != nil {
|
|
||||||
return protoreflect.ValueOfEnum(vd.Number()), nil
|
|
||||||
}
|
|
||||||
case protoreflect.MessageKind, protoreflect.GroupKind:
|
|
||||||
var terminator string
|
|
||||||
switch tok.value {
|
|
||||||
case "{":
|
|
||||||
terminator = "}"
|
|
||||||
case "<":
|
|
||||||
terminator = ">"
|
|
||||||
default:
|
|
||||||
return v, p.errorf("expected '{' or '<', found %q", tok.value)
|
|
||||||
}
|
|
||||||
err := p.unmarshalMessage(v.Message(), terminator)
|
|
||||||
return v, err
|
|
||||||
default:
|
|
||||||
panic(fmt.Sprintf("invalid kind %v", fd.Kind()))
|
|
||||||
}
|
|
||||||
return v, p.errorf("invalid %v: %v", fd.Kind(), tok.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Consume a ':' from the input stream (if the next token is a colon),
|
|
||||||
// returning an error if a colon is needed but not present.
|
|
||||||
func (p *textParser) checkForColon(fd protoreflect.FieldDescriptor) *ParseError {
|
|
||||||
tok := p.next()
|
|
||||||
if tok.err != nil {
|
|
||||||
return tok.err
|
|
||||||
}
|
|
||||||
if tok.value != ":" {
|
|
||||||
if fd.Message() == nil {
|
|
||||||
return p.errorf("expected ':', found %q", tok.value)
|
|
||||||
}
|
|
||||||
p.back()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// consumeExtensionOrAnyName consumes an extension name or an Any type URL and
|
|
||||||
// the following ']'. It returns the name or URL consumed.
|
|
||||||
func (p *textParser) consumeExtensionOrAnyName() (string, error) {
|
|
||||||
tok := p.next()
|
|
||||||
if tok.err != nil {
|
|
||||||
return "", tok.err
|
|
||||||
}
|
|
||||||
|
|
||||||
// If extension name or type url is quoted, it's a single token.
|
|
||||||
if len(tok.value) > 2 && isQuote(tok.value[0]) && tok.value[len(tok.value)-1] == tok.value[0] {
|
|
||||||
name, err := unquoteC(tok.value[1:len(tok.value)-1], rune(tok.value[0]))
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return name, p.consumeToken("]")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Consume everything up to "]"
|
|
||||||
var parts []string
|
|
||||||
for tok.value != "]" {
|
|
||||||
parts = append(parts, tok.value)
|
|
||||||
tok = p.next()
|
|
||||||
if tok.err != nil {
|
|
||||||
return "", p.errorf("unrecognized type_url or extension name: %s", tok.err)
|
|
||||||
}
|
|
||||||
if p.done && tok.value != "]" {
|
|
||||||
return "", p.errorf("unclosed type_url or extension name")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return strings.Join(parts, ""), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// consumeOptionalSeparator consumes an optional semicolon or comma.
|
|
||||||
// It is used in unmarshalMessage to provide backward compatibility.
|
|
||||||
func (p *textParser) consumeOptionalSeparator() error {
|
|
||||||
tok := p.next()
|
|
||||||
if tok.err != nil {
|
|
||||||
return tok.err
|
|
||||||
}
|
|
||||||
if tok.value != ";" && tok.value != "," {
|
|
||||||
p.back()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *textParser) errorf(format string, a ...interface{}) *ParseError {
|
|
||||||
pe := &ParseError{fmt.Sprintf(format, a...), p.cur.line, p.cur.offset}
|
|
||||||
p.cur.err = pe
|
|
||||||
p.done = true
|
|
||||||
return pe
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *textParser) skipWhitespace() {
|
|
||||||
i := 0
|
|
||||||
for i < len(p.s) && (isWhitespace(p.s[i]) || p.s[i] == '#') {
|
|
||||||
if p.s[i] == '#' {
|
|
||||||
// comment; skip to end of line or input
|
|
||||||
for i < len(p.s) && p.s[i] != '\n' {
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
if i == len(p.s) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if p.s[i] == '\n' {
|
|
||||||
p.line++
|
|
||||||
}
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
p.offset += i
|
|
||||||
p.s = p.s[i:len(p.s)]
|
|
||||||
if len(p.s) == 0 {
|
|
||||||
p.done = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *textParser) advance() {
|
|
||||||
// Skip whitespace
|
|
||||||
p.skipWhitespace()
|
|
||||||
if p.done {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start of non-whitespace
|
|
||||||
p.cur.err = nil
|
|
||||||
p.cur.offset, p.cur.line = p.offset, p.line
|
|
||||||
p.cur.unquoted = ""
|
|
||||||
switch p.s[0] {
|
|
||||||
case '<', '>', '{', '}', ':', '[', ']', ';', ',', '/':
|
|
||||||
// Single symbol
|
|
||||||
p.cur.value, p.s = p.s[0:1], p.s[1:len(p.s)]
|
|
||||||
case '"', '\'':
|
|
||||||
// Quoted string
|
|
||||||
i := 1
|
|
||||||
for i < len(p.s) && p.s[i] != p.s[0] && p.s[i] != '\n' {
|
|
||||||
if p.s[i] == '\\' && i+1 < len(p.s) {
|
|
||||||
// skip escaped char
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
if i >= len(p.s) || p.s[i] != p.s[0] {
|
|
||||||
p.errorf("unmatched quote")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
unq, err := unquoteC(p.s[1:i], rune(p.s[0]))
|
|
||||||
if err != nil {
|
|
||||||
p.errorf("invalid quoted string %s: %v", p.s[0:i+1], err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
p.cur.value, p.s = p.s[0:i+1], p.s[i+1:len(p.s)]
|
|
||||||
p.cur.unquoted = unq
|
|
||||||
default:
|
|
||||||
i := 0
|
|
||||||
for i < len(p.s) && isIdentOrNumberChar(p.s[i]) {
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
if i == 0 {
|
|
||||||
p.errorf("unexpected byte %#x", p.s[0])
|
|
||||||
return
|
|
||||||
}
|
|
||||||
p.cur.value, p.s = p.s[0:i], p.s[i:len(p.s)]
|
|
||||||
}
|
|
||||||
p.offset += len(p.cur.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Back off the parser by one token. Can only be done between calls to next().
|
|
||||||
// It makes the next advance() a no-op.
|
|
||||||
func (p *textParser) back() { p.backed = true }
|
|
||||||
|
|
||||||
// Advances the parser and returns the new current token.
|
|
||||||
func (p *textParser) next() *token {
|
|
||||||
if p.backed || p.done {
|
|
||||||
p.backed = false
|
|
||||||
return &p.cur
|
|
||||||
}
|
|
||||||
p.advance()
|
|
||||||
if p.done {
|
|
||||||
p.cur.value = ""
|
|
||||||
} else if len(p.cur.value) > 0 && isQuote(p.cur.value[0]) {
|
|
||||||
// Look for multiple quoted strings separated by whitespace,
|
|
||||||
// and concatenate them.
|
|
||||||
cat := p.cur
|
|
||||||
for {
|
|
||||||
p.skipWhitespace()
|
|
||||||
if p.done || !isQuote(p.s[0]) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
p.advance()
|
|
||||||
if p.cur.err != nil {
|
|
||||||
return &p.cur
|
|
||||||
}
|
|
||||||
cat.value += " " + p.cur.value
|
|
||||||
cat.unquoted += p.cur.unquoted
|
|
||||||
}
|
|
||||||
p.done = false // parser may have seen EOF, but we want to return cat
|
|
||||||
p.cur = cat
|
|
||||||
}
|
|
||||||
return &p.cur
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *textParser) consumeToken(s string) error {
|
|
||||||
tok := p.next()
|
|
||||||
if tok.err != nil {
|
|
||||||
return tok.err
|
|
||||||
}
|
|
||||||
if tok.value != s {
|
|
||||||
p.back()
|
|
||||||
return p.errorf("expected %q, found %q", s, tok.value)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var errBadUTF8 = errors.New("proto: bad UTF-8")
|
|
||||||
|
|
||||||
func unquoteC(s string, quote rune) (string, error) {
|
|
||||||
// This is based on C++'s tokenizer.cc.
|
|
||||||
// Despite its name, this is *not* parsing C syntax.
|
|
||||||
// For instance, "\0" is an invalid quoted string.
|
|
||||||
|
|
||||||
// Avoid allocation in trivial cases.
|
|
||||||
simple := true
|
|
||||||
for _, r := range s {
|
|
||||||
if r == '\\' || r == quote {
|
|
||||||
simple = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if simple {
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := make([]byte, 0, 3*len(s)/2)
|
|
||||||
for len(s) > 0 {
|
|
||||||
r, n := utf8.DecodeRuneInString(s)
|
|
||||||
if r == utf8.RuneError && n == 1 {
|
|
||||||
return "", errBadUTF8
|
|
||||||
}
|
|
||||||
s = s[n:]
|
|
||||||
if r != '\\' {
|
|
||||||
if r < utf8.RuneSelf {
|
|
||||||
buf = append(buf, byte(r))
|
|
||||||
} else {
|
|
||||||
buf = append(buf, string(r)...)
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
ch, tail, err := unescape(s)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
buf = append(buf, ch...)
|
|
||||||
s = tail
|
|
||||||
}
|
|
||||||
return string(buf), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func unescape(s string) (ch string, tail string, err error) {
|
|
||||||
r, n := utf8.DecodeRuneInString(s)
|
|
||||||
if r == utf8.RuneError && n == 1 {
|
|
||||||
return "", "", errBadUTF8
|
|
||||||
}
|
|
||||||
s = s[n:]
|
|
||||||
switch r {
|
|
||||||
case 'a':
|
|
||||||
return "\a", s, nil
|
|
||||||
case 'b':
|
|
||||||
return "\b", s, nil
|
|
||||||
case 'f':
|
|
||||||
return "\f", s, nil
|
|
||||||
case 'n':
|
|
||||||
return "\n", s, nil
|
|
||||||
case 'r':
|
|
||||||
return "\r", s, nil
|
|
||||||
case 't':
|
|
||||||
return "\t", s, nil
|
|
||||||
case 'v':
|
|
||||||
return "\v", s, nil
|
|
||||||
case '?':
|
|
||||||
return "?", s, nil // trigraph workaround
|
|
||||||
case '\'', '"', '\\':
|
|
||||||
return string(r), s, nil
|
|
||||||
case '0', '1', '2', '3', '4', '5', '6', '7':
|
|
||||||
if len(s) < 2 {
|
|
||||||
return "", "", fmt.Errorf(`\%c requires 2 following digits`, r)
|
|
||||||
}
|
|
||||||
ss := string(r) + s[:2]
|
|
||||||
s = s[2:]
|
|
||||||
i, err := strconv.ParseUint(ss, 8, 8)
|
|
||||||
if err != nil {
|
|
||||||
return "", "", fmt.Errorf(`\%s contains non-octal digits`, ss)
|
|
||||||
}
|
|
||||||
return string([]byte{byte(i)}), s, nil
|
|
||||||
case 'x', 'X', 'u', 'U':
|
|
||||||
var n int
|
|
||||||
switch r {
|
|
||||||
case 'x', 'X':
|
|
||||||
n = 2
|
|
||||||
case 'u':
|
|
||||||
n = 4
|
|
||||||
case 'U':
|
|
||||||
n = 8
|
|
||||||
}
|
|
||||||
if len(s) < n {
|
|
||||||
return "", "", fmt.Errorf(`\%c requires %d following digits`, r, n)
|
|
||||||
}
|
|
||||||
ss := s[:n]
|
|
||||||
s = s[n:]
|
|
||||||
i, err := strconv.ParseUint(ss, 16, 64)
|
|
||||||
if err != nil {
|
|
||||||
return "", "", fmt.Errorf(`\%c%s contains non-hexadecimal digits`, r, ss)
|
|
||||||
}
|
|
||||||
if r == 'x' || r == 'X' {
|
|
||||||
return string([]byte{byte(i)}), s, nil
|
|
||||||
}
|
|
||||||
if i > utf8.MaxRune {
|
|
||||||
return "", "", fmt.Errorf(`\%c%s is not a valid Unicode code point`, r, ss)
|
|
||||||
}
|
|
||||||
return string(i), s, nil
|
|
||||||
}
|
|
||||||
return "", "", fmt.Errorf(`unknown escape \%c`, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func isIdentOrNumberChar(c byte) bool {
|
|
||||||
switch {
|
|
||||||
case 'A' <= c && c <= 'Z', 'a' <= c && c <= 'z':
|
|
||||||
return true
|
|
||||||
case '0' <= c && c <= '9':
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
switch c {
|
|
||||||
case '-', '+', '.', '_':
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func isWhitespace(c byte) bool {
|
|
||||||
switch c {
|
|
||||||
case ' ', '\t', '\n', '\r':
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func isQuote(c byte) bool {
|
|
||||||
switch c {
|
|
||||||
case '"', '\'':
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
560
vendor/github.com/golang/protobuf/proto/text_encode.go
generated
vendored
560
vendor/github.com/golang/protobuf/proto/text_encode.go
generated
vendored
|
@ -1,560 +0,0 @@
|
||||||
// Copyright 2010 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package proto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"math"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"google.golang.org/protobuf/encoding/prototext"
|
|
||||||
"google.golang.org/protobuf/encoding/protowire"
|
|
||||||
"google.golang.org/protobuf/proto"
|
|
||||||
"google.golang.org/protobuf/reflect/protoreflect"
|
|
||||||
"google.golang.org/protobuf/reflect/protoregistry"
|
|
||||||
)
|
|
||||||
|
|
||||||
const wrapTextMarshalV2 = false
|
|
||||||
|
|
||||||
// TextMarshaler is a configurable text format marshaler.
|
|
||||||
type TextMarshaler struct {
|
|
||||||
Compact bool // use compact text format (one line)
|
|
||||||
ExpandAny bool // expand google.protobuf.Any messages of known types
|
|
||||||
}
|
|
||||||
|
|
||||||
// Marshal writes the proto text format of m to w.
|
|
||||||
func (tm *TextMarshaler) Marshal(w io.Writer, m Message) error {
|
|
||||||
b, err := tm.marshal(m)
|
|
||||||
if len(b) > 0 {
|
|
||||||
if _, err := w.Write(b); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Text returns a proto text formatted string of m.
|
|
||||||
func (tm *TextMarshaler) Text(m Message) string {
|
|
||||||
b, _ := tm.marshal(m)
|
|
||||||
return string(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tm *TextMarshaler) marshal(m Message) ([]byte, error) {
|
|
||||||
mr := MessageReflect(m)
|
|
||||||
if mr == nil || !mr.IsValid() {
|
|
||||||
return []byte("<nil>"), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if wrapTextMarshalV2 {
|
|
||||||
if m, ok := m.(encoding.TextMarshaler); ok {
|
|
||||||
return m.MarshalText()
|
|
||||||
}
|
|
||||||
|
|
||||||
opts := prototext.MarshalOptions{
|
|
||||||
AllowPartial: true,
|
|
||||||
EmitUnknown: true,
|
|
||||||
}
|
|
||||||
if !tm.Compact {
|
|
||||||
opts.Indent = " "
|
|
||||||
}
|
|
||||||
if !tm.ExpandAny {
|
|
||||||
opts.Resolver = (*protoregistry.Types)(nil)
|
|
||||||
}
|
|
||||||
return opts.Marshal(mr.Interface())
|
|
||||||
} else {
|
|
||||||
w := &textWriter{
|
|
||||||
compact: tm.Compact,
|
|
||||||
expandAny: tm.ExpandAny,
|
|
||||||
complete: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
if m, ok := m.(encoding.TextMarshaler); ok {
|
|
||||||
b, err := m.MarshalText()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
w.Write(b)
|
|
||||||
return w.buf, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
err := w.writeMessage(mr)
|
|
||||||
return w.buf, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
defaultTextMarshaler = TextMarshaler{}
|
|
||||||
compactTextMarshaler = TextMarshaler{Compact: true}
|
|
||||||
)
|
|
||||||
|
|
||||||
// MarshalText writes the proto text format of m to w.
|
|
||||||
func MarshalText(w io.Writer, m Message) error { return defaultTextMarshaler.Marshal(w, m) }
|
|
||||||
|
|
||||||
// MarshalTextString returns a proto text formatted string of m.
|
|
||||||
func MarshalTextString(m Message) string { return defaultTextMarshaler.Text(m) }
|
|
||||||
|
|
||||||
// CompactText writes the compact proto text format of m to w.
|
|
||||||
func CompactText(w io.Writer, m Message) error { return compactTextMarshaler.Marshal(w, m) }
|
|
||||||
|
|
||||||
// CompactTextString returns a compact proto text formatted string of m.
|
|
||||||
func CompactTextString(m Message) string { return compactTextMarshaler.Text(m) }
|
|
||||||
|
|
||||||
var (
|
|
||||||
newline = []byte("\n")
|
|
||||||
endBraceNewline = []byte("}\n")
|
|
||||||
posInf = []byte("inf")
|
|
||||||
negInf = []byte("-inf")
|
|
||||||
nan = []byte("nan")
|
|
||||||
)
|
|
||||||
|
|
||||||
// textWriter is an io.Writer that tracks its indentation level.
|
|
||||||
type textWriter struct {
|
|
||||||
compact bool // same as TextMarshaler.Compact
|
|
||||||
expandAny bool // same as TextMarshaler.ExpandAny
|
|
||||||
complete bool // whether the current position is a complete line
|
|
||||||
indent int // indentation level; never negative
|
|
||||||
buf []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *textWriter) Write(p []byte) (n int, _ error) {
|
|
||||||
newlines := bytes.Count(p, newline)
|
|
||||||
if newlines == 0 {
|
|
||||||
if !w.compact && w.complete {
|
|
||||||
w.writeIndent()
|
|
||||||
}
|
|
||||||
w.buf = append(w.buf, p...)
|
|
||||||
w.complete = false
|
|
||||||
return len(p), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
frags := bytes.SplitN(p, newline, newlines+1)
|
|
||||||
if w.compact {
|
|
||||||
for i, frag := range frags {
|
|
||||||
if i > 0 {
|
|
||||||
w.buf = append(w.buf, ' ')
|
|
||||||
n++
|
|
||||||
}
|
|
||||||
w.buf = append(w.buf, frag...)
|
|
||||||
n += len(frag)
|
|
||||||
}
|
|
||||||
return n, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, frag := range frags {
|
|
||||||
if w.complete {
|
|
||||||
w.writeIndent()
|
|
||||||
}
|
|
||||||
w.buf = append(w.buf, frag...)
|
|
||||||
n += len(frag)
|
|
||||||
if i+1 < len(frags) {
|
|
||||||
w.buf = append(w.buf, '\n')
|
|
||||||
n++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
w.complete = len(frags[len(frags)-1]) == 0
|
|
||||||
return n, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *textWriter) WriteByte(c byte) error {
|
|
||||||
if w.compact && c == '\n' {
|
|
||||||
c = ' '
|
|
||||||
}
|
|
||||||
if !w.compact && w.complete {
|
|
||||||
w.writeIndent()
|
|
||||||
}
|
|
||||||
w.buf = append(w.buf, c)
|
|
||||||
w.complete = c == '\n'
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *textWriter) writeName(fd protoreflect.FieldDescriptor) {
|
|
||||||
if !w.compact && w.complete {
|
|
||||||
w.writeIndent()
|
|
||||||
}
|
|
||||||
w.complete = false
|
|
||||||
|
|
||||||
if fd.Kind() != protoreflect.GroupKind {
|
|
||||||
w.buf = append(w.buf, fd.Name()...)
|
|
||||||
w.WriteByte(':')
|
|
||||||
} else {
|
|
||||||
// Use message type name for group field name.
|
|
||||||
w.buf = append(w.buf, fd.Message().Name()...)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !w.compact {
|
|
||||||
w.WriteByte(' ')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func requiresQuotes(u string) bool {
|
|
||||||
// When type URL contains any characters except [0-9A-Za-z./\-]*, it must be quoted.
|
|
||||||
for _, ch := range u {
|
|
||||||
switch {
|
|
||||||
case ch == '.' || ch == '/' || ch == '_':
|
|
||||||
continue
|
|
||||||
case '0' <= ch && ch <= '9':
|
|
||||||
continue
|
|
||||||
case 'A' <= ch && ch <= 'Z':
|
|
||||||
continue
|
|
||||||
case 'a' <= ch && ch <= 'z':
|
|
||||||
continue
|
|
||||||
default:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// writeProto3Any writes an expanded google.protobuf.Any message.
|
|
||||||
//
|
|
||||||
// It returns (false, nil) if sv value can't be unmarshaled (e.g. because
|
|
||||||
// required messages are not linked in).
|
|
||||||
//
|
|
||||||
// It returns (true, error) when sv was written in expanded format or an error
|
|
||||||
// was encountered.
|
|
||||||
func (w *textWriter) writeProto3Any(m protoreflect.Message) (bool, error) {
|
|
||||||
md := m.Descriptor()
|
|
||||||
fdURL := md.Fields().ByName("type_url")
|
|
||||||
fdVal := md.Fields().ByName("value")
|
|
||||||
|
|
||||||
url := m.Get(fdURL).String()
|
|
||||||
mt, err := protoregistry.GlobalTypes.FindMessageByURL(url)
|
|
||||||
if err != nil {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
b := m.Get(fdVal).Bytes()
|
|
||||||
m2 := mt.New()
|
|
||||||
if err := proto.Unmarshal(b, m2.Interface()); err != nil {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
w.Write([]byte("["))
|
|
||||||
if requiresQuotes(url) {
|
|
||||||
w.writeQuotedString(url)
|
|
||||||
} else {
|
|
||||||
w.Write([]byte(url))
|
|
||||||
}
|
|
||||||
if w.compact {
|
|
||||||
w.Write([]byte("]:<"))
|
|
||||||
} else {
|
|
||||||
w.Write([]byte("]: <\n"))
|
|
||||||
w.indent++
|
|
||||||
}
|
|
||||||
if err := w.writeMessage(m2); err != nil {
|
|
||||||
return true, err
|
|
||||||
}
|
|
||||||
if w.compact {
|
|
||||||
w.Write([]byte("> "))
|
|
||||||
} else {
|
|
||||||
w.indent--
|
|
||||||
w.Write([]byte(">\n"))
|
|
||||||
}
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *textWriter) writeMessage(m protoreflect.Message) error {
|
|
||||||
md := m.Descriptor()
|
|
||||||
if w.expandAny && md.FullName() == "google.protobuf.Any" {
|
|
||||||
if canExpand, err := w.writeProto3Any(m); canExpand {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fds := md.Fields()
|
|
||||||
for i := 0; i < fds.Len(); {
|
|
||||||
fd := fds.Get(i)
|
|
||||||
if od := fd.ContainingOneof(); od != nil {
|
|
||||||
fd = m.WhichOneof(od)
|
|
||||||
i += od.Fields().Len()
|
|
||||||
} else {
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
if fd == nil || !m.Has(fd) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case fd.IsList():
|
|
||||||
lv := m.Get(fd).List()
|
|
||||||
for j := 0; j < lv.Len(); j++ {
|
|
||||||
w.writeName(fd)
|
|
||||||
v := lv.Get(j)
|
|
||||||
if err := w.writeSingularValue(v, fd); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
w.WriteByte('\n')
|
|
||||||
}
|
|
||||||
case fd.IsMap():
|
|
||||||
kfd := fd.MapKey()
|
|
||||||
vfd := fd.MapValue()
|
|
||||||
mv := m.Get(fd).Map()
|
|
||||||
|
|
||||||
type entry struct{ key, val protoreflect.Value }
|
|
||||||
var entries []entry
|
|
||||||
mv.Range(func(k protoreflect.MapKey, v protoreflect.Value) bool {
|
|
||||||
entries = append(entries, entry{k.Value(), v})
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
sort.Slice(entries, func(i, j int) bool {
|
|
||||||
switch kfd.Kind() {
|
|
||||||
case protoreflect.BoolKind:
|
|
||||||
return !entries[i].key.Bool() && entries[j].key.Bool()
|
|
||||||
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind, protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
|
|
||||||
return entries[i].key.Int() < entries[j].key.Int()
|
|
||||||
case protoreflect.Uint32Kind, protoreflect.Fixed32Kind, protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
|
|
||||||
return entries[i].key.Uint() < entries[j].key.Uint()
|
|
||||||
case protoreflect.StringKind:
|
|
||||||
return entries[i].key.String() < entries[j].key.String()
|
|
||||||
default:
|
|
||||||
panic("invalid kind")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
for _, entry := range entries {
|
|
||||||
w.writeName(fd)
|
|
||||||
w.WriteByte('<')
|
|
||||||
if !w.compact {
|
|
||||||
w.WriteByte('\n')
|
|
||||||
}
|
|
||||||
w.indent++
|
|
||||||
w.writeName(kfd)
|
|
||||||
if err := w.writeSingularValue(entry.key, kfd); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
w.WriteByte('\n')
|
|
||||||
w.writeName(vfd)
|
|
||||||
if err := w.writeSingularValue(entry.val, vfd); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
w.WriteByte('\n')
|
|
||||||
w.indent--
|
|
||||||
w.WriteByte('>')
|
|
||||||
w.WriteByte('\n')
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
w.writeName(fd)
|
|
||||||
if err := w.writeSingularValue(m.Get(fd), fd); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
w.WriteByte('\n')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if b := m.GetUnknown(); len(b) > 0 {
|
|
||||||
w.writeUnknownFields(b)
|
|
||||||
}
|
|
||||||
return w.writeExtensions(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *textWriter) writeSingularValue(v protoreflect.Value, fd protoreflect.FieldDescriptor) error {
|
|
||||||
switch fd.Kind() {
|
|
||||||
case protoreflect.FloatKind, protoreflect.DoubleKind:
|
|
||||||
switch vf := v.Float(); {
|
|
||||||
case math.IsInf(vf, +1):
|
|
||||||
w.Write(posInf)
|
|
||||||
case math.IsInf(vf, -1):
|
|
||||||
w.Write(negInf)
|
|
||||||
case math.IsNaN(vf):
|
|
||||||
w.Write(nan)
|
|
||||||
default:
|
|
||||||
fmt.Fprint(w, v.Interface())
|
|
||||||
}
|
|
||||||
case protoreflect.StringKind:
|
|
||||||
// NOTE: This does not validate UTF-8 for historical reasons.
|
|
||||||
w.writeQuotedString(string(v.String()))
|
|
||||||
case protoreflect.BytesKind:
|
|
||||||
w.writeQuotedString(string(v.Bytes()))
|
|
||||||
case protoreflect.MessageKind, protoreflect.GroupKind:
|
|
||||||
var bra, ket byte = '<', '>'
|
|
||||||
if fd.Kind() == protoreflect.GroupKind {
|
|
||||||
bra, ket = '{', '}'
|
|
||||||
}
|
|
||||||
w.WriteByte(bra)
|
|
||||||
if !w.compact {
|
|
||||||
w.WriteByte('\n')
|
|
||||||
}
|
|
||||||
w.indent++
|
|
||||||
m := v.Message()
|
|
||||||
if m2, ok := m.Interface().(encoding.TextMarshaler); ok {
|
|
||||||
b, err := m2.MarshalText()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
w.Write(b)
|
|
||||||
} else {
|
|
||||||
w.writeMessage(m)
|
|
||||||
}
|
|
||||||
w.indent--
|
|
||||||
w.WriteByte(ket)
|
|
||||||
case protoreflect.EnumKind:
|
|
||||||
if ev := fd.Enum().Values().ByNumber(v.Enum()); ev != nil {
|
|
||||||
fmt.Fprint(w, ev.Name())
|
|
||||||
} else {
|
|
||||||
fmt.Fprint(w, v.Enum())
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
fmt.Fprint(w, v.Interface())
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// writeQuotedString writes a quoted string in the protocol buffer text format.
|
|
||||||
func (w *textWriter) writeQuotedString(s string) {
|
|
||||||
w.WriteByte('"')
|
|
||||||
for i := 0; i < len(s); i++ {
|
|
||||||
switch c := s[i]; c {
|
|
||||||
case '\n':
|
|
||||||
w.buf = append(w.buf, `\n`...)
|
|
||||||
case '\r':
|
|
||||||
w.buf = append(w.buf, `\r`...)
|
|
||||||
case '\t':
|
|
||||||
w.buf = append(w.buf, `\t`...)
|
|
||||||
case '"':
|
|
||||||
w.buf = append(w.buf, `\"`...)
|
|
||||||
case '\\':
|
|
||||||
w.buf = append(w.buf, `\\`...)
|
|
||||||
default:
|
|
||||||
if isPrint := c >= 0x20 && c < 0x7f; isPrint {
|
|
||||||
w.buf = append(w.buf, c)
|
|
||||||
} else {
|
|
||||||
w.buf = append(w.buf, fmt.Sprintf(`\%03o`, c)...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
w.WriteByte('"')
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *textWriter) writeUnknownFields(b []byte) {
|
|
||||||
if !w.compact {
|
|
||||||
fmt.Fprintf(w, "/* %d unknown bytes */\n", len(b))
|
|
||||||
}
|
|
||||||
|
|
||||||
for len(b) > 0 {
|
|
||||||
num, wtyp, n := protowire.ConsumeTag(b)
|
|
||||||
if n < 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
b = b[n:]
|
|
||||||
|
|
||||||
if wtyp == protowire.EndGroupType {
|
|
||||||
w.indent--
|
|
||||||
w.Write(endBraceNewline)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fmt.Fprint(w, num)
|
|
||||||
if wtyp != protowire.StartGroupType {
|
|
||||||
w.WriteByte(':')
|
|
||||||
}
|
|
||||||
if !w.compact || wtyp == protowire.StartGroupType {
|
|
||||||
w.WriteByte(' ')
|
|
||||||
}
|
|
||||||
switch wtyp {
|
|
||||||
case protowire.VarintType:
|
|
||||||
v, n := protowire.ConsumeVarint(b)
|
|
||||||
if n < 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
b = b[n:]
|
|
||||||
fmt.Fprint(w, v)
|
|
||||||
case protowire.Fixed32Type:
|
|
||||||
v, n := protowire.ConsumeFixed32(b)
|
|
||||||
if n < 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
b = b[n:]
|
|
||||||
fmt.Fprint(w, v)
|
|
||||||
case protowire.Fixed64Type:
|
|
||||||
v, n := protowire.ConsumeFixed64(b)
|
|
||||||
if n < 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
b = b[n:]
|
|
||||||
fmt.Fprint(w, v)
|
|
||||||
case protowire.BytesType:
|
|
||||||
v, n := protowire.ConsumeBytes(b)
|
|
||||||
if n < 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
b = b[n:]
|
|
||||||
fmt.Fprintf(w, "%q", v)
|
|
||||||
case protowire.StartGroupType:
|
|
||||||
w.WriteByte('{')
|
|
||||||
w.indent++
|
|
||||||
default:
|
|
||||||
fmt.Fprintf(w, "/* unknown wire type %d */", wtyp)
|
|
||||||
}
|
|
||||||
w.WriteByte('\n')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// writeExtensions writes all the extensions in m.
|
|
||||||
func (w *textWriter) writeExtensions(m protoreflect.Message) error {
|
|
||||||
md := m.Descriptor()
|
|
||||||
if md.ExtensionRanges().Len() == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type ext struct {
|
|
||||||
desc protoreflect.FieldDescriptor
|
|
||||||
val protoreflect.Value
|
|
||||||
}
|
|
||||||
var exts []ext
|
|
||||||
m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
|
|
||||||
if fd.IsExtension() {
|
|
||||||
exts = append(exts, ext{fd, v})
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
sort.Slice(exts, func(i, j int) bool {
|
|
||||||
return exts[i].desc.Number() < exts[j].desc.Number()
|
|
||||||
})
|
|
||||||
|
|
||||||
for _, ext := range exts {
|
|
||||||
// For message set, use the name of the message as the extension name.
|
|
||||||
name := string(ext.desc.FullName())
|
|
||||||
if isMessageSet(ext.desc.ContainingMessage()) {
|
|
||||||
name = strings.TrimSuffix(name, ".message_set_extension")
|
|
||||||
}
|
|
||||||
|
|
||||||
if !ext.desc.IsList() {
|
|
||||||
if err := w.writeSingularExtension(name, ext.val, ext.desc); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
lv := ext.val.List()
|
|
||||||
for i := 0; i < lv.Len(); i++ {
|
|
||||||
if err := w.writeSingularExtension(name, lv.Get(i), ext.desc); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *textWriter) writeSingularExtension(name string, v protoreflect.Value, fd protoreflect.FieldDescriptor) error {
|
|
||||||
fmt.Fprintf(w, "[%s]:", name)
|
|
||||||
if !w.compact {
|
|
||||||
w.WriteByte(' ')
|
|
||||||
}
|
|
||||||
if err := w.writeSingularValue(v, fd); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
w.WriteByte('\n')
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *textWriter) writeIndent() {
|
|
||||||
if !w.complete {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for i := 0; i < w.indent*2; i++ {
|
|
||||||
w.buf = append(w.buf, ' ')
|
|
||||||
}
|
|
||||||
w.complete = false
|
|
||||||
}
|
|
78
vendor/github.com/golang/protobuf/proto/wire.go
generated
vendored
78
vendor/github.com/golang/protobuf/proto/wire.go
generated
vendored
|
@ -1,78 +0,0 @@
|
||||||
// Copyright 2019 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package proto
|
|
||||||
|
|
||||||
import (
|
|
||||||
protoV2 "google.golang.org/protobuf/proto"
|
|
||||||
"google.golang.org/protobuf/runtime/protoiface"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Size returns the size in bytes of the wire-format encoding of m.
|
|
||||||
func Size(m Message) int {
|
|
||||||
if m == nil {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
mi := MessageV2(m)
|
|
||||||
return protoV2.Size(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Marshal returns the wire-format encoding of m.
|
|
||||||
func Marshal(m Message) ([]byte, error) {
|
|
||||||
b, err := marshalAppend(nil, m, false)
|
|
||||||
if b == nil {
|
|
||||||
b = zeroBytes
|
|
||||||
}
|
|
||||||
return b, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var zeroBytes = make([]byte, 0, 0)
|
|
||||||
|
|
||||||
func marshalAppend(buf []byte, m Message, deterministic bool) ([]byte, error) {
|
|
||||||
if m == nil {
|
|
||||||
return nil, ErrNil
|
|
||||||
}
|
|
||||||
mi := MessageV2(m)
|
|
||||||
nbuf, err := protoV2.MarshalOptions{
|
|
||||||
Deterministic: deterministic,
|
|
||||||
AllowPartial: true,
|
|
||||||
}.MarshalAppend(buf, mi)
|
|
||||||
if err != nil {
|
|
||||||
return buf, err
|
|
||||||
}
|
|
||||||
if len(buf) == len(nbuf) {
|
|
||||||
if !mi.ProtoReflect().IsValid() {
|
|
||||||
return buf, ErrNil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nbuf, checkRequiredNotSet(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unmarshal parses a wire-format message in b and places the decoded results in m.
|
|
||||||
//
|
|
||||||
// Unmarshal resets m before starting to unmarshal, so any existing data in m is always
|
|
||||||
// removed. Use UnmarshalMerge to preserve and append to existing data.
|
|
||||||
func Unmarshal(b []byte, m Message) error {
|
|
||||||
m.Reset()
|
|
||||||
return UnmarshalMerge(b, m)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalMerge parses a wire-format message in b and places the decoded results in m.
|
|
||||||
func UnmarshalMerge(b []byte, m Message) error {
|
|
||||||
mi := MessageV2(m)
|
|
||||||
out, err := protoV2.UnmarshalOptions{
|
|
||||||
AllowPartial: true,
|
|
||||||
Merge: true,
|
|
||||||
}.UnmarshalState(protoiface.UnmarshalInput{
|
|
||||||
Buf: b,
|
|
||||||
Message: mi.ProtoReflect(),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if out.Flags&protoiface.UnmarshalInitialized > 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return checkRequiredNotSet(mi)
|
|
||||||
}
|
|
34
vendor/github.com/golang/protobuf/proto/wrappers.go
generated
vendored
34
vendor/github.com/golang/protobuf/proto/wrappers.go
generated
vendored
|
@ -1,34 +0,0 @@
|
||||||
// Copyright 2019 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package proto
|
|
||||||
|
|
||||||
// Bool stores v in a new bool value and returns a pointer to it.
|
|
||||||
func Bool(v bool) *bool { return &v }
|
|
||||||
|
|
||||||
// Int stores v in a new int32 value and returns a pointer to it.
|
|
||||||
//
|
|
||||||
// Deprecated: Use Int32 instead.
|
|
||||||
func Int(v int) *int32 { return Int32(int32(v)) }
|
|
||||||
|
|
||||||
// Int32 stores v in a new int32 value and returns a pointer to it.
|
|
||||||
func Int32(v int32) *int32 { return &v }
|
|
||||||
|
|
||||||
// Int64 stores v in a new int64 value and returns a pointer to it.
|
|
||||||
func Int64(v int64) *int64 { return &v }
|
|
||||||
|
|
||||||
// Uint32 stores v in a new uint32 value and returns a pointer to it.
|
|
||||||
func Uint32(v uint32) *uint32 { return &v }
|
|
||||||
|
|
||||||
// Uint64 stores v in a new uint64 value and returns a pointer to it.
|
|
||||||
func Uint64(v uint64) *uint64 { return &v }
|
|
||||||
|
|
||||||
// Float32 stores v in a new float32 value and returns a pointer to it.
|
|
||||||
func Float32(v float32) *float32 { return &v }
|
|
||||||
|
|
||||||
// Float64 stores v in a new float64 value and returns a pointer to it.
|
|
||||||
func Float64(v float64) *float64 { return &v }
|
|
||||||
|
|
||||||
// String stores v in a new string value and returns a pointer to it.
|
|
||||||
func String(v string) *string { return &v }
|
|
165
vendor/github.com/golang/protobuf/ptypes/any.go
generated
vendored
165
vendor/github.com/golang/protobuf/ptypes/any.go
generated
vendored
|
@ -1,165 +0,0 @@
|
||||||
// Copyright 2016 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package ptypes
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/golang/protobuf/proto"
|
|
||||||
"google.golang.org/protobuf/reflect/protoreflect"
|
|
||||||
"google.golang.org/protobuf/reflect/protoregistry"
|
|
||||||
|
|
||||||
anypb "github.com/golang/protobuf/ptypes/any"
|
|
||||||
)
|
|
||||||
|
|
||||||
const urlPrefix = "type.googleapis.com/"
|
|
||||||
|
|
||||||
// AnyMessageName returns the message name contained in an anypb.Any message.
|
|
||||||
// Most type assertions should use the Is function instead.
|
|
||||||
func AnyMessageName(any *anypb.Any) (string, error) {
|
|
||||||
name, err := anyMessageName(any)
|
|
||||||
return string(name), err
|
|
||||||
}
|
|
||||||
func anyMessageName(any *anypb.Any) (protoreflect.FullName, error) {
|
|
||||||
if any == nil {
|
|
||||||
return "", fmt.Errorf("message is nil")
|
|
||||||
}
|
|
||||||
name := protoreflect.FullName(any.TypeUrl)
|
|
||||||
if i := strings.LastIndex(any.TypeUrl, "/"); i >= 0 {
|
|
||||||
name = name[i+len("/"):]
|
|
||||||
}
|
|
||||||
if !name.IsValid() {
|
|
||||||
return "", fmt.Errorf("message type url %q is invalid", any.TypeUrl)
|
|
||||||
}
|
|
||||||
return name, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarshalAny marshals the given message m into an anypb.Any message.
|
|
||||||
func MarshalAny(m proto.Message) (*anypb.Any, error) {
|
|
||||||
switch dm := m.(type) {
|
|
||||||
case DynamicAny:
|
|
||||||
m = dm.Message
|
|
||||||
case *DynamicAny:
|
|
||||||
if dm == nil {
|
|
||||||
return nil, proto.ErrNil
|
|
||||||
}
|
|
||||||
m = dm.Message
|
|
||||||
}
|
|
||||||
b, err := proto.Marshal(m)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &anypb.Any{TypeUrl: urlPrefix + proto.MessageName(m), Value: b}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Empty returns a new message of the type specified in an anypb.Any message.
|
|
||||||
// It returns protoregistry.NotFound if the corresponding message type could not
|
|
||||||
// be resolved in the global registry.
|
|
||||||
func Empty(any *anypb.Any) (proto.Message, error) {
|
|
||||||
name, err := anyMessageName(any)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
mt, err := protoregistry.GlobalTypes.FindMessageByName(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return proto.MessageV1(mt.New().Interface()), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalAny unmarshals the encoded value contained in the anypb.Any message
|
|
||||||
// into the provided message m. It returns an error if the target message
|
|
||||||
// does not match the type in the Any message or if an unmarshal error occurs.
|
|
||||||
//
|
|
||||||
// The target message m may be a *DynamicAny message. If the underlying message
|
|
||||||
// type could not be resolved, then this returns protoregistry.NotFound.
|
|
||||||
func UnmarshalAny(any *anypb.Any, m proto.Message) error {
|
|
||||||
if dm, ok := m.(*DynamicAny); ok {
|
|
||||||
if dm.Message == nil {
|
|
||||||
var err error
|
|
||||||
dm.Message, err = Empty(any)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m = dm.Message
|
|
||||||
}
|
|
||||||
|
|
||||||
anyName, err := AnyMessageName(any)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
msgName := proto.MessageName(m)
|
|
||||||
if anyName != msgName {
|
|
||||||
return fmt.Errorf("mismatched message type: got %q want %q", anyName, msgName)
|
|
||||||
}
|
|
||||||
return proto.Unmarshal(any.Value, m)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is reports whether the Any message contains a message of the specified type.
|
|
||||||
func Is(any *anypb.Any, m proto.Message) bool {
|
|
||||||
if any == nil || m == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
name := proto.MessageName(m)
|
|
||||||
if !strings.HasSuffix(any.TypeUrl, name) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return len(any.TypeUrl) == len(name) || any.TypeUrl[len(any.TypeUrl)-len(name)-1] == '/'
|
|
||||||
}
|
|
||||||
|
|
||||||
// DynamicAny is a value that can be passed to UnmarshalAny to automatically
|
|
||||||
// allocate a proto.Message for the type specified in an anypb.Any message.
|
|
||||||
// The allocated message is stored in the embedded proto.Message.
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
// var x ptypes.DynamicAny
|
|
||||||
// if err := ptypes.UnmarshalAny(a, &x); err != nil { ... }
|
|
||||||
// fmt.Printf("unmarshaled message: %v", x.Message)
|
|
||||||
type DynamicAny struct{ proto.Message }
|
|
||||||
|
|
||||||
func (m DynamicAny) String() string {
|
|
||||||
if m.Message == nil {
|
|
||||||
return "<nil>"
|
|
||||||
}
|
|
||||||
return m.Message.String()
|
|
||||||
}
|
|
||||||
func (m DynamicAny) Reset() {
|
|
||||||
if m.Message == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
m.Message.Reset()
|
|
||||||
}
|
|
||||||
func (m DynamicAny) ProtoMessage() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
func (m DynamicAny) ProtoReflect() protoreflect.Message {
|
|
||||||
if m.Message == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return dynamicAny{proto.MessageReflect(m.Message)}
|
|
||||||
}
|
|
||||||
|
|
||||||
type dynamicAny struct{ protoreflect.Message }
|
|
||||||
|
|
||||||
func (m dynamicAny) Type() protoreflect.MessageType {
|
|
||||||
return dynamicAnyType{m.Message.Type()}
|
|
||||||
}
|
|
||||||
func (m dynamicAny) New() protoreflect.Message {
|
|
||||||
return dynamicAnyType{m.Message.Type()}.New()
|
|
||||||
}
|
|
||||||
func (m dynamicAny) Interface() protoreflect.ProtoMessage {
|
|
||||||
return DynamicAny{proto.MessageV1(m.Message.Interface())}
|
|
||||||
}
|
|
||||||
|
|
||||||
type dynamicAnyType struct{ protoreflect.MessageType }
|
|
||||||
|
|
||||||
func (t dynamicAnyType) New() protoreflect.Message {
|
|
||||||
return dynamicAny{t.MessageType.New()}
|
|
||||||
}
|
|
||||||
func (t dynamicAnyType) Zero() protoreflect.Message {
|
|
||||||
return dynamicAny{t.MessageType.Zero()}
|
|
||||||
}
|
|
62
vendor/github.com/golang/protobuf/ptypes/any/any.pb.go
generated
vendored
62
vendor/github.com/golang/protobuf/ptypes/any/any.pb.go
generated
vendored
|
@ -1,62 +0,0 @@
|
||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
|
||||||
// source: github.com/golang/protobuf/ptypes/any/any.proto
|
|
||||||
|
|
||||||
package any
|
|
||||||
|
|
||||||
import (
|
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
|
||||||
anypb "google.golang.org/protobuf/types/known/anypb"
|
|
||||||
reflect "reflect"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Symbols defined in public import of google/protobuf/any.proto.
|
|
||||||
|
|
||||||
type Any = anypb.Any
|
|
||||||
|
|
||||||
var File_github_com_golang_protobuf_ptypes_any_any_proto protoreflect.FileDescriptor
|
|
||||||
|
|
||||||
var file_github_com_golang_protobuf_ptypes_any_any_proto_rawDesc = []byte{
|
|
||||||
0x0a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c,
|
|
||||||
0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79,
|
|
||||||
0x70, 0x65, 0x73, 0x2f, 0x61, 0x6e, 0x79, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
|
||||||
0x6f, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
|
||||||
0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x42, 0x2b, 0x5a, 0x29,
|
|
||||||
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e,
|
|
||||||
0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79, 0x70, 0x65,
|
|
||||||
0x73, 0x2f, 0x61, 0x6e, 0x79, 0x3b, 0x61, 0x6e, 0x79, 0x50, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f,
|
|
||||||
0x74, 0x6f, 0x33,
|
|
||||||
}
|
|
||||||
|
|
||||||
var file_github_com_golang_protobuf_ptypes_any_any_proto_goTypes = []interface{}{}
|
|
||||||
var file_github_com_golang_protobuf_ptypes_any_any_proto_depIdxs = []int32{
|
|
||||||
0, // [0:0] is the sub-list for method output_type
|
|
||||||
0, // [0:0] is the sub-list for method input_type
|
|
||||||
0, // [0:0] is the sub-list for extension type_name
|
|
||||||
0, // [0:0] is the sub-list for extension extendee
|
|
||||||
0, // [0:0] is the sub-list for field type_name
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() { file_github_com_golang_protobuf_ptypes_any_any_proto_init() }
|
|
||||||
func file_github_com_golang_protobuf_ptypes_any_any_proto_init() {
|
|
||||||
if File_github_com_golang_protobuf_ptypes_any_any_proto != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
type x struct{}
|
|
||||||
out := protoimpl.TypeBuilder{
|
|
||||||
File: protoimpl.DescBuilder{
|
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
|
||||||
RawDescriptor: file_github_com_golang_protobuf_ptypes_any_any_proto_rawDesc,
|
|
||||||
NumEnums: 0,
|
|
||||||
NumMessages: 0,
|
|
||||||
NumExtensions: 0,
|
|
||||||
NumServices: 0,
|
|
||||||
},
|
|
||||||
GoTypes: file_github_com_golang_protobuf_ptypes_any_any_proto_goTypes,
|
|
||||||
DependencyIndexes: file_github_com_golang_protobuf_ptypes_any_any_proto_depIdxs,
|
|
||||||
}.Build()
|
|
||||||
File_github_com_golang_protobuf_ptypes_any_any_proto = out.File
|
|
||||||
file_github_com_golang_protobuf_ptypes_any_any_proto_rawDesc = nil
|
|
||||||
file_github_com_golang_protobuf_ptypes_any_any_proto_goTypes = nil
|
|
||||||
file_github_com_golang_protobuf_ptypes_any_any_proto_depIdxs = nil
|
|
||||||
}
|
|
6
vendor/github.com/golang/protobuf/ptypes/doc.go
generated
vendored
6
vendor/github.com/golang/protobuf/ptypes/doc.go
generated
vendored
|
@ -1,6 +0,0 @@
|
||||||
// Copyright 2016 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// Package ptypes provides functionality for interacting with well-known types.
|
|
||||||
package ptypes
|
|
72
vendor/github.com/golang/protobuf/ptypes/duration.go
generated
vendored
72
vendor/github.com/golang/protobuf/ptypes/duration.go
generated
vendored
|
@ -1,72 +0,0 @@
|
||||||
// Copyright 2016 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package ptypes
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
durationpb "github.com/golang/protobuf/ptypes/duration"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Range of google.protobuf.Duration as specified in duration.proto.
|
|
||||||
// This is about 10,000 years in seconds.
|
|
||||||
const (
|
|
||||||
maxSeconds = int64(10000 * 365.25 * 24 * 60 * 60)
|
|
||||||
minSeconds = -maxSeconds
|
|
||||||
)
|
|
||||||
|
|
||||||
// Duration converts a durationpb.Duration to a time.Duration.
|
|
||||||
// Duration returns an error if dur is invalid or overflows a time.Duration.
|
|
||||||
func Duration(dur *durationpb.Duration) (time.Duration, error) {
|
|
||||||
if err := validateDuration(dur); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
d := time.Duration(dur.Seconds) * time.Second
|
|
||||||
if int64(d/time.Second) != dur.Seconds {
|
|
||||||
return 0, fmt.Errorf("duration: %v is out of range for time.Duration", dur)
|
|
||||||
}
|
|
||||||
if dur.Nanos != 0 {
|
|
||||||
d += time.Duration(dur.Nanos) * time.Nanosecond
|
|
||||||
if (d < 0) != (dur.Nanos < 0) {
|
|
||||||
return 0, fmt.Errorf("duration: %v is out of range for time.Duration", dur)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return d, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DurationProto converts a time.Duration to a durationpb.Duration.
|
|
||||||
func DurationProto(d time.Duration) *durationpb.Duration {
|
|
||||||
nanos := d.Nanoseconds()
|
|
||||||
secs := nanos / 1e9
|
|
||||||
nanos -= secs * 1e9
|
|
||||||
return &durationpb.Duration{
|
|
||||||
Seconds: int64(secs),
|
|
||||||
Nanos: int32(nanos),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// validateDuration determines whether the durationpb.Duration is valid
|
|
||||||
// according to the definition in google/protobuf/duration.proto.
|
|
||||||
// A valid durpb.Duration may still be too large to fit into a time.Duration
|
|
||||||
// Note that the range of durationpb.Duration is about 10,000 years,
|
|
||||||
// while the range of time.Duration is about 290 years.
|
|
||||||
func validateDuration(dur *durationpb.Duration) error {
|
|
||||||
if dur == nil {
|
|
||||||
return errors.New("duration: nil Duration")
|
|
||||||
}
|
|
||||||
if dur.Seconds < minSeconds || dur.Seconds > maxSeconds {
|
|
||||||
return fmt.Errorf("duration: %v: seconds out of range", dur)
|
|
||||||
}
|
|
||||||
if dur.Nanos <= -1e9 || dur.Nanos >= 1e9 {
|
|
||||||
return fmt.Errorf("duration: %v: nanos out of range", dur)
|
|
||||||
}
|
|
||||||
// Seconds and Nanos must have the same sign, unless d.Nanos is zero.
|
|
||||||
if (dur.Seconds < 0 && dur.Nanos > 0) || (dur.Seconds > 0 && dur.Nanos < 0) {
|
|
||||||
return fmt.Errorf("duration: %v: seconds and nanos have different signs", dur)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
63
vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go
generated
vendored
63
vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go
generated
vendored
|
@ -1,63 +0,0 @@
|
||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
|
||||||
// source: github.com/golang/protobuf/ptypes/duration/duration.proto
|
|
||||||
|
|
||||||
package duration
|
|
||||||
|
|
||||||
import (
|
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
|
||||||
durationpb "google.golang.org/protobuf/types/known/durationpb"
|
|
||||||
reflect "reflect"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Symbols defined in public import of google/protobuf/duration.proto.
|
|
||||||
|
|
||||||
type Duration = durationpb.Duration
|
|
||||||
|
|
||||||
var File_github_com_golang_protobuf_ptypes_duration_duration_proto protoreflect.FileDescriptor
|
|
||||||
|
|
||||||
var file_github_com_golang_protobuf_ptypes_duration_duration_proto_rawDesc = []byte{
|
|
||||||
0x0a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c,
|
|
||||||
0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79,
|
|
||||||
0x70, 0x65, 0x73, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x64, 0x75, 0x72,
|
|
||||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f,
|
|
||||||
0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72,
|
|
||||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x42, 0x35, 0x5a, 0x33, 0x67,
|
|
||||||
0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67,
|
|
||||||
0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79, 0x70, 0x65, 0x73,
|
|
||||||
0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3b, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69,
|
|
||||||
0x6f, 0x6e, 0x50, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
}
|
|
||||||
|
|
||||||
var file_github_com_golang_protobuf_ptypes_duration_duration_proto_goTypes = []interface{}{}
|
|
||||||
var file_github_com_golang_protobuf_ptypes_duration_duration_proto_depIdxs = []int32{
|
|
||||||
0, // [0:0] is the sub-list for method output_type
|
|
||||||
0, // [0:0] is the sub-list for method input_type
|
|
||||||
0, // [0:0] is the sub-list for extension type_name
|
|
||||||
0, // [0:0] is the sub-list for extension extendee
|
|
||||||
0, // [0:0] is the sub-list for field type_name
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() { file_github_com_golang_protobuf_ptypes_duration_duration_proto_init() }
|
|
||||||
func file_github_com_golang_protobuf_ptypes_duration_duration_proto_init() {
|
|
||||||
if File_github_com_golang_protobuf_ptypes_duration_duration_proto != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
type x struct{}
|
|
||||||
out := protoimpl.TypeBuilder{
|
|
||||||
File: protoimpl.DescBuilder{
|
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
|
||||||
RawDescriptor: file_github_com_golang_protobuf_ptypes_duration_duration_proto_rawDesc,
|
|
||||||
NumEnums: 0,
|
|
||||||
NumMessages: 0,
|
|
||||||
NumExtensions: 0,
|
|
||||||
NumServices: 0,
|
|
||||||
},
|
|
||||||
GoTypes: file_github_com_golang_protobuf_ptypes_duration_duration_proto_goTypes,
|
|
||||||
DependencyIndexes: file_github_com_golang_protobuf_ptypes_duration_duration_proto_depIdxs,
|
|
||||||
}.Build()
|
|
||||||
File_github_com_golang_protobuf_ptypes_duration_duration_proto = out.File
|
|
||||||
file_github_com_golang_protobuf_ptypes_duration_duration_proto_rawDesc = nil
|
|
||||||
file_github_com_golang_protobuf_ptypes_duration_duration_proto_goTypes = nil
|
|
||||||
file_github_com_golang_protobuf_ptypes_duration_duration_proto_depIdxs = nil
|
|
||||||
}
|
|
103
vendor/github.com/golang/protobuf/ptypes/timestamp.go
generated
vendored
103
vendor/github.com/golang/protobuf/ptypes/timestamp.go
generated
vendored
|
@ -1,103 +0,0 @@
|
||||||
// Copyright 2016 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package ptypes
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
timestamppb "github.com/golang/protobuf/ptypes/timestamp"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Range of google.protobuf.Duration as specified in timestamp.proto.
|
|
||||||
const (
|
|
||||||
// Seconds field of the earliest valid Timestamp.
|
|
||||||
// This is time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC).Unix().
|
|
||||||
minValidSeconds = -62135596800
|
|
||||||
// Seconds field just after the latest valid Timestamp.
|
|
||||||
// This is time.Date(10000, 1, 1, 0, 0, 0, 0, time.UTC).Unix().
|
|
||||||
maxValidSeconds = 253402300800
|
|
||||||
)
|
|
||||||
|
|
||||||
// Timestamp converts a timestamppb.Timestamp to a time.Time.
|
|
||||||
// It returns an error if the argument is invalid.
|
|
||||||
//
|
|
||||||
// Unlike most Go functions, if Timestamp returns an error, the first return
|
|
||||||
// value is not the zero time.Time. Instead, it is the value obtained from the
|
|
||||||
// time.Unix function when passed the contents of the Timestamp, in the UTC
|
|
||||||
// locale. This may or may not be a meaningful time; many invalid Timestamps
|
|
||||||
// do map to valid time.Times.
|
|
||||||
//
|
|
||||||
// A nil Timestamp returns an error. The first return value in that case is
|
|
||||||
// undefined.
|
|
||||||
func Timestamp(ts *timestamppb.Timestamp) (time.Time, error) {
|
|
||||||
// Don't return the zero value on error, because corresponds to a valid
|
|
||||||
// timestamp. Instead return whatever time.Unix gives us.
|
|
||||||
var t time.Time
|
|
||||||
if ts == nil {
|
|
||||||
t = time.Unix(0, 0).UTC() // treat nil like the empty Timestamp
|
|
||||||
} else {
|
|
||||||
t = time.Unix(ts.Seconds, int64(ts.Nanos)).UTC()
|
|
||||||
}
|
|
||||||
return t, validateTimestamp(ts)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TimestampNow returns a google.protobuf.Timestamp for the current time.
|
|
||||||
func TimestampNow() *timestamppb.Timestamp {
|
|
||||||
ts, err := TimestampProto(time.Now())
|
|
||||||
if err != nil {
|
|
||||||
panic("ptypes: time.Now() out of Timestamp range")
|
|
||||||
}
|
|
||||||
return ts
|
|
||||||
}
|
|
||||||
|
|
||||||
// TimestampProto converts the time.Time to a google.protobuf.Timestamp proto.
|
|
||||||
// It returns an error if the resulting Timestamp is invalid.
|
|
||||||
func TimestampProto(t time.Time) (*timestamppb.Timestamp, error) {
|
|
||||||
ts := ×tamppb.Timestamp{
|
|
||||||
Seconds: t.Unix(),
|
|
||||||
Nanos: int32(t.Nanosecond()),
|
|
||||||
}
|
|
||||||
if err := validateTimestamp(ts); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return ts, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TimestampString returns the RFC 3339 string for valid Timestamps.
|
|
||||||
// For invalid Timestamps, it returns an error message in parentheses.
|
|
||||||
func TimestampString(ts *timestamppb.Timestamp) string {
|
|
||||||
t, err := Timestamp(ts)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Sprintf("(%v)", err)
|
|
||||||
}
|
|
||||||
return t.Format(time.RFC3339Nano)
|
|
||||||
}
|
|
||||||
|
|
||||||
// validateTimestamp determines whether a Timestamp is valid.
|
|
||||||
// A valid timestamp represents a time in the range [0001-01-01, 10000-01-01)
|
|
||||||
// and has a Nanos field in the range [0, 1e9).
|
|
||||||
//
|
|
||||||
// If the Timestamp is valid, validateTimestamp returns nil.
|
|
||||||
// Otherwise, it returns an error that describes the problem.
|
|
||||||
//
|
|
||||||
// Every valid Timestamp can be represented by a time.Time,
|
|
||||||
// but the converse is not true.
|
|
||||||
func validateTimestamp(ts *timestamppb.Timestamp) error {
|
|
||||||
if ts == nil {
|
|
||||||
return errors.New("timestamp: nil Timestamp")
|
|
||||||
}
|
|
||||||
if ts.Seconds < minValidSeconds {
|
|
||||||
return fmt.Errorf("timestamp: %v before 0001-01-01", ts)
|
|
||||||
}
|
|
||||||
if ts.Seconds >= maxValidSeconds {
|
|
||||||
return fmt.Errorf("timestamp: %v after 10000-01-01", ts)
|
|
||||||
}
|
|
||||||
if ts.Nanos < 0 || ts.Nanos >= 1e9 {
|
|
||||||
return fmt.Errorf("timestamp: %v: nanos not in range [0, 1e9)", ts)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
64
vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go
generated
vendored
64
vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go
generated
vendored
|
@ -1,64 +0,0 @@
|
||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
|
||||||
// source: github.com/golang/protobuf/ptypes/timestamp/timestamp.proto
|
|
||||||
|
|
||||||
package timestamp
|
|
||||||
|
|
||||||
import (
|
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
|
||||||
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
|
|
||||||
reflect "reflect"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Symbols defined in public import of google/protobuf/timestamp.proto.
|
|
||||||
|
|
||||||
type Timestamp = timestamppb.Timestamp
|
|
||||||
|
|
||||||
var File_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto protoreflect.FileDescriptor
|
|
||||||
|
|
||||||
var file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_rawDesc = []byte{
|
|
||||||
0x0a, 0x3b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c,
|
|
||||||
0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79,
|
|
||||||
0x70, 0x65, 0x73, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2f, 0x74, 0x69,
|
|
||||||
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67,
|
|
||||||
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74,
|
|
||||||
0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x42, 0x37,
|
|
||||||
0x5a, 0x35, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c,
|
|
||||||
0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79,
|
|
||||||
0x70, 0x65, 0x73, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x3b, 0x74, 0x69,
|
|
||||||
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x50, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
|
||||||
0x33,
|
|
||||||
}
|
|
||||||
|
|
||||||
var file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_goTypes = []interface{}{}
|
|
||||||
var file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_depIdxs = []int32{
|
|
||||||
0, // [0:0] is the sub-list for method output_type
|
|
||||||
0, // [0:0] is the sub-list for method input_type
|
|
||||||
0, // [0:0] is the sub-list for extension type_name
|
|
||||||
0, // [0:0] is the sub-list for extension extendee
|
|
||||||
0, // [0:0] is the sub-list for field type_name
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() { file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_init() }
|
|
||||||
func file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_init() {
|
|
||||||
if File_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
type x struct{}
|
|
||||||
out := protoimpl.TypeBuilder{
|
|
||||||
File: protoimpl.DescBuilder{
|
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
|
||||||
RawDescriptor: file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_rawDesc,
|
|
||||||
NumEnums: 0,
|
|
||||||
NumMessages: 0,
|
|
||||||
NumExtensions: 0,
|
|
||||||
NumServices: 0,
|
|
||||||
},
|
|
||||||
GoTypes: file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_goTypes,
|
|
||||||
DependencyIndexes: file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_depIdxs,
|
|
||||||
}.Build()
|
|
||||||
File_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto = out.File
|
|
||||||
file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_rawDesc = nil
|
|
||||||
file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_goTypes = nil
|
|
||||||
file_github_com_golang_protobuf_ptypes_timestamp_timestamp_proto_depIdxs = nil
|
|
||||||
}
|
|
23
vendor/github.com/hashicorp/golang-lru/.gitignore
generated
vendored
23
vendor/github.com/hashicorp/golang-lru/.gitignore
generated
vendored
|
@ -1,23 +0,0 @@
|
||||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
|
||||||
*.o
|
|
||||||
*.a
|
|
||||||
*.so
|
|
||||||
|
|
||||||
# Folders
|
|
||||||
_obj
|
|
||||||
_test
|
|
||||||
|
|
||||||
# Architecture specific extensions/prefixes
|
|
||||||
*.[568vq]
|
|
||||||
[568vq].out
|
|
||||||
|
|
||||||
*.cgo1.go
|
|
||||||
*.cgo2.c
|
|
||||||
_cgo_defun.c
|
|
||||||
_cgo_gotypes.go
|
|
||||||
_cgo_export.*
|
|
||||||
|
|
||||||
_testmain.go
|
|
||||||
|
|
||||||
*.exe
|
|
||||||
*.test
|
|
223
vendor/github.com/hashicorp/golang-lru/2q.go
generated
vendored
223
vendor/github.com/hashicorp/golang-lru/2q.go
generated
vendored
|
@ -1,223 +0,0 @@
|
||||||
package lru
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/hashicorp/golang-lru/simplelru"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Default2QRecentRatio is the ratio of the 2Q cache dedicated
|
|
||||||
// to recently added entries that have only been accessed once.
|
|
||||||
Default2QRecentRatio = 0.25
|
|
||||||
|
|
||||||
// Default2QGhostEntries is the default ratio of ghost
|
|
||||||
// entries kept to track entries recently evicted
|
|
||||||
Default2QGhostEntries = 0.50
|
|
||||||
)
|
|
||||||
|
|
||||||
// TwoQueueCache is a thread-safe fixed size 2Q cache.
|
|
||||||
// 2Q is an enhancement over the standard LRU cache
|
|
||||||
// in that it tracks both frequently and recently used
|
|
||||||
// entries separately. This avoids a burst in access to new
|
|
||||||
// entries from evicting frequently used entries. It adds some
|
|
||||||
// additional tracking overhead to the standard LRU cache, and is
|
|
||||||
// computationally about 2x the cost, and adds some metadata over
|
|
||||||
// head. The ARCCache is similar, but does not require setting any
|
|
||||||
// parameters.
|
|
||||||
type TwoQueueCache struct {
|
|
||||||
size int
|
|
||||||
recentSize int
|
|
||||||
|
|
||||||
recent simplelru.LRUCache
|
|
||||||
frequent simplelru.LRUCache
|
|
||||||
recentEvict simplelru.LRUCache
|
|
||||||
lock sync.RWMutex
|
|
||||||
}
|
|
||||||
|
|
||||||
// New2Q creates a new TwoQueueCache using the default
|
|
||||||
// values for the parameters.
|
|
||||||
func New2Q(size int) (*TwoQueueCache, error) {
|
|
||||||
return New2QParams(size, Default2QRecentRatio, Default2QGhostEntries)
|
|
||||||
}
|
|
||||||
|
|
||||||
// New2QParams creates a new TwoQueueCache using the provided
|
|
||||||
// parameter values.
|
|
||||||
func New2QParams(size int, recentRatio float64, ghostRatio float64) (*TwoQueueCache, error) {
|
|
||||||
if size <= 0 {
|
|
||||||
return nil, fmt.Errorf("invalid size")
|
|
||||||
}
|
|
||||||
if recentRatio < 0.0 || recentRatio > 1.0 {
|
|
||||||
return nil, fmt.Errorf("invalid recent ratio")
|
|
||||||
}
|
|
||||||
if ghostRatio < 0.0 || ghostRatio > 1.0 {
|
|
||||||
return nil, fmt.Errorf("invalid ghost ratio")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine the sub-sizes
|
|
||||||
recentSize := int(float64(size) * recentRatio)
|
|
||||||
evictSize := int(float64(size) * ghostRatio)
|
|
||||||
|
|
||||||
// Allocate the LRUs
|
|
||||||
recent, err := simplelru.NewLRU(size, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
frequent, err := simplelru.NewLRU(size, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
recentEvict, err := simplelru.NewLRU(evictSize, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize the cache
|
|
||||||
c := &TwoQueueCache{
|
|
||||||
size: size,
|
|
||||||
recentSize: recentSize,
|
|
||||||
recent: recent,
|
|
||||||
frequent: frequent,
|
|
||||||
recentEvict: recentEvict,
|
|
||||||
}
|
|
||||||
return c, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get looks up a key's value from the cache.
|
|
||||||
func (c *TwoQueueCache) Get(key interface{}) (value interface{}, ok bool) {
|
|
||||||
c.lock.Lock()
|
|
||||||
defer c.lock.Unlock()
|
|
||||||
|
|
||||||
// Check if this is a frequent value
|
|
||||||
if val, ok := c.frequent.Get(key); ok {
|
|
||||||
return val, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the value is contained in recent, then we
|
|
||||||
// promote it to frequent
|
|
||||||
if val, ok := c.recent.Peek(key); ok {
|
|
||||||
c.recent.Remove(key)
|
|
||||||
c.frequent.Add(key, val)
|
|
||||||
return val, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// No hit
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add adds a value to the cache.
|
|
||||||
func (c *TwoQueueCache) Add(key, value interface{}) {
|
|
||||||
c.lock.Lock()
|
|
||||||
defer c.lock.Unlock()
|
|
||||||
|
|
||||||
// Check if the value is frequently used already,
|
|
||||||
// and just update the value
|
|
||||||
if c.frequent.Contains(key) {
|
|
||||||
c.frequent.Add(key, value)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the value is recently used, and promote
|
|
||||||
// the value into the frequent list
|
|
||||||
if c.recent.Contains(key) {
|
|
||||||
c.recent.Remove(key)
|
|
||||||
c.frequent.Add(key, value)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the value was recently evicted, add it to the
|
|
||||||
// frequently used list
|
|
||||||
if c.recentEvict.Contains(key) {
|
|
||||||
c.ensureSpace(true)
|
|
||||||
c.recentEvict.Remove(key)
|
|
||||||
c.frequent.Add(key, value)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add to the recently seen list
|
|
||||||
c.ensureSpace(false)
|
|
||||||
c.recent.Add(key, value)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// ensureSpace is used to ensure we have space in the cache
|
|
||||||
func (c *TwoQueueCache) ensureSpace(recentEvict bool) {
|
|
||||||
// If we have space, nothing to do
|
|
||||||
recentLen := c.recent.Len()
|
|
||||||
freqLen := c.frequent.Len()
|
|
||||||
if recentLen+freqLen < c.size {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the recent buffer is larger than
|
|
||||||
// the target, evict from there
|
|
||||||
if recentLen > 0 && (recentLen > c.recentSize || (recentLen == c.recentSize && !recentEvict)) {
|
|
||||||
k, _, _ := c.recent.RemoveOldest()
|
|
||||||
c.recentEvict.Add(k, nil)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove from the frequent list otherwise
|
|
||||||
c.frequent.RemoveOldest()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Len returns the number of items in the cache.
|
|
||||||
func (c *TwoQueueCache) Len() int {
|
|
||||||
c.lock.RLock()
|
|
||||||
defer c.lock.RUnlock()
|
|
||||||
return c.recent.Len() + c.frequent.Len()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Keys returns a slice of the keys in the cache.
|
|
||||||
// The frequently used keys are first in the returned slice.
|
|
||||||
func (c *TwoQueueCache) Keys() []interface{} {
|
|
||||||
c.lock.RLock()
|
|
||||||
defer c.lock.RUnlock()
|
|
||||||
k1 := c.frequent.Keys()
|
|
||||||
k2 := c.recent.Keys()
|
|
||||||
return append(k1, k2...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove removes the provided key from the cache.
|
|
||||||
func (c *TwoQueueCache) Remove(key interface{}) {
|
|
||||||
c.lock.Lock()
|
|
||||||
defer c.lock.Unlock()
|
|
||||||
if c.frequent.Remove(key) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if c.recent.Remove(key) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if c.recentEvict.Remove(key) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Purge is used to completely clear the cache.
|
|
||||||
func (c *TwoQueueCache) Purge() {
|
|
||||||
c.lock.Lock()
|
|
||||||
defer c.lock.Unlock()
|
|
||||||
c.recent.Purge()
|
|
||||||
c.frequent.Purge()
|
|
||||||
c.recentEvict.Purge()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Contains is used to check if the cache contains a key
|
|
||||||
// without updating recency or frequency.
|
|
||||||
func (c *TwoQueueCache) Contains(key interface{}) bool {
|
|
||||||
c.lock.RLock()
|
|
||||||
defer c.lock.RUnlock()
|
|
||||||
return c.frequent.Contains(key) || c.recent.Contains(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Peek is used to inspect the cache value of a key
|
|
||||||
// without updating recency or frequency.
|
|
||||||
func (c *TwoQueueCache) Peek(key interface{}) (value interface{}, ok bool) {
|
|
||||||
c.lock.RLock()
|
|
||||||
defer c.lock.RUnlock()
|
|
||||||
if val, ok := c.frequent.Peek(key); ok {
|
|
||||||
return val, ok
|
|
||||||
}
|
|
||||||
return c.recent.Peek(key)
|
|
||||||
}
|
|
362
vendor/github.com/hashicorp/golang-lru/LICENSE
generated
vendored
362
vendor/github.com/hashicorp/golang-lru/LICENSE
generated
vendored
|
@ -1,362 +0,0 @@
|
||||||
Mozilla Public License, version 2.0
|
|
||||||
|
|
||||||
1. Definitions
|
|
||||||
|
|
||||||
1.1. "Contributor"
|
|
||||||
|
|
||||||
means each individual or legal entity that creates, contributes to the
|
|
||||||
creation of, or owns Covered Software.
|
|
||||||
|
|
||||||
1.2. "Contributor Version"
|
|
||||||
|
|
||||||
means the combination of the Contributions of others (if any) used by a
|
|
||||||
Contributor and that particular Contributor's Contribution.
|
|
||||||
|
|
||||||
1.3. "Contribution"
|
|
||||||
|
|
||||||
means Covered Software of a particular Contributor.
|
|
||||||
|
|
||||||
1.4. "Covered Software"
|
|
||||||
|
|
||||||
means Source Code Form to which the initial Contributor has attached the
|
|
||||||
notice in Exhibit A, the Executable Form of such Source Code Form, and
|
|
||||||
Modifications of such Source Code Form, in each case including portions
|
|
||||||
thereof.
|
|
||||||
|
|
||||||
1.5. "Incompatible With Secondary Licenses"
|
|
||||||
means
|
|
||||||
|
|
||||||
a. that the initial Contributor has attached the notice described in
|
|
||||||
Exhibit B to the Covered Software; or
|
|
||||||
|
|
||||||
b. that the Covered Software was made available under the terms of
|
|
||||||
version 1.1 or earlier of the License, but not also under the terms of
|
|
||||||
a Secondary License.
|
|
||||||
|
|
||||||
1.6. "Executable Form"
|
|
||||||
|
|
||||||
means any form of the work other than Source Code Form.
|
|
||||||
|
|
||||||
1.7. "Larger Work"
|
|
||||||
|
|
||||||
means a work that combines Covered Software with other material, in a
|
|
||||||
separate file or files, that is not Covered Software.
|
|
||||||
|
|
||||||
1.8. "License"
|
|
||||||
|
|
||||||
means this document.
|
|
||||||
|
|
||||||
1.9. "Licensable"
|
|
||||||
|
|
||||||
means having the right to grant, to the maximum extent possible, whether
|
|
||||||
at the time of the initial grant or subsequently, any and all of the
|
|
||||||
rights conveyed by this License.
|
|
||||||
|
|
||||||
1.10. "Modifications"
|
|
||||||
|
|
||||||
means any of the following:
|
|
||||||
|
|
||||||
a. any file in Source Code Form that results from an addition to,
|
|
||||||
deletion from, or modification of the contents of Covered Software; or
|
|
||||||
|
|
||||||
b. any new file in Source Code Form that contains any Covered Software.
|
|
||||||
|
|
||||||
1.11. "Patent Claims" of a Contributor
|
|
||||||
|
|
||||||
means any patent claim(s), including without limitation, method,
|
|
||||||
process, and apparatus claims, in any patent Licensable by such
|
|
||||||
Contributor that would be infringed, but for the grant of the License,
|
|
||||||
by the making, using, selling, offering for sale, having made, import,
|
|
||||||
or transfer of either its Contributions or its Contributor Version.
|
|
||||||
|
|
||||||
1.12. "Secondary License"
|
|
||||||
|
|
||||||
means either the GNU General Public License, Version 2.0, the GNU Lesser
|
|
||||||
General Public License, Version 2.1, the GNU Affero General Public
|
|
||||||
License, Version 3.0, or any later versions of those licenses.
|
|
||||||
|
|
||||||
1.13. "Source Code Form"
|
|
||||||
|
|
||||||
means the form of the work preferred for making modifications.
|
|
||||||
|
|
||||||
1.14. "You" (or "Your")
|
|
||||||
|
|
||||||
means an individual or a legal entity exercising rights under this
|
|
||||||
License. For legal entities, "You" includes any entity that controls, is
|
|
||||||
controlled by, or is under common control with You. For purposes of this
|
|
||||||
definition, "control" means (a) the power, direct or indirect, to cause
|
|
||||||
the direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (b) ownership of more than fifty percent (50%) of the
|
|
||||||
outstanding shares or beneficial ownership of such entity.
|
|
||||||
|
|
||||||
|
|
||||||
2. License Grants and Conditions
|
|
||||||
|
|
||||||
2.1. Grants
|
|
||||||
|
|
||||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
|
||||||
non-exclusive license:
|
|
||||||
|
|
||||||
a. under intellectual property rights (other than patent or trademark)
|
|
||||||
Licensable by such Contributor to use, reproduce, make available,
|
|
||||||
modify, display, perform, distribute, and otherwise exploit its
|
|
||||||
Contributions, either on an unmodified basis, with Modifications, or
|
|
||||||
as part of a Larger Work; and
|
|
||||||
|
|
||||||
b. under Patent Claims of such Contributor to make, use, sell, offer for
|
|
||||||
sale, have made, import, and otherwise transfer either its
|
|
||||||
Contributions or its Contributor Version.
|
|
||||||
|
|
||||||
2.2. Effective Date
|
|
||||||
|
|
||||||
The licenses granted in Section 2.1 with respect to any Contribution
|
|
||||||
become effective for each Contribution on the date the Contributor first
|
|
||||||
distributes such Contribution.
|
|
||||||
|
|
||||||
2.3. Limitations on Grant Scope
|
|
||||||
|
|
||||||
The licenses granted in this Section 2 are the only rights granted under
|
|
||||||
this License. No additional rights or licenses will be implied from the
|
|
||||||
distribution or licensing of Covered Software under this License.
|
|
||||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
|
||||||
Contributor:
|
|
||||||
|
|
||||||
a. for any code that a Contributor has removed from Covered Software; or
|
|
||||||
|
|
||||||
b. for infringements caused by: (i) Your and any other third party's
|
|
||||||
modifications of Covered Software, or (ii) the combination of its
|
|
||||||
Contributions with other software (except as part of its Contributor
|
|
||||||
Version); or
|
|
||||||
|
|
||||||
c. under Patent Claims infringed by Covered Software in the absence of
|
|
||||||
its Contributions.
|
|
||||||
|
|
||||||
This License does not grant any rights in the trademarks, service marks,
|
|
||||||
or logos of any Contributor (except as may be necessary to comply with
|
|
||||||
the notice requirements in Section 3.4).
|
|
||||||
|
|
||||||
2.4. Subsequent Licenses
|
|
||||||
|
|
||||||
No Contributor makes additional grants as a result of Your choice to
|
|
||||||
distribute the Covered Software under a subsequent version of this
|
|
||||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
|
||||||
permitted under the terms of Section 3.3).
|
|
||||||
|
|
||||||
2.5. Representation
|
|
||||||
|
|
||||||
Each Contributor represents that the Contributor believes its
|
|
||||||
Contributions are its original creation(s) or it has sufficient rights to
|
|
||||||
grant the rights to its Contributions conveyed by this License.
|
|
||||||
|
|
||||||
2.6. Fair Use
|
|
||||||
|
|
||||||
This License is not intended to limit any rights You have under
|
|
||||||
applicable copyright doctrines of fair use, fair dealing, or other
|
|
||||||
equivalents.
|
|
||||||
|
|
||||||
2.7. Conditions
|
|
||||||
|
|
||||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
|
|
||||||
Section 2.1.
|
|
||||||
|
|
||||||
|
|
||||||
3. Responsibilities
|
|
||||||
|
|
||||||
3.1. Distribution of Source Form
|
|
||||||
|
|
||||||
All distribution of Covered Software in Source Code Form, including any
|
|
||||||
Modifications that You create or to which You contribute, must be under
|
|
||||||
the terms of this License. You must inform recipients that the Source
|
|
||||||
Code Form of the Covered Software is governed by the terms of this
|
|
||||||
License, and how they can obtain a copy of this License. You may not
|
|
||||||
attempt to alter or restrict the recipients' rights in the Source Code
|
|
||||||
Form.
|
|
||||||
|
|
||||||
3.2. Distribution of Executable Form
|
|
||||||
|
|
||||||
If You distribute Covered Software in Executable Form then:
|
|
||||||
|
|
||||||
a. such Covered Software must also be made available in Source Code Form,
|
|
||||||
as described in Section 3.1, and You must inform recipients of the
|
|
||||||
Executable Form how they can obtain a copy of such Source Code Form by
|
|
||||||
reasonable means in a timely manner, at a charge no more than the cost
|
|
||||||
of distribution to the recipient; and
|
|
||||||
|
|
||||||
b. You may distribute such Executable Form under the terms of this
|
|
||||||
License, or sublicense it under different terms, provided that the
|
|
||||||
license for the Executable Form does not attempt to limit or alter the
|
|
||||||
recipients' rights in the Source Code Form under this License.
|
|
||||||
|
|
||||||
3.3. Distribution of a Larger Work
|
|
||||||
|
|
||||||
You may create and distribute a Larger Work under terms of Your choice,
|
|
||||||
provided that You also comply with the requirements of this License for
|
|
||||||
the Covered Software. If the Larger Work is a combination of Covered
|
|
||||||
Software with a work governed by one or more Secondary Licenses, and the
|
|
||||||
Covered Software is not Incompatible With Secondary Licenses, this
|
|
||||||
License permits You to additionally distribute such Covered Software
|
|
||||||
under the terms of such Secondary License(s), so that the recipient of
|
|
||||||
the Larger Work may, at their option, further distribute the Covered
|
|
||||||
Software under the terms of either this License or such Secondary
|
|
||||||
License(s).
|
|
||||||
|
|
||||||
3.4. Notices
|
|
||||||
|
|
||||||
You may not remove or alter the substance of any license notices
|
|
||||||
(including copyright notices, patent notices, disclaimers of warranty, or
|
|
||||||
limitations of liability) contained within the Source Code Form of the
|
|
||||||
Covered Software, except that You may alter any license notices to the
|
|
||||||
extent required to remedy known factual inaccuracies.
|
|
||||||
|
|
||||||
3.5. Application of Additional Terms
|
|
||||||
|
|
||||||
You may choose to offer, and to charge a fee for, warranty, support,
|
|
||||||
indemnity or liability obligations to one or more recipients of Covered
|
|
||||||
Software. However, You may do so only on Your own behalf, and not on
|
|
||||||
behalf of any Contributor. You must make it absolutely clear that any
|
|
||||||
such warranty, support, indemnity, or liability obligation is offered by
|
|
||||||
You alone, and You hereby agree to indemnify every Contributor for any
|
|
||||||
liability incurred by such Contributor as a result of warranty, support,
|
|
||||||
indemnity or liability terms You offer. You may include additional
|
|
||||||
disclaimers of warranty and limitations of liability specific to any
|
|
||||||
jurisdiction.
|
|
||||||
|
|
||||||
4. Inability to Comply Due to Statute or Regulation
|
|
||||||
|
|
||||||
If it is impossible for You to comply with any of the terms of this License
|
|
||||||
with respect to some or all of the Covered Software due to statute,
|
|
||||||
judicial order, or regulation then You must: (a) comply with the terms of
|
|
||||||
this License to the maximum extent possible; and (b) describe the
|
|
||||||
limitations and the code they affect. Such description must be placed in a
|
|
||||||
text file included with all distributions of the Covered Software under
|
|
||||||
this License. Except to the extent prohibited by statute or regulation,
|
|
||||||
such description must be sufficiently detailed for a recipient of ordinary
|
|
||||||
skill to be able to understand it.
|
|
||||||
|
|
||||||
5. Termination
|
|
||||||
|
|
||||||
5.1. The rights granted under this License will terminate automatically if You
|
|
||||||
fail to comply with any of its terms. However, if You become compliant,
|
|
||||||
then the rights granted under this License from a particular Contributor
|
|
||||||
are reinstated (a) provisionally, unless and until such Contributor
|
|
||||||
explicitly and finally terminates Your grants, and (b) on an ongoing
|
|
||||||
basis, if such Contributor fails to notify You of the non-compliance by
|
|
||||||
some reasonable means prior to 60 days after You have come back into
|
|
||||||
compliance. Moreover, Your grants from a particular Contributor are
|
|
||||||
reinstated on an ongoing basis if such Contributor notifies You of the
|
|
||||||
non-compliance by some reasonable means, this is the first time You have
|
|
||||||
received notice of non-compliance with this License from such
|
|
||||||
Contributor, and You become compliant prior to 30 days after Your receipt
|
|
||||||
of the notice.
|
|
||||||
|
|
||||||
5.2. If You initiate litigation against any entity by asserting a patent
|
|
||||||
infringement claim (excluding declaratory judgment actions,
|
|
||||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
|
||||||
directly or indirectly infringes any patent, then the rights granted to
|
|
||||||
You by any and all Contributors for the Covered Software under Section
|
|
||||||
2.1 of this License shall terminate.
|
|
||||||
|
|
||||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
|
|
||||||
license agreements (excluding distributors and resellers) which have been
|
|
||||||
validly granted by You or Your distributors under this License prior to
|
|
||||||
termination shall survive termination.
|
|
||||||
|
|
||||||
6. Disclaimer of Warranty
|
|
||||||
|
|
||||||
Covered Software is provided under this License on an "as is" basis,
|
|
||||||
without warranty of any kind, either expressed, implied, or statutory,
|
|
||||||
including, without limitation, warranties that the Covered Software is free
|
|
||||||
of defects, merchantable, fit for a particular purpose or non-infringing.
|
|
||||||
The entire risk as to the quality and performance of the Covered Software
|
|
||||||
is with You. Should any Covered Software prove defective in any respect,
|
|
||||||
You (not any Contributor) assume the cost of any necessary servicing,
|
|
||||||
repair, or correction. This disclaimer of warranty constitutes an essential
|
|
||||||
part of this License. No use of any Covered Software is authorized under
|
|
||||||
this License except under this disclaimer.
|
|
||||||
|
|
||||||
7. Limitation of Liability
|
|
||||||
|
|
||||||
Under no circumstances and under no legal theory, whether tort (including
|
|
||||||
negligence), contract, or otherwise, shall any Contributor, or anyone who
|
|
||||||
distributes Covered Software as permitted above, be liable to You for any
|
|
||||||
direct, indirect, special, incidental, or consequential damages of any
|
|
||||||
character including, without limitation, damages for lost profits, loss of
|
|
||||||
goodwill, work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses, even if such party shall have been
|
|
||||||
informed of the possibility of such damages. This limitation of liability
|
|
||||||
shall not apply to liability for death or personal injury resulting from
|
|
||||||
such party's negligence to the extent applicable law prohibits such
|
|
||||||
limitation. Some jurisdictions do not allow the exclusion or limitation of
|
|
||||||
incidental or consequential damages, so this exclusion and limitation may
|
|
||||||
not apply to You.
|
|
||||||
|
|
||||||
8. Litigation
|
|
||||||
|
|
||||||
Any litigation relating to this License may be brought only in the courts
|
|
||||||
of a jurisdiction where the defendant maintains its principal place of
|
|
||||||
business and such litigation shall be governed by laws of that
|
|
||||||
jurisdiction, without reference to its conflict-of-law provisions. Nothing
|
|
||||||
in this Section shall prevent a party's ability to bring cross-claims or
|
|
||||||
counter-claims.
|
|
||||||
|
|
||||||
9. Miscellaneous
|
|
||||||
|
|
||||||
This License represents the complete agreement concerning the subject
|
|
||||||
matter hereof. If any provision of this License is held to be
|
|
||||||
unenforceable, such provision shall be reformed only to the extent
|
|
||||||
necessary to make it enforceable. Any law or regulation which provides that
|
|
||||||
the language of a contract shall be construed against the drafter shall not
|
|
||||||
be used to construe this License against a Contributor.
|
|
||||||
|
|
||||||
|
|
||||||
10. Versions of the License
|
|
||||||
|
|
||||||
10.1. New Versions
|
|
||||||
|
|
||||||
Mozilla Foundation is the license steward. Except as provided in Section
|
|
||||||
10.3, no one other than the license steward has the right to modify or
|
|
||||||
publish new versions of this License. Each version will be given a
|
|
||||||
distinguishing version number.
|
|
||||||
|
|
||||||
10.2. Effect of New Versions
|
|
||||||
|
|
||||||
You may distribute the Covered Software under the terms of the version
|
|
||||||
of the License under which You originally received the Covered Software,
|
|
||||||
or under the terms of any subsequent version published by the license
|
|
||||||
steward.
|
|
||||||
|
|
||||||
10.3. Modified Versions
|
|
||||||
|
|
||||||
If you create software not governed by this License, and you want to
|
|
||||||
create a new license for such software, you may create and use a
|
|
||||||
modified version of this License if you rename the license and remove
|
|
||||||
any references to the name of the license steward (except to note that
|
|
||||||
such modified license differs from this License).
|
|
||||||
|
|
||||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
|
||||||
Licenses If You choose to distribute Source Code Form that is
|
|
||||||
Incompatible With Secondary Licenses under the terms of this version of
|
|
||||||
the License, the notice described in Exhibit B of this License must be
|
|
||||||
attached.
|
|
||||||
|
|
||||||
Exhibit A - Source Code Form License Notice
|
|
||||||
|
|
||||||
This Source Code Form is subject to the
|
|
||||||
terms of the Mozilla Public License, v.
|
|
||||||
2.0. If a copy of the MPL was not
|
|
||||||
distributed with this file, You can
|
|
||||||
obtain one at
|
|
||||||
http://mozilla.org/MPL/2.0/.
|
|
||||||
|
|
||||||
If it is not possible or desirable to put the notice in a particular file,
|
|
||||||
then You may include the notice in a location (such as a LICENSE file in a
|
|
||||||
relevant directory) where a recipient would be likely to look for such a
|
|
||||||
notice.
|
|
||||||
|
|
||||||
You may add additional accurate notices of copyright ownership.
|
|
||||||
|
|
||||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
|
||||||
|
|
||||||
This Source Code Form is "Incompatible
|
|
||||||
With Secondary Licenses", as defined by
|
|
||||||
the Mozilla Public License, v. 2.0.
|
|
25
vendor/github.com/hashicorp/golang-lru/README.md
generated
vendored
25
vendor/github.com/hashicorp/golang-lru/README.md
generated
vendored
|
@ -1,25 +0,0 @@
|
||||||
golang-lru
|
|
||||||
==========
|
|
||||||
|
|
||||||
This provides the `lru` package which implements a fixed-size
|
|
||||||
thread safe LRU cache. It is based on the cache in Groupcache.
|
|
||||||
|
|
||||||
Documentation
|
|
||||||
=============
|
|
||||||
|
|
||||||
Full docs are available on [Godoc](http://godoc.org/github.com/hashicorp/golang-lru)
|
|
||||||
|
|
||||||
Example
|
|
||||||
=======
|
|
||||||
|
|
||||||
Using the LRU is very simple:
|
|
||||||
|
|
||||||
```go
|
|
||||||
l, _ := New(128)
|
|
||||||
for i := 0; i < 256; i++ {
|
|
||||||
l.Add(i, nil)
|
|
||||||
}
|
|
||||||
if l.Len() != 128 {
|
|
||||||
panic(fmt.Sprintf("bad len: %v", l.Len()))
|
|
||||||
}
|
|
||||||
```
|
|
257
vendor/github.com/hashicorp/golang-lru/arc.go
generated
vendored
257
vendor/github.com/hashicorp/golang-lru/arc.go
generated
vendored
|
@ -1,257 +0,0 @@
|
||||||
package lru
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/hashicorp/golang-lru/simplelru"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ARCCache is a thread-safe fixed size Adaptive Replacement Cache (ARC).
|
|
||||||
// ARC is an enhancement over the standard LRU cache in that tracks both
|
|
||||||
// frequency and recency of use. This avoids a burst in access to new
|
|
||||||
// entries from evicting the frequently used older entries. It adds some
|
|
||||||
// additional tracking overhead to a standard LRU cache, computationally
|
|
||||||
// it is roughly 2x the cost, and the extra memory overhead is linear
|
|
||||||
// with the size of the cache. ARC has been patented by IBM, but is
|
|
||||||
// similar to the TwoQueueCache (2Q) which requires setting parameters.
|
|
||||||
type ARCCache struct {
|
|
||||||
size int // Size is the total capacity of the cache
|
|
||||||
p int // P is the dynamic preference towards T1 or T2
|
|
||||||
|
|
||||||
t1 simplelru.LRUCache // T1 is the LRU for recently accessed items
|
|
||||||
b1 simplelru.LRUCache // B1 is the LRU for evictions from t1
|
|
||||||
|
|
||||||
t2 simplelru.LRUCache // T2 is the LRU for frequently accessed items
|
|
||||||
b2 simplelru.LRUCache // B2 is the LRU for evictions from t2
|
|
||||||
|
|
||||||
lock sync.RWMutex
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewARC creates an ARC of the given size
|
|
||||||
func NewARC(size int) (*ARCCache, error) {
|
|
||||||
// Create the sub LRUs
|
|
||||||
b1, err := simplelru.NewLRU(size, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
b2, err := simplelru.NewLRU(size, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
t1, err := simplelru.NewLRU(size, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
t2, err := simplelru.NewLRU(size, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize the ARC
|
|
||||||
c := &ARCCache{
|
|
||||||
size: size,
|
|
||||||
p: 0,
|
|
||||||
t1: t1,
|
|
||||||
b1: b1,
|
|
||||||
t2: t2,
|
|
||||||
b2: b2,
|
|
||||||
}
|
|
||||||
return c, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get looks up a key's value from the cache.
|
|
||||||
func (c *ARCCache) Get(key interface{}) (value interface{}, ok bool) {
|
|
||||||
c.lock.Lock()
|
|
||||||
defer c.lock.Unlock()
|
|
||||||
|
|
||||||
// If the value is contained in T1 (recent), then
|
|
||||||
// promote it to T2 (frequent)
|
|
||||||
if val, ok := c.t1.Peek(key); ok {
|
|
||||||
c.t1.Remove(key)
|
|
||||||
c.t2.Add(key, val)
|
|
||||||
return val, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the value is contained in T2 (frequent)
|
|
||||||
if val, ok := c.t2.Get(key); ok {
|
|
||||||
return val, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// No hit
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add adds a value to the cache.
|
|
||||||
func (c *ARCCache) Add(key, value interface{}) {
|
|
||||||
c.lock.Lock()
|
|
||||||
defer c.lock.Unlock()
|
|
||||||
|
|
||||||
// Check if the value is contained in T1 (recent), and potentially
|
|
||||||
// promote it to frequent T2
|
|
||||||
if c.t1.Contains(key) {
|
|
||||||
c.t1.Remove(key)
|
|
||||||
c.t2.Add(key, value)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the value is already in T2 (frequent) and update it
|
|
||||||
if c.t2.Contains(key) {
|
|
||||||
c.t2.Add(key, value)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if this value was recently evicted as part of the
|
|
||||||
// recently used list
|
|
||||||
if c.b1.Contains(key) {
|
|
||||||
// T1 set is too small, increase P appropriately
|
|
||||||
delta := 1
|
|
||||||
b1Len := c.b1.Len()
|
|
||||||
b2Len := c.b2.Len()
|
|
||||||
if b2Len > b1Len {
|
|
||||||
delta = b2Len / b1Len
|
|
||||||
}
|
|
||||||
if c.p+delta >= c.size {
|
|
||||||
c.p = c.size
|
|
||||||
} else {
|
|
||||||
c.p += delta
|
|
||||||
}
|
|
||||||
|
|
||||||
// Potentially need to make room in the cache
|
|
||||||
if c.t1.Len()+c.t2.Len() >= c.size {
|
|
||||||
c.replace(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove from B1
|
|
||||||
c.b1.Remove(key)
|
|
||||||
|
|
||||||
// Add the key to the frequently used list
|
|
||||||
c.t2.Add(key, value)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if this value was recently evicted as part of the
|
|
||||||
// frequently used list
|
|
||||||
if c.b2.Contains(key) {
|
|
||||||
// T2 set is too small, decrease P appropriately
|
|
||||||
delta := 1
|
|
||||||
b1Len := c.b1.Len()
|
|
||||||
b2Len := c.b2.Len()
|
|
||||||
if b1Len > b2Len {
|
|
||||||
delta = b1Len / b2Len
|
|
||||||
}
|
|
||||||
if delta >= c.p {
|
|
||||||
c.p = 0
|
|
||||||
} else {
|
|
||||||
c.p -= delta
|
|
||||||
}
|
|
||||||
|
|
||||||
// Potentially need to make room in the cache
|
|
||||||
if c.t1.Len()+c.t2.Len() >= c.size {
|
|
||||||
c.replace(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove from B2
|
|
||||||
c.b2.Remove(key)
|
|
||||||
|
|
||||||
// Add the key to the frequently used list
|
|
||||||
c.t2.Add(key, value)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Potentially need to make room in the cache
|
|
||||||
if c.t1.Len()+c.t2.Len() >= c.size {
|
|
||||||
c.replace(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Keep the size of the ghost buffers trim
|
|
||||||
if c.b1.Len() > c.size-c.p {
|
|
||||||
c.b1.RemoveOldest()
|
|
||||||
}
|
|
||||||
if c.b2.Len() > c.p {
|
|
||||||
c.b2.RemoveOldest()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add to the recently seen list
|
|
||||||
c.t1.Add(key, value)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// replace is used to adaptively evict from either T1 or T2
|
|
||||||
// based on the current learned value of P
|
|
||||||
func (c *ARCCache) replace(b2ContainsKey bool) {
|
|
||||||
t1Len := c.t1.Len()
|
|
||||||
if t1Len > 0 && (t1Len > c.p || (t1Len == c.p && b2ContainsKey)) {
|
|
||||||
k, _, ok := c.t1.RemoveOldest()
|
|
||||||
if ok {
|
|
||||||
c.b1.Add(k, nil)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
k, _, ok := c.t2.RemoveOldest()
|
|
||||||
if ok {
|
|
||||||
c.b2.Add(k, nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Len returns the number of cached entries
|
|
||||||
func (c *ARCCache) Len() int {
|
|
||||||
c.lock.RLock()
|
|
||||||
defer c.lock.RUnlock()
|
|
||||||
return c.t1.Len() + c.t2.Len()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Keys returns all the cached keys
|
|
||||||
func (c *ARCCache) Keys() []interface{} {
|
|
||||||
c.lock.RLock()
|
|
||||||
defer c.lock.RUnlock()
|
|
||||||
k1 := c.t1.Keys()
|
|
||||||
k2 := c.t2.Keys()
|
|
||||||
return append(k1, k2...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove is used to purge a key from the cache
|
|
||||||
func (c *ARCCache) Remove(key interface{}) {
|
|
||||||
c.lock.Lock()
|
|
||||||
defer c.lock.Unlock()
|
|
||||||
if c.t1.Remove(key) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if c.t2.Remove(key) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if c.b1.Remove(key) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if c.b2.Remove(key) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Purge is used to clear the cache
|
|
||||||
func (c *ARCCache) Purge() {
|
|
||||||
c.lock.Lock()
|
|
||||||
defer c.lock.Unlock()
|
|
||||||
c.t1.Purge()
|
|
||||||
c.t2.Purge()
|
|
||||||
c.b1.Purge()
|
|
||||||
c.b2.Purge()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Contains is used to check if the cache contains a key
|
|
||||||
// without updating recency or frequency.
|
|
||||||
func (c *ARCCache) Contains(key interface{}) bool {
|
|
||||||
c.lock.RLock()
|
|
||||||
defer c.lock.RUnlock()
|
|
||||||
return c.t1.Contains(key) || c.t2.Contains(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Peek is used to inspect the cache value of a key
|
|
||||||
// without updating recency or frequency.
|
|
||||||
func (c *ARCCache) Peek(key interface{}) (value interface{}, ok bool) {
|
|
||||||
c.lock.RLock()
|
|
||||||
defer c.lock.RUnlock()
|
|
||||||
if val, ok := c.t1.Peek(key); ok {
|
|
||||||
return val, ok
|
|
||||||
}
|
|
||||||
return c.t2.Peek(key)
|
|
||||||
}
|
|
21
vendor/github.com/hashicorp/golang-lru/doc.go
generated
vendored
21
vendor/github.com/hashicorp/golang-lru/doc.go
generated
vendored
|
@ -1,21 +0,0 @@
|
||||||
// Package lru provides three different LRU caches of varying sophistication.
|
|
||||||
//
|
|
||||||
// Cache is a simple LRU cache. It is based on the
|
|
||||||
// LRU implementation in groupcache:
|
|
||||||
// https://github.com/golang/groupcache/tree/master/lru
|
|
||||||
//
|
|
||||||
// TwoQueueCache tracks frequently used and recently used entries separately.
|
|
||||||
// This avoids a burst of accesses from taking out frequently used entries,
|
|
||||||
// at the cost of about 2x computational overhead and some extra bookkeeping.
|
|
||||||
//
|
|
||||||
// ARCCache is an adaptive replacement cache. It tracks recent evictions as
|
|
||||||
// well as recent usage in both the frequent and recent caches. Its
|
|
||||||
// computational overhead is comparable to TwoQueueCache, but the memory
|
|
||||||
// overhead is linear with the size of the cache.
|
|
||||||
//
|
|
||||||
// ARC has been patented by IBM, so do not use it if that is problematic for
|
|
||||||
// your program.
|
|
||||||
//
|
|
||||||
// All caches in this package take locks while operating, and are therefore
|
|
||||||
// thread-safe for consumers.
|
|
||||||
package lru
|
|
3
vendor/github.com/hashicorp/golang-lru/go.mod
generated
vendored
3
vendor/github.com/hashicorp/golang-lru/go.mod
generated
vendored
|
@ -1,3 +0,0 @@
|
||||||
module github.com/hashicorp/golang-lru
|
|
||||||
|
|
||||||
go 1.12
|
|
150
vendor/github.com/hashicorp/golang-lru/lru.go
generated
vendored
150
vendor/github.com/hashicorp/golang-lru/lru.go
generated
vendored
|
@ -1,150 +0,0 @@
|
||||||
package lru
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/hashicorp/golang-lru/simplelru"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Cache is a thread-safe fixed size LRU cache.
|
|
||||||
type Cache struct {
|
|
||||||
lru simplelru.LRUCache
|
|
||||||
lock sync.RWMutex
|
|
||||||
}
|
|
||||||
|
|
||||||
// New creates an LRU of the given size.
|
|
||||||
func New(size int) (*Cache, error) {
|
|
||||||
return NewWithEvict(size, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewWithEvict constructs a fixed size cache with the given eviction
|
|
||||||
// callback.
|
|
||||||
func NewWithEvict(size int, onEvicted func(key interface{}, value interface{})) (*Cache, error) {
|
|
||||||
lru, err := simplelru.NewLRU(size, simplelru.EvictCallback(onEvicted))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
c := &Cache{
|
|
||||||
lru: lru,
|
|
||||||
}
|
|
||||||
return c, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Purge is used to completely clear the cache.
|
|
||||||
func (c *Cache) Purge() {
|
|
||||||
c.lock.Lock()
|
|
||||||
c.lru.Purge()
|
|
||||||
c.lock.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add adds a value to the cache. Returns true if an eviction occurred.
|
|
||||||
func (c *Cache) Add(key, value interface{}) (evicted bool) {
|
|
||||||
c.lock.Lock()
|
|
||||||
evicted = c.lru.Add(key, value)
|
|
||||||
c.lock.Unlock()
|
|
||||||
return evicted
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get looks up a key's value from the cache.
|
|
||||||
func (c *Cache) Get(key interface{}) (value interface{}, ok bool) {
|
|
||||||
c.lock.Lock()
|
|
||||||
value, ok = c.lru.Get(key)
|
|
||||||
c.lock.Unlock()
|
|
||||||
return value, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// Contains checks if a key is in the cache, without updating the
|
|
||||||
// recent-ness or deleting it for being stale.
|
|
||||||
func (c *Cache) Contains(key interface{}) bool {
|
|
||||||
c.lock.RLock()
|
|
||||||
containKey := c.lru.Contains(key)
|
|
||||||
c.lock.RUnlock()
|
|
||||||
return containKey
|
|
||||||
}
|
|
||||||
|
|
||||||
// Peek returns the key value (or undefined if not found) without updating
|
|
||||||
// the "recently used"-ness of the key.
|
|
||||||
func (c *Cache) Peek(key interface{}) (value interface{}, ok bool) {
|
|
||||||
c.lock.RLock()
|
|
||||||
value, ok = c.lru.Peek(key)
|
|
||||||
c.lock.RUnlock()
|
|
||||||
return value, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContainsOrAdd checks if a key is in the cache without updating the
|
|
||||||
// recent-ness or deleting it for being stale, and if not, adds the value.
|
|
||||||
// Returns whether found and whether an eviction occurred.
|
|
||||||
func (c *Cache) ContainsOrAdd(key, value interface{}) (ok, evicted bool) {
|
|
||||||
c.lock.Lock()
|
|
||||||
defer c.lock.Unlock()
|
|
||||||
|
|
||||||
if c.lru.Contains(key) {
|
|
||||||
return true, false
|
|
||||||
}
|
|
||||||
evicted = c.lru.Add(key, value)
|
|
||||||
return false, evicted
|
|
||||||
}
|
|
||||||
|
|
||||||
// PeekOrAdd checks if a key is in the cache without updating the
|
|
||||||
// recent-ness or deleting it for being stale, and if not, adds the value.
|
|
||||||
// Returns whether found and whether an eviction occurred.
|
|
||||||
func (c *Cache) PeekOrAdd(key, value interface{}) (previous interface{}, ok, evicted bool) {
|
|
||||||
c.lock.Lock()
|
|
||||||
defer c.lock.Unlock()
|
|
||||||
|
|
||||||
previous, ok = c.lru.Peek(key)
|
|
||||||
if ok {
|
|
||||||
return previous, true, false
|
|
||||||
}
|
|
||||||
|
|
||||||
evicted = c.lru.Add(key, value)
|
|
||||||
return nil, false, evicted
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove removes the provided key from the cache.
|
|
||||||
func (c *Cache) Remove(key interface{}) (present bool) {
|
|
||||||
c.lock.Lock()
|
|
||||||
present = c.lru.Remove(key)
|
|
||||||
c.lock.Unlock()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resize changes the cache size.
|
|
||||||
func (c *Cache) Resize(size int) (evicted int) {
|
|
||||||
c.lock.Lock()
|
|
||||||
evicted = c.lru.Resize(size)
|
|
||||||
c.lock.Unlock()
|
|
||||||
return evicted
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveOldest removes the oldest item from the cache.
|
|
||||||
func (c *Cache) RemoveOldest() (key interface{}, value interface{}, ok bool) {
|
|
||||||
c.lock.Lock()
|
|
||||||
key, value, ok = c.lru.RemoveOldest()
|
|
||||||
c.lock.Unlock()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetOldest returns the oldest entry
|
|
||||||
func (c *Cache) GetOldest() (key interface{}, value interface{}, ok bool) {
|
|
||||||
c.lock.Lock()
|
|
||||||
key, value, ok = c.lru.GetOldest()
|
|
||||||
c.lock.Unlock()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Keys returns a slice of the keys in the cache, from oldest to newest.
|
|
||||||
func (c *Cache) Keys() []interface{} {
|
|
||||||
c.lock.RLock()
|
|
||||||
keys := c.lru.Keys()
|
|
||||||
c.lock.RUnlock()
|
|
||||||
return keys
|
|
||||||
}
|
|
||||||
|
|
||||||
// Len returns the number of items in the cache.
|
|
||||||
func (c *Cache) Len() int {
|
|
||||||
c.lock.RLock()
|
|
||||||
length := c.lru.Len()
|
|
||||||
c.lock.RUnlock()
|
|
||||||
return length
|
|
||||||
}
|
|
177
vendor/github.com/hashicorp/golang-lru/simplelru/lru.go
generated
vendored
177
vendor/github.com/hashicorp/golang-lru/simplelru/lru.go
generated
vendored
|
@ -1,177 +0,0 @@
|
||||||
package simplelru
|
|
||||||
|
|
||||||
import (
|
|
||||||
"container/list"
|
|
||||||
"errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// EvictCallback is used to get a callback when a cache entry is evicted
|
|
||||||
type EvictCallback func(key interface{}, value interface{})
|
|
||||||
|
|
||||||
// LRU implements a non-thread safe fixed size LRU cache
|
|
||||||
type LRU struct {
|
|
||||||
size int
|
|
||||||
evictList *list.List
|
|
||||||
items map[interface{}]*list.Element
|
|
||||||
onEvict EvictCallback
|
|
||||||
}
|
|
||||||
|
|
||||||
// entry is used to hold a value in the evictList
|
|
||||||
type entry struct {
|
|
||||||
key interface{}
|
|
||||||
value interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewLRU constructs an LRU of the given size
|
|
||||||
func NewLRU(size int, onEvict EvictCallback) (*LRU, error) {
|
|
||||||
if size <= 0 {
|
|
||||||
return nil, errors.New("Must provide a positive size")
|
|
||||||
}
|
|
||||||
c := &LRU{
|
|
||||||
size: size,
|
|
||||||
evictList: list.New(),
|
|
||||||
items: make(map[interface{}]*list.Element),
|
|
||||||
onEvict: onEvict,
|
|
||||||
}
|
|
||||||
return c, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Purge is used to completely clear the cache.
|
|
||||||
func (c *LRU) Purge() {
|
|
||||||
for k, v := range c.items {
|
|
||||||
if c.onEvict != nil {
|
|
||||||
c.onEvict(k, v.Value.(*entry).value)
|
|
||||||
}
|
|
||||||
delete(c.items, k)
|
|
||||||
}
|
|
||||||
c.evictList.Init()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add adds a value to the cache. Returns true if an eviction occurred.
|
|
||||||
func (c *LRU) Add(key, value interface{}) (evicted bool) {
|
|
||||||
// Check for existing item
|
|
||||||
if ent, ok := c.items[key]; ok {
|
|
||||||
c.evictList.MoveToFront(ent)
|
|
||||||
ent.Value.(*entry).value = value
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add new item
|
|
||||||
ent := &entry{key, value}
|
|
||||||
entry := c.evictList.PushFront(ent)
|
|
||||||
c.items[key] = entry
|
|
||||||
|
|
||||||
evict := c.evictList.Len() > c.size
|
|
||||||
// Verify size not exceeded
|
|
||||||
if evict {
|
|
||||||
c.removeOldest()
|
|
||||||
}
|
|
||||||
return evict
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get looks up a key's value from the cache.
|
|
||||||
func (c *LRU) Get(key interface{}) (value interface{}, ok bool) {
|
|
||||||
if ent, ok := c.items[key]; ok {
|
|
||||||
c.evictList.MoveToFront(ent)
|
|
||||||
if ent.Value.(*entry) == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
return ent.Value.(*entry).value, true
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Contains checks if a key is in the cache, without updating the recent-ness
|
|
||||||
// or deleting it for being stale.
|
|
||||||
func (c *LRU) Contains(key interface{}) (ok bool) {
|
|
||||||
_, ok = c.items[key]
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// Peek returns the key value (or undefined if not found) without updating
|
|
||||||
// the "recently used"-ness of the key.
|
|
||||||
func (c *LRU) Peek(key interface{}) (value interface{}, ok bool) {
|
|
||||||
var ent *list.Element
|
|
||||||
if ent, ok = c.items[key]; ok {
|
|
||||||
return ent.Value.(*entry).value, true
|
|
||||||
}
|
|
||||||
return nil, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove removes the provided key from the cache, returning if the
|
|
||||||
// key was contained.
|
|
||||||
func (c *LRU) Remove(key interface{}) (present bool) {
|
|
||||||
if ent, ok := c.items[key]; ok {
|
|
||||||
c.removeElement(ent)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveOldest removes the oldest item from the cache.
|
|
||||||
func (c *LRU) RemoveOldest() (key interface{}, value interface{}, ok bool) {
|
|
||||||
ent := c.evictList.Back()
|
|
||||||
if ent != nil {
|
|
||||||
c.removeElement(ent)
|
|
||||||
kv := ent.Value.(*entry)
|
|
||||||
return kv.key, kv.value, true
|
|
||||||
}
|
|
||||||
return nil, nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetOldest returns the oldest entry
|
|
||||||
func (c *LRU) GetOldest() (key interface{}, value interface{}, ok bool) {
|
|
||||||
ent := c.evictList.Back()
|
|
||||||
if ent != nil {
|
|
||||||
kv := ent.Value.(*entry)
|
|
||||||
return kv.key, kv.value, true
|
|
||||||
}
|
|
||||||
return nil, nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Keys returns a slice of the keys in the cache, from oldest to newest.
|
|
||||||
func (c *LRU) Keys() []interface{} {
|
|
||||||
keys := make([]interface{}, len(c.items))
|
|
||||||
i := 0
|
|
||||||
for ent := c.evictList.Back(); ent != nil; ent = ent.Prev() {
|
|
||||||
keys[i] = ent.Value.(*entry).key
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
return keys
|
|
||||||
}
|
|
||||||
|
|
||||||
// Len returns the number of items in the cache.
|
|
||||||
func (c *LRU) Len() int {
|
|
||||||
return c.evictList.Len()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resize changes the cache size.
|
|
||||||
func (c *LRU) Resize(size int) (evicted int) {
|
|
||||||
diff := c.Len() - size
|
|
||||||
if diff < 0 {
|
|
||||||
diff = 0
|
|
||||||
}
|
|
||||||
for i := 0; i < diff; i++ {
|
|
||||||
c.removeOldest()
|
|
||||||
}
|
|
||||||
c.size = size
|
|
||||||
return diff
|
|
||||||
}
|
|
||||||
|
|
||||||
// removeOldest removes the oldest item from the cache.
|
|
||||||
func (c *LRU) removeOldest() {
|
|
||||||
ent := c.evictList.Back()
|
|
||||||
if ent != nil {
|
|
||||||
c.removeElement(ent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// removeElement is used to remove a given list element from the cache
|
|
||||||
func (c *LRU) removeElement(e *list.Element) {
|
|
||||||
c.evictList.Remove(e)
|
|
||||||
kv := e.Value.(*entry)
|
|
||||||
delete(c.items, kv.key)
|
|
||||||
if c.onEvict != nil {
|
|
||||||
c.onEvict(kv.key, kv.value)
|
|
||||||
}
|
|
||||||
}
|
|
39
vendor/github.com/hashicorp/golang-lru/simplelru/lru_interface.go
generated
vendored
39
vendor/github.com/hashicorp/golang-lru/simplelru/lru_interface.go
generated
vendored
|
@ -1,39 +0,0 @@
|
||||||
package simplelru
|
|
||||||
|
|
||||||
// LRUCache is the interface for simple LRU cache.
|
|
||||||
type LRUCache interface {
|
|
||||||
// Adds a value to the cache, returns true if an eviction occurred and
|
|
||||||
// updates the "recently used"-ness of the key.
|
|
||||||
Add(key, value interface{}) bool
|
|
||||||
|
|
||||||
// Returns key's value from the cache and
|
|
||||||
// updates the "recently used"-ness of the key. #value, isFound
|
|
||||||
Get(key interface{}) (value interface{}, ok bool)
|
|
||||||
|
|
||||||
// Checks if a key exists in cache without updating the recent-ness.
|
|
||||||
Contains(key interface{}) (ok bool)
|
|
||||||
|
|
||||||
// Returns key's value without updating the "recently used"-ness of the key.
|
|
||||||
Peek(key interface{}) (value interface{}, ok bool)
|
|
||||||
|
|
||||||
// Removes a key from the cache.
|
|
||||||
Remove(key interface{}) bool
|
|
||||||
|
|
||||||
// Removes the oldest entry from cache.
|
|
||||||
RemoveOldest() (interface{}, interface{}, bool)
|
|
||||||
|
|
||||||
// Returns the oldest entry from the cache. #key, value, isFound
|
|
||||||
GetOldest() (interface{}, interface{}, bool)
|
|
||||||
|
|
||||||
// Returns a slice of the keys in the cache, from oldest to newest.
|
|
||||||
Keys() []interface{}
|
|
||||||
|
|
||||||
// Returns the number of items in the cache.
|
|
||||||
Len() int
|
|
||||||
|
|
||||||
// Clears all cache entries.
|
|
||||||
Purge()
|
|
||||||
|
|
||||||
// Resizes cache, returning number evicted
|
|
||||||
Resize(int) int
|
|
||||||
}
|
|
9
vendor/github.com/konsorten/go-windows-terminal-sequences/LICENSE
generated
vendored
9
vendor/github.com/konsorten/go-windows-terminal-sequences/LICENSE
generated
vendored
|
@ -1,9 +0,0 @@
|
||||||
(The MIT License)
|
|
||||||
|
|
||||||
Copyright (c) 2017 marvin + konsorten GmbH (open-source@konsorten.de)
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
42
vendor/github.com/konsorten/go-windows-terminal-sequences/README.md
generated
vendored
42
vendor/github.com/konsorten/go-windows-terminal-sequences/README.md
generated
vendored
|
@ -1,42 +0,0 @@
|
||||||
# Windows Terminal Sequences
|
|
||||||
|
|
||||||
This library allow for enabling Windows terminal color support for Go.
|
|
||||||
|
|
||||||
See [Console Virtual Terminal Sequences](https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences) for details.
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
```go
|
|
||||||
import (
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
sequences "github.com/konsorten/go-windows-terminal-sequences"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
sequences.EnableVirtualTerminalProcessing(syscall.Stdout, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
## Authors
|
|
||||||
|
|
||||||
The tool is sponsored by the [marvin + konsorten GmbH](http://www.konsorten.de).
|
|
||||||
|
|
||||||
We thank all the authors who provided code to this library:
|
|
||||||
|
|
||||||
* Felix Kollmann
|
|
||||||
* Nicolas Perraut
|
|
||||||
* @dirty49374
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
(The MIT License)
|
|
||||||
|
|
||||||
Copyright (c) 2018 marvin + konsorten GmbH (open-source@konsorten.de)
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
1
vendor/github.com/konsorten/go-windows-terminal-sequences/go.mod
generated
vendored
1
vendor/github.com/konsorten/go-windows-terminal-sequences/go.mod
generated
vendored
|
@ -1 +0,0 @@
|
||||||
module github.com/konsorten/go-windows-terminal-sequences
|
|
35
vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go
generated
vendored
35
vendor/github.com/konsorten/go-windows-terminal-sequences/sequences.go
generated
vendored
|
@ -1,35 +0,0 @@
|
||||||
// +build windows
|
|
||||||
|
|
||||||
package sequences
|
|
||||||
|
|
||||||
import (
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
kernel32Dll *syscall.LazyDLL = syscall.NewLazyDLL("Kernel32.dll")
|
|
||||||
setConsoleMode *syscall.LazyProc = kernel32Dll.NewProc("SetConsoleMode")
|
|
||||||
)
|
|
||||||
|
|
||||||
func EnableVirtualTerminalProcessing(stream syscall.Handle, enable bool) error {
|
|
||||||
const ENABLE_VIRTUAL_TERMINAL_PROCESSING uint32 = 0x4
|
|
||||||
|
|
||||||
var mode uint32
|
|
||||||
err := syscall.GetConsoleMode(syscall.Stdout, &mode)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if enable {
|
|
||||||
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
|
||||||
} else {
|
|
||||||
mode &^= ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
|
||||||
}
|
|
||||||
|
|
||||||
ret, _, err := setConsoleMode.Call(uintptr(stream), uintptr(mode))
|
|
||||||
if ret == 0 {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
11
vendor/github.com/konsorten/go-windows-terminal-sequences/sequences_dummy.go
generated
vendored
11
vendor/github.com/konsorten/go-windows-terminal-sequences/sequences_dummy.go
generated
vendored
|
@ -1,11 +0,0 @@
|
||||||
// +build linux darwin
|
|
||||||
|
|
||||||
package sequences
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
func EnableVirtualTerminalProcessing(stream uintptr, enable bool) error {
|
|
||||||
return fmt.Errorf("windows only package")
|
|
||||||
}
|
|
201
vendor/github.com/matttproud/golang_protobuf_extensions/LICENSE
generated
vendored
201
vendor/github.com/matttproud/golang_protobuf_extensions/LICENSE
generated
vendored
|
@ -1,201 +0,0 @@
|
||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright {yyyy} {name of copyright owner}
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
1
vendor/github.com/matttproud/golang_protobuf_extensions/NOTICE
generated
vendored
1
vendor/github.com/matttproud/golang_protobuf_extensions/NOTICE
generated
vendored
|
@ -1 +0,0 @@
|
||||||
Copyright 2012 Matt T. Proud (matt.proud@gmail.com)
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue