Compare commits
9 Commits
master
...
feat/first
Author | SHA1 | Date | |
---|---|---|---|
275161a3e8 | |||
34bbaee448 | |||
db2e31e0b9 | |||
9e168cb27c | |||
86bfdd5622 | |||
5cab1cd96d | |||
ebc15cb394 | |||
620cef3310 | |||
95f86d69f4 |
13
Containerfile
Normal file
13
Containerfile
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
FROM docker.io/golang:1.19-alpine AS builder
|
||||||
|
|
||||||
|
WORKDIR /go/src
|
||||||
|
ADD . .
|
||||||
|
|
||||||
|
RUN CGO_ENABLED=0 go build -v -mod vendor -tags netgo ./cmd/pod-volume-cleaner
|
||||||
|
|
||||||
|
######
|
||||||
|
FROM gcr.io/distroless/static
|
||||||
|
|
||||||
|
USER 1234
|
||||||
|
COPY --from=builder /go/src/pod-volume-cleaner /go/bin/pod-volume-cleaner
|
||||||
|
ENTRYPOINT ["/go/bin/pod-volume-cleaner"]
|
26
Dockerfile
Normal file
26
Dockerfile
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# Build the manager binary
|
||||||
|
FROM docker.io/library/golang:1.19 as builder
|
||||||
|
|
||||||
|
WORKDIR /workspace
|
||||||
|
# Copy the Go Modules manifests
|
||||||
|
COPY go.mod go.mod
|
||||||
|
COPY go.sum go.sum
|
||||||
|
|
||||||
|
# Copy dependencies
|
||||||
|
COPY vendor/ vendor/
|
||||||
|
|
||||||
|
# Copy the go source
|
||||||
|
COPY cmd/ cmd/
|
||||||
|
COPY pkg/ pkg/
|
||||||
|
|
||||||
|
# Build
|
||||||
|
RUN CGO_ENABLED=0 go build -a -v -tags netgo -o pod-cleaner ./cmd/pod-cleaner
|
||||||
|
|
||||||
|
# Use distroless as minimal base image to package the manager binary
|
||||||
|
# Refer to https://github.com/GoogleContainerTools/distroless for more details
|
||||||
|
FROM gcr.io/distroless/static:nonroot
|
||||||
|
WORKDIR /
|
||||||
|
COPY --from=builder /workspace/pod-cleaner .
|
||||||
|
USER 65532:65532
|
||||||
|
|
||||||
|
ENTRYPOINT ["/pod-cleaner"]
|
201
LICENSE
Normal file
201
LICENSE
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
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.
|
5
README.md
Normal file
5
README.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# pod-cleaner
|
||||||
|
|
||||||
|
Watch syslog file and generate alerts on orphaned pod error messages.
|
||||||
|
|
||||||
|
See https://github.com/kubernetes/kubernetes/issues/105536
|
44
cmd/pod-volume-cleaner/main.go
Normal file
44
cmd/pod-volume-cleaner/main.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"github.com/cyrilix/pod-cleaner/pkg/cleaner"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var metricPath string
|
||||||
|
var metricPort string
|
||||||
|
var logfile string
|
||||||
|
|
||||||
|
flag.StringVar(&metricPath, "metric-path", "/metrics", "Url path for metrics")
|
||||||
|
flag.StringVar(&metricPort, "metric-port", ":9098", "Http port to expose metrics")
|
||||||
|
flag.StringVar(&logfile, "log-file", "/var/syslog", "Log file to watch for orphan messages")
|
||||||
|
|
||||||
|
logLevel := zap.LevelFlag("log", zap.InfoLevel, "log level")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
config := zap.NewDevelopmentConfig()
|
||||||
|
config.Level = zap.NewAtomicLevelAt(*logLevel)
|
||||||
|
lgr, err := config.Build()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("unable to init logger: %v", err)
|
||||||
|
}
|
||||||
|
defer lgr.Sync()
|
||||||
|
|
||||||
|
zap.ReplaceGlobals(lgr)
|
||||||
|
|
||||||
|
c := cleaner.NewPodWatcher("log-file")
|
||||||
|
defer c.Close()
|
||||||
|
go c.Watch()
|
||||||
|
|
||||||
|
http.Handle(metricPath, promhttp.Handler())
|
||||||
|
err = http.ListenAndServe(metricPort, nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Panicf("unable to start prometheus listener: %v", err)
|
||||||
|
}
|
||||||
|
}
|
26
go.mod
Normal file
26
go.mod
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
module github.com/cyrilix/pod-cleaner
|
||||||
|
|
||||||
|
go 1.19
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/nxadm/tail v1.4.8
|
||||||
|
github.com/prometheus/client_golang v1.13.0
|
||||||
|
go.uber.org/zap v1.23.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/benbjohnson/clock v1.3.0 // indirect
|
||||||
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||||
|
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
||||||
|
github.com/golang/protobuf v1.5.2 // indirect
|
||||||
|
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||||
|
github.com/prometheus/client_model v0.2.0 // indirect
|
||||||
|
github.com/prometheus/common v0.37.0 // indirect
|
||||||
|
github.com/prometheus/procfs v0.8.0 // indirect
|
||||||
|
go.uber.org/atomic v1.7.0 // indirect
|
||||||
|
go.uber.org/multierr v1.6.0 // indirect
|
||||||
|
golang.org/x/sys v0.0.0-20220907062415-87db552b00fd // indirect
|
||||||
|
google.golang.org/protobuf v1.28.1 // indirect
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||||
|
)
|
497
go.sum
Normal file
497
go.sum
Normal file
@ -0,0 +1,497 @@
|
|||||||
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||||
|
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||||
|
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||||
|
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||||
|
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||||
|
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||||
|
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
||||||
|
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
||||||
|
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
||||||
|
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||||
|
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||||
|
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||||
|
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||||
|
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||||
|
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||||
|
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||||
|
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||||
|
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||||
|
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||||
|
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||||
|
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||||
|
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||||
|
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||||
|
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||||
|
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
|
||||||
|
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||||
|
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||||
|
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||||
|
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||||
|
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||||
|
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||||
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
|
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
|
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
|
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||||
|
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
|
||||||
|
github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||||
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||||
|
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||||
|
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||||
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
|
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||||
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
|
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
|
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||||
|
github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
|
||||||
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
|
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||||
|
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
||||||
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
|
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||||
|
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||||
|
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||||
|
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||||
|
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||||
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||||
|
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||||
|
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||||
|
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||||
|
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||||
|
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
|
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
|
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||||
|
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
|
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||||
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||||
|
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||||
|
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
|
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
|
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
|
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
|
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
|
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
|
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||||
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
|
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
|
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.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
|
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
|
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||||
|
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||||
|
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/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.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||||
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
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.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
|
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/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||||
|
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||||
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
|
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||||
|
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||||
|
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||||
|
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
|
||||||
|
github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU=
|
||||||
|
github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/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-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
|
||||||
|
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
|
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||||
|
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
||||||
|
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||||
|
github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE=
|
||||||
|
github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
|
||||||
|
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
|
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
|
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||||
|
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||||
|
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||||
|
github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
|
||||||
|
github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
|
||||||
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
|
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||||
|
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||||
|
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||||
|
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
|
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
|
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
|
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||||
|
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
|
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
|
||||||
|
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
||||||
|
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||||
|
go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY=
|
||||||
|
go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY=
|
||||||
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
|
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||||
|
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||||
|
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||||
|
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||||
|
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||||
|
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||||
|
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||||
|
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||||
|
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
|
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||||
|
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||||
|
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||||
|
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||||
|
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||||
|
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||||
|
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||||
|
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
|
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||||
|
golang.org/x/net v0.0.0-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-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
|
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
|
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
|
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
|
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
|
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
|
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
|
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
|
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
|
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
|
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||||
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220907062415-87db552b00fd h1:AZeIEzg+8RCELJYq8w+ODLVxFgLMMigSwO/ffKPEd9U=
|
||||||
|
golang.org/x/sys v0.0.0-20220907062415-87db552b00fd/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
|
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
|
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
|
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||||
|
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||||
|
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||||
|
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
|
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
|
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
|
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
|
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||||
|
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||||
|
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||||
|
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||||
|
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||||
|
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||||
|
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||||
|
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||||
|
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||||
|
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||||
|
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||||
|
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||||
|
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||||
|
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||||
|
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||||
|
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||||
|
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||||
|
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||||
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||||
|
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
|
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||||
|
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
|
||||||
|
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||||
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||||
|
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||||
|
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
|
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
|
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
|
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||||
|
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
|
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
|
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
|
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||||
|
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||||
|
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
|
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
|
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||||
|
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||||
|
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||||
|
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||||
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
|
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
||||||
|
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
|
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 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
|
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.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.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||||
|
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||||
|
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||||
|
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||||
|
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||||
|
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
23
helm/.helmignore
Normal file
23
helm/.helmignore
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# Patterns to ignore when building packages.
|
||||||
|
# This supports shell glob matching, relative path matching, and
|
||||||
|
# negation (prefixed with !). Only one pattern per line.
|
||||||
|
.DS_Store
|
||||||
|
# Common VCS dirs
|
||||||
|
.git/
|
||||||
|
.gitignore
|
||||||
|
.bzr/
|
||||||
|
.bzrignore
|
||||||
|
.hg/
|
||||||
|
.hgignore
|
||||||
|
.svn/
|
||||||
|
# Common backup files
|
||||||
|
*.swp
|
||||||
|
*.bak
|
||||||
|
*.tmp
|
||||||
|
*.orig
|
||||||
|
*~
|
||||||
|
# Various IDEs
|
||||||
|
.project
|
||||||
|
.idea/
|
||||||
|
*.tmproj
|
||||||
|
.vscode/
|
24
helm/Chart.yaml
Normal file
24
helm/Chart.yaml
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
apiVersion: v2
|
||||||
|
name: pod-volume-cleaner
|
||||||
|
description: Helm chart for pod-volume-cleaner
|
||||||
|
|
||||||
|
# A chart can be either an 'application' or a 'library' chart.
|
||||||
|
#
|
||||||
|
# Application charts are a collection of templates that can be packaged into versioned archives
|
||||||
|
# to be deployed.
|
||||||
|
#
|
||||||
|
# Library charts provide useful utilities or functions for the chart developer. They're included as
|
||||||
|
# a dependency of application charts to inject those utilities and functions into the rendering
|
||||||
|
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
|
||||||
|
type: application
|
||||||
|
|
||||||
|
# This is the chart version. This version number should be incremented each time you make changes
|
||||||
|
# to the chart and its templates, including the app version.
|
||||||
|
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
||||||
|
version: 0.1.0
|
||||||
|
|
||||||
|
# This is the version number of the application being deployed. This version number should be
|
||||||
|
# incremented each time you make changes to the application. Versions are not expected to
|
||||||
|
# follow Semantic Versioning. They should reflect the version the application is using.
|
||||||
|
# It is recommended to use it with quotes.
|
||||||
|
appVersion: "0.1.0"
|
48
helm/README.md
Normal file
48
helm/README.md
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
# pod-volume-cleaner
|
||||||
|
|
||||||
|
  
|
||||||
|
|
||||||
|
Helm chart for pod-volume-cleaner
|
||||||
|
|
||||||
|
## Values
|
||||||
|
|
||||||
|
| Key | Type | Default | Description |
|
||||||
|
|-----|------|---------|-------------|
|
||||||
|
| fullnameOverride | string | `nil` | Override the expanded name of the chart |
|
||||||
|
| image.pullPolicy | string | `"IfNotPresent"` | Image pull policy |
|
||||||
|
| image.pullSecrets | list | `[]` | Image pull secrets |
|
||||||
|
| image.repository | string | `"docker.io/cyrilix/pod-cleaner"` | Image repository |
|
||||||
|
| image.tag | string | `""` | Image tag Defaults to appVersion in Chart.yaml if omitted |
|
||||||
|
| nameOverride | string | `nil` | Override the name of the chart |
|
||||||
|
| nodeAffinity | object | `{}` | Node affinity constraints. |
|
||||||
|
| nodeSelector | object | `{}` | Node labels for pod assignment |
|
||||||
|
| podAnnotations | object | `{}` | Additional annotations to add to each pod |
|
||||||
|
| podCleaner.logLevel | string | `"info"` | Log level: info,debug |
|
||||||
|
| podCleaner.logfile | string | `"/var/log/syslog"` | File to watch to detect orphan pod errors |
|
||||||
|
| podLabels | object | `{}` | Additional labels to add to each pod |
|
||||||
|
| podMonitor.additionalLabels | string | `nil` | Additional labels |
|
||||||
|
| podMonitor.enabled | bool | `false` | Create a `PodMonitor` to collect Prometheus metrics. |
|
||||||
|
| podMonitor.interval | string | `"30s"` | Interval to scrape metrics |
|
||||||
|
| podMonitor.path | string | `"/metrics"` | Url path to scrap metrics |
|
||||||
|
| podMonitor.scrapeTimeout | string | `"25s"` | Timeout if metrics can't be retrieved in given time interval |
|
||||||
|
| podMonitor.secure | bool | `false` | Is TLS required for endpoint |
|
||||||
|
| podMonitor.tlsConfig | object | `{}` | TLS Configuration for endpoint |
|
||||||
|
| podSecurityContext | object | `{}` | Security context for the pod |
|
||||||
|
| priorityClassName | string | `""` | Optional priority class to be used for kyverno pods |
|
||||||
|
| rbac.create | bool | `true` | Create ClusterRoles, ClusterRoleBindings, and ServiceAccount |
|
||||||
|
| rbac.serviceAccount.annotations | object | `{}` | Annotations for the ServiceAccount |
|
||||||
|
| rbac.serviceAccount.create | bool | `true` | Create a ServiceAccount |
|
||||||
|
| rbac.serviceAccount.name | string | `nil` | The ServiceAccount name |
|
||||||
|
| resources | object | `{}` | |
|
||||||
|
| revisionHistoryLimit | int | `0` | The number of old history to retain to allow rollback |
|
||||||
|
| securityContext | object | `{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"privileged":false,"readOnlyRootFilesystem":true,"runAsNonRoot":true,"seccompProfile":{"type":"RuntimeDefault"}}` | Security context for the containers |
|
||||||
|
| service.annotations | object | `{}` | Service annotations. |
|
||||||
|
| service.nodePort | string | `nil` | Service node port. Only used if `service.type` is `NodePort`. |
|
||||||
|
| service.port | int | `9098` | Service port. |
|
||||||
|
| service.type | string | `"ClusterIP"` | Service type. |
|
||||||
|
| tolerations | list | `[]` | List of node taints to tolerate |
|
||||||
|
| topologySpreadConstraints | list | `[]` | Topology spread constraints. |
|
||||||
|
| updateStrategy | object | See [values.yaml](values.yaml) | Deployment update strategy. Ref: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy |
|
||||||
|
|
||||||
|
----------------------------------------------
|
||||||
|
Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0)
|
36
helm/README.md.tpl
Normal file
36
helm/README.md.tpl
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
|
||||||
|
## Upgrade
|
||||||
|
|
||||||
|
None
|
||||||
|
|
||||||
|
|
||||||
|
## Develop
|
||||||
|
|
||||||
|
### Update documentation
|
||||||
|
|
||||||
|
Chart documentation is generated with [helm-docs](https://github.com/norwoodj/helm-docs) from `values.yaml` file.
|
||||||
|
After file modification, regenerate README.md with command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run --rm -it -v $(pwd):/helm --workdir /helm norwoodj/helm-docs helm-docs
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run linter
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run --rm -it -w /charts -v $(pwd)/../{{ .Name }}:/charts quay.io/helmpack/chart-testing:v2.4.0 ct lint --charts . --config /charts/ct.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
### Prometheus Rules
|
||||||
|
|
||||||
|
Check rules:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run --rm --entrypoint /bin/sh -v $(pwd):/workdir -w /workdir prom/prometheus -c -- "promtool check rules resources/prometheus-rules/*"
|
||||||
|
```
|
||||||
|
|
||||||
|
Test rules:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run --rm --entrypoint /bin/sh -v $(pwd):/workdir -w /workdir prom/prometheus -c -- "promtool test rules tests/prometheus/*"
|
||||||
|
```
|
68
helm/templates/_helpers.tpl
Normal file
68
helm/templates/_helpers.tpl
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
{{/*
|
||||||
|
Expand the name of the chart.
|
||||||
|
*/}}
|
||||||
|
{{- define "pod-cleaner.name" -}}
|
||||||
|
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create a default fully qualified app name.
|
||||||
|
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||||
|
If release name contains chart name it will be used as a full name.
|
||||||
|
*/}}
|
||||||
|
{{- define "pod-cleaner.fullname" -}}
|
||||||
|
{{- if .Values.fullnameOverride }}
|
||||||
|
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- else }}
|
||||||
|
{{- $name := default .Chart.Name .Values.nameOverride }}
|
||||||
|
{{- if contains $name .Release.Name }}
|
||||||
|
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- else }}
|
||||||
|
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create chart name and version as used by the chart label.
|
||||||
|
*/}}
|
||||||
|
{{- define "pod-cleaner.chart" -}}
|
||||||
|
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Common labels
|
||||||
|
*/}}
|
||||||
|
{{- define "pod-cleaner.labels" -}}
|
||||||
|
app: {{ .Chart.Name }}
|
||||||
|
helm.sh/chart: {{ include "pod-cleaner.chart" . }}
|
||||||
|
{{ include "pod-cleaner.selectorLabels" . }}
|
||||||
|
{{- if .Chart.AppVersion }}
|
||||||
|
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||||
|
version: {{ .Chart.AppVersion | quote }}
|
||||||
|
{{- end }}
|
||||||
|
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Selector labels
|
||||||
|
*/}}
|
||||||
|
{{- define "pod-cleaner.selectorLabels" -}}
|
||||||
|
app.kubernetes.io/name: {{ include "pod-cleaner.name" . }}
|
||||||
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create the name of the service account to use
|
||||||
|
*/}}
|
||||||
|
{{- define "pod-cleaner.serviceAccountName" -}}
|
||||||
|
{{- if .Values.rbac.serviceAccount.create }}
|
||||||
|
{{- default (include "pod-cleaner.fullname" .) .Values.rbac.serviceAccount.name }}
|
||||||
|
{{- else }}
|
||||||
|
{{- default "default" .Values.rbac.serviceAccount.name }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "pod-cleaner.metrics.portName" -}}
|
||||||
|
http-metric
|
||||||
|
{{- end -}}
|
75
helm/templates/daemonset.yaml
Normal file
75
helm/templates/daemonset.yaml
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: DaemonSet
|
||||||
|
metadata:
|
||||||
|
name: {{ include "pod-cleaner.fullname" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "pod-cleaner.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "pod-cleaner.selectorLabels" . | nindent 6 }}
|
||||||
|
{{- if .Values.updateStrategy }}
|
||||||
|
updateStrategy:
|
||||||
|
{{ toYaml .Values.updateStrategy | nindent 4 | trim }}
|
||||||
|
{{- end }}
|
||||||
|
revisionHistoryLimit: {{ .Values.revisionHistoryLimit }}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
{{- with .Values.podAnnotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
labels:
|
||||||
|
{{- include "pod-cleaner.selectorLabels" . | nindent 8 }}
|
||||||
|
spec:
|
||||||
|
{{- with .Values.image.pullSecrets }}
|
||||||
|
imagePullSecrets:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
serviceAccountName: {{ include "pod-cleaner.serviceAccountName" . }}
|
||||||
|
securityContext:
|
||||||
|
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
||||||
|
containers:
|
||||||
|
- name: {{ .Chart.Name }}
|
||||||
|
securityContext:
|
||||||
|
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||||
|
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
|
||||||
|
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||||
|
args:
|
||||||
|
- "--metric-path={{ .Values.podMonitor.path }}"
|
||||||
|
- "--metric-port=0.0.0.0:{{ .Values.service.port }}"
|
||||||
|
- "--log-file={{ .Values.podCleaner.logfile }}"
|
||||||
|
- "--log={{ .Values.podCleaner.logLevel }}"
|
||||||
|
ports:
|
||||||
|
- name: {{ include "pod-cleaner.metrics.portName" . }}
|
||||||
|
containerPort: {{ .Values.service.port }}
|
||||||
|
protocol: TCP
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: {{ .Values.podMonitor.path }}
|
||||||
|
port: {{ include "pod-cleaner.metrics.portName" . }}
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: {{ .Values.podMonitor.path }}
|
||||||
|
port: {{ include "pod-cleaner.metrics.portName" . }}
|
||||||
|
resources:
|
||||||
|
{{- toYaml .Values.resources | nindent 12 }}
|
||||||
|
{{- if or .Values.nodeAffinity }}
|
||||||
|
affinity:
|
||||||
|
{{- toYaml .Values.nodeAffinity | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.nodeSelector }}
|
||||||
|
nodeSelector:
|
||||||
|
{{ tpl (toYaml . ) $ | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.tolerations }}
|
||||||
|
tolerations:
|
||||||
|
{{- tpl (toYaml . ) $ | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.topologySpreadConstraints }}
|
||||||
|
topologySpreadConstraints: {{ tpl (toYaml . ) $ | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
serviceAccountName: {{ template "pod-cleaner.serviceAccountName" . }}
|
||||||
|
{{- if .Values.priorityClassName }}
|
||||||
|
priorityClassName: {{ .Values.priorityClassName | quote }}
|
||||||
|
{{- end }}
|
30
helm/templates/podmonitor.yaml
Normal file
30
helm/templates/podmonitor.yaml
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
{{- if .Values.podMonitor.enabled }}
|
||||||
|
apiVersion: monitoring.coreos.com/v1
|
||||||
|
kind: PodMonitor
|
||||||
|
metadata:
|
||||||
|
name: {{ include "pod-cleaner.fullname" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "pod-cleaner.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "pod-cleaner.labels" . | nindent 6 }}
|
||||||
|
podMetricsEndpoints:
|
||||||
|
- port: {{ include "pod-cleaner.metrics.portName" . | quote }}
|
||||||
|
path: {{ .Values.podMonitor.path | quote }}
|
||||||
|
{{- if .Values.podMonitor.tlsConfig }}
|
||||||
|
scheme: "https"
|
||||||
|
tlsConfig:
|
||||||
|
{{- toYaml .Values.podMonitor.tlsConfig | trim | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
interval: {{ .Values.podMonitor.interval }}
|
||||||
|
scrapeTimeout: {{ .Values.podMonitor.scrapeTimeout }}
|
||||||
|
|
||||||
|
namespaceSelector:
|
||||||
|
matchNames:
|
||||||
|
- {{ .Release.Namespace }}
|
||||||
|
{{- if .Values.podMonitor.additionalLabels }}
|
||||||
|
jobLabel:
|
||||||
|
{{- toYaml .Values.podMonitor.additionalLabels | trim | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
12
helm/templates/serviceaccount.yaml
Normal file
12
helm/templates/serviceaccount.yaml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{{- if .Values.rbac.serviceAccount.create -}}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: {{ include "pod-cleaner.serviceAccountName" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "pod-cleaner.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.rbac.serviceAccount.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
128
helm/values.yaml
Normal file
128
helm/values.yaml
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
# -- Override the name of the chart
|
||||||
|
nameOverride:
|
||||||
|
|
||||||
|
# -- Override the expanded name of the chart
|
||||||
|
fullnameOverride:
|
||||||
|
|
||||||
|
image:
|
||||||
|
# -- Image repository
|
||||||
|
repository: git.cyrilix.bzh/cyrilix/pod-volume-cleaner
|
||||||
|
# -- Image tag
|
||||||
|
# Defaults to appVersion in Chart.yaml if omitted
|
||||||
|
tag: ""
|
||||||
|
# -- Image pull policy
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
# -- Image pull secrets
|
||||||
|
pullSecrets: []
|
||||||
|
# - secretName
|
||||||
|
|
||||||
|
# -- The number of old history to retain to allow rollback
|
||||||
|
revisionHistoryLimit: 0
|
||||||
|
|
||||||
|
# -- Deployment update strategy.
|
||||||
|
# Ref: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy
|
||||||
|
# @default -- See [values.yaml](values.yaml)
|
||||||
|
updateStrategy:
|
||||||
|
type: RollingUpdate
|
||||||
|
|
||||||
|
rbac:
|
||||||
|
# -- Create ClusterRoles, ClusterRoleBindings, and ServiceAccount
|
||||||
|
create: true
|
||||||
|
serviceAccount:
|
||||||
|
# -- Create a ServiceAccount
|
||||||
|
create: true
|
||||||
|
# -- The ServiceAccount name
|
||||||
|
name:
|
||||||
|
# -- Annotations for the ServiceAccount
|
||||||
|
annotations: {}
|
||||||
|
# example.com/annotation: value
|
||||||
|
|
||||||
|
|
||||||
|
service:
|
||||||
|
# -- Service port.
|
||||||
|
port: 9098
|
||||||
|
# -- Service type.
|
||||||
|
type: ClusterIP
|
||||||
|
# -- Service node port.
|
||||||
|
# Only used if `service.type` is `NodePort`.
|
||||||
|
nodePort:
|
||||||
|
# -- Service annotations.
|
||||||
|
annotations: { }
|
||||||
|
|
||||||
|
|
||||||
|
resources: {}
|
||||||
|
# We usually recommend not to specify default resources and to leave this as a conscious
|
||||||
|
# choice for the user. This also increases chances charts run on environments with little
|
||||||
|
# resources, such as Minikube. If you do want to specify resources, uncomment the following
|
||||||
|
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
|
||||||
|
# limits:
|
||||||
|
# cpu: 100m
|
||||||
|
# memory: 128Mi
|
||||||
|
# requests:
|
||||||
|
# cpu: 100m
|
||||||
|
# memory: 128Mi
|
||||||
|
|
||||||
|
|
||||||
|
# -- Additional labels to add to each pod
|
||||||
|
podLabels: {}
|
||||||
|
# example.com/label: foo
|
||||||
|
|
||||||
|
# -- Additional annotations to add to each pod
|
||||||
|
podAnnotations: {}
|
||||||
|
# example.com/annotation: foo
|
||||||
|
|
||||||
|
# -- Security context for the pod
|
||||||
|
podSecurityContext: {}
|
||||||
|
|
||||||
|
# -- Security context for the containers
|
||||||
|
securityContext:
|
||||||
|
runAsNonRoot: true
|
||||||
|
privileged: false
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
readOnlyRootFilesystem: true
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
|
seccompProfile:
|
||||||
|
type: RuntimeDefault
|
||||||
|
|
||||||
|
# -- Optional priority class to be used for kyverno pods
|
||||||
|
priorityClassName: ''
|
||||||
|
|
||||||
|
# -- Node affinity constraints.
|
||||||
|
nodeAffinity: {}
|
||||||
|
|
||||||
|
# -- Node labels for pod assignment
|
||||||
|
nodeSelector: {}
|
||||||
|
|
||||||
|
# -- List of node taints to tolerate
|
||||||
|
tolerations: []
|
||||||
|
|
||||||
|
# -- Topology spread constraints.
|
||||||
|
topologySpreadConstraints: []
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
podCleaner:
|
||||||
|
# -- File to watch to detect orphan pod errors
|
||||||
|
logfile: /var/log/syslog
|
||||||
|
# -- Log level: info,debug
|
||||||
|
logLevel: info
|
||||||
|
|
||||||
|
|
||||||
|
podMonitor:
|
||||||
|
# -- Create a `PodMonitor` to collect Prometheus metrics.
|
||||||
|
enabled: false
|
||||||
|
# -- Url path to scrap metrics
|
||||||
|
path: /metrics
|
||||||
|
# -- Additional labels
|
||||||
|
additionalLabels:
|
||||||
|
# key: value
|
||||||
|
# -- Interval to scrape metrics
|
||||||
|
interval: 30s
|
||||||
|
# -- Timeout if metrics can't be retrieved in given time interval
|
||||||
|
scrapeTimeout: 25s
|
||||||
|
# -- Is TLS required for endpoint
|
||||||
|
secure: false
|
||||||
|
# -- TLS Configuration for endpoint
|
||||||
|
tlsConfig: {}
|
96
pkg/cleaner/cleaner.go
Normal file
96
pkg/cleaner/cleaner.go
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
package cleaner
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/cyrilix/pod-cleaner/pkg/metrics"
|
||||||
|
"github.com/cyrilix/pod-cleaner/pkg/monitor"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
defaultRegex = regexp.MustCompile("There were many similar errors. Turn up verbosity to see them.\" err=\\\"orphaned pod \\\\\"(?P<podId>[0-9a-f\\-]+)\\\\\" found, but error not a directory occurred when trying to remove the volumes dir\" numErrs=(?P<numErrs>[0-9]+)")
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewPodWatcher(logfile string) *PodWatcher {
|
||||||
|
return &PodWatcher{
|
||||||
|
m: monitor.New(),
|
||||||
|
rex: defaultRegex,
|
||||||
|
logfile: logfile,
|
||||||
|
cancel: make(chan interface{}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type PodWatcher struct {
|
||||||
|
m monitor.Monitor
|
||||||
|
rex *regexp.Regexp
|
||||||
|
logfile string
|
||||||
|
|
||||||
|
cancel chan interface{}
|
||||||
|
|
||||||
|
muPodError sync.RWMutex
|
||||||
|
numErrors int
|
||||||
|
podIdErrors string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *PodWatcher) Close() error {
|
||||||
|
close(w.cancel)
|
||||||
|
if w.m != nil {
|
||||||
|
err := w.m.Close()
|
||||||
|
if err != nil {
|
||||||
|
zap.S().Errorf("unable to close monitor resource: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *PodWatcher) GetNumErrors() int {
|
||||||
|
w.muPodError.RLock()
|
||||||
|
defer w.muPodError.RUnlock()
|
||||||
|
return w.numErrors
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *PodWatcher) GetPodDirInError() string {
|
||||||
|
w.muPodError.RLock()
|
||||||
|
defer w.muPodError.RUnlock()
|
||||||
|
if w.podIdErrors == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("/var/lib/kubelet/pods/%s", w.podIdErrors)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *PodWatcher) Watch() {
|
||||||
|
lineChan := make(chan string)
|
||||||
|
go func() {
|
||||||
|
err := w.m.Watch(w.logfile, w.rex, lineChan)
|
||||||
|
if err != nil {
|
||||||
|
zap.S().Panicf("unable to init watching on file '%s', %v", w.logfile, err)
|
||||||
|
}
|
||||||
|
close(w.cancel)
|
||||||
|
}()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case line := <-lineChan:
|
||||||
|
w.processLogRecord(line)
|
||||||
|
case <-w.cancel:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *PodWatcher) processLogRecord(line string) {
|
||||||
|
numErrors, err := strconv.Atoi(w.rex.FindStringSubmatch(line)[w.rex.SubexpIndex("numErrs")])
|
||||||
|
if err != nil {
|
||||||
|
zap.S().Errorf("unable to extract numErrors value from line '%v': %v", line, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.muPodError.Lock()
|
||||||
|
defer w.muPodError.Unlock()
|
||||||
|
w.numErrors = numErrors
|
||||||
|
w.podIdErrors = w.rex.FindStringSubmatch(line)[w.rex.SubexpIndex("podId")]
|
||||||
|
|
||||||
|
metrics.NumErrors.Set(float64(numErrors))
|
||||||
|
}
|
50
pkg/cleaner/cleaner_test.go
Normal file
50
pkg/cleaner/cleaner_test.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package cleaner
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/cyrilix/pod-cleaner/pkg/monitor"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPodWatcher_Watch(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
logfile string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
wantPodDir string
|
||||||
|
wantNumError int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "one error in file",
|
||||||
|
fields: fields{
|
||||||
|
logfile: "test_data/one-error.log",
|
||||||
|
},
|
||||||
|
wantPodDir: "/var/lib/kubelet/pods/1d4bfc07-3469-4eaa-992f-6d23c17f3aee",
|
||||||
|
wantNumError: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no error",
|
||||||
|
fields: fields{
|
||||||
|
logfile: "test_data/no-error.log",
|
||||||
|
},
|
||||||
|
wantPodDir: "",
|
||||||
|
wantNumError: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
w := NewPodWatcher(tt.fields.logfile)
|
||||||
|
w.m = monitor.New(monitor.WithTailFollow(false), monitor.WithReOpen(false))
|
||||||
|
w.Watch()
|
||||||
|
gotNumErr := w.GetNumErrors()
|
||||||
|
if gotNumErr != tt.wantNumError {
|
||||||
|
t.Errorf("PodWatcher_Watch(), bad numErrors found: %v, want %v", gotNumErr, tt.wantNumError)
|
||||||
|
}
|
||||||
|
gotPodDir := w.GetPodDirInError()
|
||||||
|
if gotPodDir != tt.wantPodDir {
|
||||||
|
t.Errorf("PodWatcher_Watch(), bad pod directory found: %v, want %v", gotPodDir, tt.wantPodDir)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
3
pkg/cleaner/test_data/no-error.log
Normal file
3
pkg/cleaner/test_data/no-error.log
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
egreg
|
||||||
|
abcffe
|
||||||
|
erfer
|
4
pkg/cleaner/test_data/one-error.log
Normal file
4
pkg/cleaner/test_data/one-error.log
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
egreg
|
||||||
|
Oct 07 12:46:32 k8s-master2-staging kubelet[7310]: E1007 12:46:32.359145 7310 kubelet_volumes.go:245] "There were many similar errors. Turn up verbosity to see them." err="orphaned pod \"1d4bfc07-3469-4eaa-992f-6d23c17f3aee\" found, but error not a directory occurred when trying to remove the volumes dir" numErrs=1
|
||||||
|
abcffe
|
||||||
|
erfer
|
17
pkg/metrics/metrics.go
Normal file
17
pkg/metrics/metrics.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package metrics
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
NumErrors = promauto.NewGauge(
|
||||||
|
prometheus.GaugeOpts{
|
||||||
|
Namespace: "infra",
|
||||||
|
Subsystem: "pod_cleaner",
|
||||||
|
Name: "orphans_pod_error_count",
|
||||||
|
Help: "Number of orphan pods that failed to be cleaned",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
)
|
81
pkg/monitor/monitor.go
Normal file
81
pkg/monitor/monitor.go
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
package monitor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/nxadm/tail"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Option func(monitor *LogMonitor)
|
||||||
|
|
||||||
|
// WithTailFollow Continue looking for new lines (tail -f)
|
||||||
|
func WithTailFollow(follow bool) Option {
|
||||||
|
return func(monitor *LogMonitor) {
|
||||||
|
monitor.follow = follow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithReOpen Reopen recreated files (tail -F)
|
||||||
|
func WithReOpen(reopen bool) Option {
|
||||||
|
return func(monitor *LogMonitor) {
|
||||||
|
monitor.reopen = reopen
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Monitor interface {
|
||||||
|
Close() error
|
||||||
|
Watch(filename string, filter *regexp.Regexp, lineChan chan<- string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(opts ...Option) *LogMonitor {
|
||||||
|
l := &LogMonitor{
|
||||||
|
follow: true,
|
||||||
|
reopen: true,
|
||||||
|
cancel: make(chan interface{}),
|
||||||
|
}
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(l)
|
||||||
|
}
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
type LogMonitor struct {
|
||||||
|
follow bool
|
||||||
|
reopen bool
|
||||||
|
cancel chan interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *LogMonitor) Close() error {
|
||||||
|
close(l.cancel)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *LogMonitor) Watch(filename string, filter *regexp.Regexp, lineChan chan<- string) error {
|
||||||
|
t, err := tail.TailFile(filename, tail.Config{Follow: l.follow, ReOpen: l.reopen, Logger: tail.DiscardingLogger})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to begin to tail file '%s': %w", filename, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case line := <-t.Lines:
|
||||||
|
if line == nil {
|
||||||
|
// EOF
|
||||||
|
t.Cleanup()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if line.Err != nil {
|
||||||
|
zap.S().Errorf("tail error: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if filter.MatchString(line.Text) {
|
||||||
|
lineChan <- line.Text
|
||||||
|
}
|
||||||
|
case <-l.cancel:
|
||||||
|
t.Stop()
|
||||||
|
t.Cleanup()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
113
pkg/monitor/monitor_test.go
Normal file
113
pkg/monitor/monitor_test.go
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
package monitor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"reflect"
|
||||||
|
"regexp"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLogMonitor_Watch(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
filter *regexp.Regexp
|
||||||
|
}
|
||||||
|
type data struct {
|
||||||
|
lines []string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
data data
|
||||||
|
want []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "watch all lines",
|
||||||
|
args: args{
|
||||||
|
regexp.MustCompile(".*"),
|
||||||
|
},
|
||||||
|
data: data{lines: []string{"line1", "line2"}},
|
||||||
|
want: []string{"line1", "line2"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "match none lines",
|
||||||
|
args: args{
|
||||||
|
regexp.MustCompile(".*with unknown pattern.*"),
|
||||||
|
},
|
||||||
|
data: data{lines: []string{"line1", "line2"}},
|
||||||
|
want: []string{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "match one line",
|
||||||
|
args: args{
|
||||||
|
regexp.MustCompile(".* to keep$"),
|
||||||
|
},
|
||||||
|
data: data{lines: []string{"line1", "line2 to keep"}},
|
||||||
|
want: []string{"line2 to keep"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
dir, err := os.MkdirTemp("", "watch")
|
||||||
|
logfile := path.Join(dir, "file.log")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unable to init tmp dir: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
|
l := New()
|
||||||
|
defer l.Close()
|
||||||
|
|
||||||
|
chanLines := make(chan string, 5)
|
||||||
|
go func() {
|
||||||
|
err := l.Watch(logfile, tt.args.filter, chanLines)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unable to start to watching logs: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Create new file to watch
|
||||||
|
file, err := os.Create(logfile)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unable to create log file: %v", err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
// Write test data into watched file
|
||||||
|
waitEndWriting := sync.WaitGroup{}
|
||||||
|
waitEndWriting.Add(len(tt.data.lines))
|
||||||
|
go func() {
|
||||||
|
for _, line := range tt.data.lines {
|
||||||
|
_, err = file.WriteString(line + "\n")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unable to write line '%v': %v", line, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
waitEndWriting.Done()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
lineCpt := 0
|
||||||
|
waitEndWriting.Wait()
|
||||||
|
got := make([]string, 0, len(tt.want))
|
||||||
|
for len(got) < len(tt.want) {
|
||||||
|
select {
|
||||||
|
case line := <-chanLines:
|
||||||
|
got = append(got, line)
|
||||||
|
lineCpt++
|
||||||
|
case <-time.After(1 * time.Millisecond):
|
||||||
|
t.Errorf("waiting line timeout")
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(tt.want, got) {
|
||||||
|
t.Errorf("LogMonitor_Watch(), bad lines published: got = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
20
vendor/github.com/beorn7/perks/LICENSE
generated
vendored
Normal file
20
vendor/github.com/beorn7/perks/LICENSE
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
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
Normal file
2388
vendor/github.com/beorn7/perks/quantile/exampledata.txt
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
316
vendor/github.com/beorn7/perks/quantile/stream.go
generated
vendored
Normal file
316
vendor/github.com/beorn7/perks/quantile/stream.go
generated
vendored
Normal file
@ -0,0 +1,316 @@
|
|||||||
|
// 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
|
||||||
|
}
|
22
vendor/github.com/cespare/xxhash/v2/LICENSE.txt
generated
vendored
Normal file
22
vendor/github.com/cespare/xxhash/v2/LICENSE.txt
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
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.
|
69
vendor/github.com/cespare/xxhash/v2/README.md
generated
vendored
Normal file
69
vendor/github.com/cespare/xxhash/v2/README.md
generated
vendored
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
# xxhash
|
||||||
|
|
||||||
|
[](https://pkg.go.dev/github.com/cespare/xxhash/v2)
|
||||||
|
[](https://github.com/cespare/xxhash/actions/workflows/test.yml)
|
||||||
|
|
||||||
|
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)
|
||||||
|
- [VictoriaMetrics](https://github.com/VictoriaMetrics/VictoriaMetrics)
|
||||||
|
- [FreeCache](https://github.com/coocood/freecache)
|
||||||
|
- [FastCache](https://github.com/VictoriaMetrics/fastcache)
|
235
vendor/github.com/cespare/xxhash/v2/xxhash.go
generated
vendored
Normal file
235
vendor/github.com/cespare/xxhash/v2/xxhash.go
generated
vendored
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
// 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)
|
||||||
|
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
Normal file
13
vendor/github.com/cespare/xxhash/v2/xxhash_amd64.go
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// +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
Normal file
215
vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s
generated
vendored
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
// +build !appengine
|
||||||
|
// +build gc
|
||||||
|
// +build !purego
|
||||||
|
|
||||||
|
#include "textflag.h"
|
||||||
|
|
||||||
|
// Register allocation:
|
||||||
|
// AX h
|
||||||
|
// SI 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
|
||||||
|
// DI prime4v
|
||||||
|
|
||||||
|
// round reads from and advances the buffer pointer in SI.
|
||||||
|
// It assumes that R13 has prime1v and R14 has prime2v.
|
||||||
|
#define round(r) \
|
||||||
|
MOVQ (SI), R12 \
|
||||||
|
ADDQ $8, SI \
|
||||||
|
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 DI has prime4v.
|
||||||
|
#define mergeRound(acc, val) \
|
||||||
|
IMULQ R14, val \
|
||||||
|
ROLQ $31, val \
|
||||||
|
IMULQ R13, val \
|
||||||
|
XORQ val, acc \
|
||||||
|
IMULQ R13, acc \
|
||||||
|
ADDQ DI, 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), DI
|
||||||
|
|
||||||
|
// Load slice.
|
||||||
|
MOVQ b_base+0(FP), SI
|
||||||
|
MOVQ b_len+8(FP), DX
|
||||||
|
LEAQ (SI)(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 SI > BX.
|
||||||
|
blockLoop:
|
||||||
|
round(R8)
|
||||||
|
round(R9)
|
||||||
|
round(R10)
|
||||||
|
round(R11)
|
||||||
|
|
||||||
|
CMPQ SI, 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 SI > len(b)-8.
|
||||||
|
ADDQ $24, BX
|
||||||
|
|
||||||
|
CMPQ SI, BX
|
||||||
|
JG fourByte
|
||||||
|
|
||||||
|
wordLoop:
|
||||||
|
// Calculate k1.
|
||||||
|
MOVQ (SI), R8
|
||||||
|
ADDQ $8, SI
|
||||||
|
IMULQ R14, R8
|
||||||
|
ROLQ $31, R8
|
||||||
|
IMULQ R13, R8
|
||||||
|
|
||||||
|
XORQ R8, AX
|
||||||
|
ROLQ $27, AX
|
||||||
|
IMULQ R13, AX
|
||||||
|
ADDQ DI, AX
|
||||||
|
|
||||||
|
CMPQ SI, BX
|
||||||
|
JLE wordLoop
|
||||||
|
|
||||||
|
fourByte:
|
||||||
|
ADDQ $4, BX
|
||||||
|
CMPQ SI, BX
|
||||||
|
JG singles
|
||||||
|
|
||||||
|
MOVL (SI), R8
|
||||||
|
ADDQ $4, SI
|
||||||
|
IMULQ R13, R8
|
||||||
|
XORQ R8, AX
|
||||||
|
|
||||||
|
ROLQ $23, AX
|
||||||
|
IMULQ R14, AX
|
||||||
|
ADDQ ·prime3v(SB), AX
|
||||||
|
|
||||||
|
singles:
|
||||||
|
ADDQ $4, BX
|
||||||
|
CMPQ SI, BX
|
||||||
|
JGE finalize
|
||||||
|
|
||||||
|
singlesLoop:
|
||||||
|
MOVBQZX (SI), R12
|
||||||
|
ADDQ $1, SI
|
||||||
|
IMULQ ·prime5v(SB), R12
|
||||||
|
XORQ R12, AX
|
||||||
|
|
||||||
|
ROLQ $11, AX
|
||||||
|
IMULQ R13, AX
|
||||||
|
|
||||||
|
CMPQ SI, 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), SI
|
||||||
|
MOVQ b_len+16(FP), DX
|
||||||
|
LEAQ (SI)(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 SI, 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 SI minus the old base pointer.
|
||||||
|
SUBQ b_base+8(FP), SI
|
||||||
|
MOVQ SI, ret+32(FP)
|
||||||
|
|
||||||
|
RET
|
76
vendor/github.com/cespare/xxhash/v2/xxhash_other.go
generated
vendored
Normal file
76
vendor/github.com/cespare/xxhash/v2/xxhash_other.go
generated
vendored
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
// +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
Normal file
15
vendor/github.com/cespare/xxhash/v2/xxhash_safe.go
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// +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))
|
||||||
|
}
|
57
vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go
generated
vendored
Normal file
57
vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go
generated
vendored
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
// +build !appengine
|
||||||
|
|
||||||
|
// This file encapsulates usage of unsafe.
|
||||||
|
// xxhash_safe.go contains the safe implementations.
|
||||||
|
|
||||||
|
package xxhash
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// In the future it's possible that compiler optimizations will make these
|
||||||
|
// XxxString functions unnecessary by realizing that calls such as
|
||||||
|
// Sum64([]byte(s)) don't need to copy s. See https://golang.org/issue/2205.
|
||||||
|
// If that happens, even if we keep these functions they can be replaced with
|
||||||
|
// the trivial safe code.
|
||||||
|
|
||||||
|
// NOTE: The usual way of doing an unsafe string-to-[]byte conversion is:
|
||||||
|
//
|
||||||
|
// 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)
|
||||||
|
//
|
||||||
|
// Unfortunately, as of Go 1.15.3 the inliner's cost model assigns a high enough
|
||||||
|
// weight to this sequence of expressions that any function that uses it will
|
||||||
|
// not be inlined. Instead, the functions below use a different unsafe
|
||||||
|
// conversion designed to minimize the inliner weight and allow both to be
|
||||||
|
// inlined. There is also a test (TestInlining) which verifies that these are
|
||||||
|
// inlined.
|
||||||
|
//
|
||||||
|
// See https://github.com/golang/go/issues/42739 for discussion.
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
b := *(*[]byte)(unsafe.Pointer(&sliceHeader{s, 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) {
|
||||||
|
d.Write(*(*[]byte)(unsafe.Pointer(&sliceHeader{s, len(s)})))
|
||||||
|
// d.Write always returns len(s), nil.
|
||||||
|
// Ignoring the return output and returning these fixed values buys a
|
||||||
|
// savings of 6 in the inliner's cost model.
|
||||||
|
return len(s), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// sliceHeader is similar to reflect.SliceHeader, but it assumes that the layout
|
||||||
|
// of the first two words is the same as the layout of a string.
|
||||||
|
type sliceHeader struct {
|
||||||
|
s string
|
||||||
|
cap int
|
||||||
|
}
|
12
vendor/github.com/fsnotify/fsnotify/.editorconfig
generated
vendored
Normal file
12
vendor/github.com/fsnotify/fsnotify/.editorconfig
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*.go]
|
||||||
|
indent_style = tab
|
||||||
|
indent_size = 4
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.{yml,yaml}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
1
vendor/github.com/fsnotify/fsnotify/.gitattributes
generated
vendored
Normal file
1
vendor/github.com/fsnotify/fsnotify/.gitattributes
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
go.sum linguist-generated
|
6
vendor/github.com/fsnotify/fsnotify/.gitignore
generated
vendored
Normal file
6
vendor/github.com/fsnotify/fsnotify/.gitignore
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# Setup a Global .gitignore for OS and editor generated files:
|
||||||
|
# https://help.github.com/articles/ignoring-files
|
||||||
|
# git config --global core.excludesfile ~/.gitignore_global
|
||||||
|
|
||||||
|
.vagrant
|
||||||
|
*.sublime-project
|
36
vendor/github.com/fsnotify/fsnotify/.travis.yml
generated
vendored
Normal file
36
vendor/github.com/fsnotify/fsnotify/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
sudo: false
|
||||||
|
language: go
|
||||||
|
|
||||||
|
go:
|
||||||
|
- "stable"
|
||||||
|
- "1.11.x"
|
||||||
|
- "1.10.x"
|
||||||
|
- "1.9.x"
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- go: "stable"
|
||||||
|
env: GOLINT=true
|
||||||
|
allow_failures:
|
||||||
|
- go: tip
|
||||||
|
fast_finish: true
|
||||||
|
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
- if [ ! -z "${GOLINT}" ]; then go get -u golang.org/x/lint/golint; fi
|
||||||
|
|
||||||
|
script:
|
||||||
|
- go test --race ./...
|
||||||
|
|
||||||
|
after_script:
|
||||||
|
- test -z "$(gofmt -s -l -w . | tee /dev/stderr)"
|
||||||
|
- if [ ! -z "${GOLINT}" ]; then echo running golint; golint --set_exit_status ./...; else echo skipping golint; fi
|
||||||
|
- go vet ./...
|
||||||
|
|
||||||
|
os:
|
||||||
|
- linux
|
||||||
|
- osx
|
||||||
|
- windows
|
||||||
|
|
||||||
|
notifications:
|
||||||
|
email: false
|
52
vendor/github.com/fsnotify/fsnotify/AUTHORS
generated
vendored
Normal file
52
vendor/github.com/fsnotify/fsnotify/AUTHORS
generated
vendored
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
# Names should be added to this file as
|
||||||
|
# Name or Organization <email address>
|
||||||
|
# The email address is not required for organizations.
|
||||||
|
|
||||||
|
# You can update this list using the following command:
|
||||||
|
#
|
||||||
|
# $ git shortlog -se | awk '{print $2 " " $3 " " $4}'
|
||||||
|
|
||||||
|
# Please keep the list sorted.
|
||||||
|
|
||||||
|
Aaron L <aaron@bettercoder.net>
|
||||||
|
Adrien Bustany <adrien@bustany.org>
|
||||||
|
Amit Krishnan <amit.krishnan@oracle.com>
|
||||||
|
Anmol Sethi <me@anmol.io>
|
||||||
|
Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
|
||||||
|
Bruno Bigras <bigras.bruno@gmail.com>
|
||||||
|
Caleb Spare <cespare@gmail.com>
|
||||||
|
Case Nelson <case@teammating.com>
|
||||||
|
Chris Howey <chris@howey.me> <howeyc@gmail.com>
|
||||||
|
Christoffer Buchholz <christoffer.buchholz@gmail.com>
|
||||||
|
Daniel Wagner-Hall <dawagner@gmail.com>
|
||||||
|
Dave Cheney <dave@cheney.net>
|
||||||
|
Evan Phoenix <evan@fallingsnow.net>
|
||||||
|
Francisco Souza <f@souza.cc>
|
||||||
|
Hari haran <hariharan.uno@gmail.com>
|
||||||
|
John C Barstow
|
||||||
|
Kelvin Fo <vmirage@gmail.com>
|
||||||
|
Ken-ichirou MATSUZAWA <chamas@h4.dion.ne.jp>
|
||||||
|
Matt Layher <mdlayher@gmail.com>
|
||||||
|
Nathan Youngman <git@nathany.com>
|
||||||
|
Nickolai Zeldovich <nickolai@csail.mit.edu>
|
||||||
|
Patrick <patrick@dropbox.com>
|
||||||
|
Paul Hammond <paul@paulhammond.org>
|
||||||
|
Pawel Knap <pawelknap88@gmail.com>
|
||||||
|
Pieter Droogendijk <pieter@binky.org.uk>
|
||||||
|
Pursuit92 <JoshChase@techpursuit.net>
|
||||||
|
Riku Voipio <riku.voipio@linaro.org>
|
||||||
|
Rob Figueiredo <robfig@gmail.com>
|
||||||
|
Rodrigo Chiossi <rodrigochiossi@gmail.com>
|
||||||
|
Slawek Ligus <root@ooz.ie>
|
||||||
|
Soge Zhang <zhssoge@gmail.com>
|
||||||
|
Tiffany Jernigan <tiffany.jernigan@intel.com>
|
||||||
|
Tilak Sharma <tilaks@google.com>
|
||||||
|
Tom Payne <twpayne@gmail.com>
|
||||||
|
Travis Cline <travis.cline@gmail.com>
|
||||||
|
Tudor Golubenco <tudor.g@gmail.com>
|
||||||
|
Vahe Khachikyan <vahe@live.ca>
|
||||||
|
Yukang <moorekang@gmail.com>
|
||||||
|
bronze1man <bronze1man@gmail.com>
|
||||||
|
debrando <denis.brandolini@gmail.com>
|
||||||
|
henrikedwards <henrik.edwards@gmail.com>
|
||||||
|
铁哥 <guotie.9@gmail.com>
|
317
vendor/github.com/fsnotify/fsnotify/CHANGELOG.md
generated
vendored
Normal file
317
vendor/github.com/fsnotify/fsnotify/CHANGELOG.md
generated
vendored
Normal file
@ -0,0 +1,317 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
## v1.4.7 / 2018-01-09
|
||||||
|
|
||||||
|
* BSD/macOS: Fix possible deadlock on closing the watcher on kqueue (thanks @nhooyr and @glycerine)
|
||||||
|
* Tests: Fix missing verb on format string (thanks @rchiossi)
|
||||||
|
* Linux: Fix deadlock in Remove (thanks @aarondl)
|
||||||
|
* Linux: Watch.Add improvements (avoid race, fix consistency, reduce garbage) (thanks @twpayne)
|
||||||
|
* Docs: Moved FAQ into the README (thanks @vahe)
|
||||||
|
* Linux: Properly handle inotify's IN_Q_OVERFLOW event (thanks @zeldovich)
|
||||||
|
* Docs: replace references to OS X with macOS
|
||||||
|
|
||||||
|
## v1.4.2 / 2016-10-10
|
||||||
|
|
||||||
|
* Linux: use InotifyInit1 with IN_CLOEXEC to stop leaking a file descriptor to a child process when using fork/exec [#178](https://github.com/fsnotify/fsnotify/pull/178) (thanks @pattyshack)
|
||||||
|
|
||||||
|
## v1.4.1 / 2016-10-04
|
||||||
|
|
||||||
|
* Fix flaky inotify stress test on Linux [#177](https://github.com/fsnotify/fsnotify/pull/177) (thanks @pattyshack)
|
||||||
|
|
||||||
|
## v1.4.0 / 2016-10-01
|
||||||
|
|
||||||
|
* add a String() method to Event.Op [#165](https://github.com/fsnotify/fsnotify/pull/165) (thanks @oozie)
|
||||||
|
|
||||||
|
## v1.3.1 / 2016-06-28
|
||||||
|
|
||||||
|
* Windows: fix for double backslash when watching the root of a drive [#151](https://github.com/fsnotify/fsnotify/issues/151) (thanks @brunoqc)
|
||||||
|
|
||||||
|
## v1.3.0 / 2016-04-19
|
||||||
|
|
||||||
|
* Support linux/arm64 by [patching](https://go-review.googlesource.com/#/c/21971/) x/sys/unix and switching to to it from syscall (thanks @suihkulokki) [#135](https://github.com/fsnotify/fsnotify/pull/135)
|
||||||
|
|
||||||
|
## v1.2.10 / 2016-03-02
|
||||||
|
|
||||||
|
* Fix golint errors in windows.go [#121](https://github.com/fsnotify/fsnotify/pull/121) (thanks @tiffanyfj)
|
||||||
|
|
||||||
|
## v1.2.9 / 2016-01-13
|
||||||
|
|
||||||
|
kqueue: Fix logic for CREATE after REMOVE [#111](https://github.com/fsnotify/fsnotify/pull/111) (thanks @bep)
|
||||||
|
|
||||||
|
## v1.2.8 / 2015-12-17
|
||||||
|
|
||||||
|
* kqueue: fix race condition in Close [#105](https://github.com/fsnotify/fsnotify/pull/105) (thanks @djui for reporting the issue and @ppknap for writing a failing test)
|
||||||
|
* inotify: fix race in test
|
||||||
|
* enable race detection for continuous integration (Linux, Mac, Windows)
|
||||||
|
|
||||||
|
## v1.2.5 / 2015-10-17
|
||||||
|
|
||||||
|
* inotify: use epoll_create1 for arm64 support (requires Linux 2.6.27 or later) [#100](https://github.com/fsnotify/fsnotify/pull/100) (thanks @suihkulokki)
|
||||||
|
* inotify: fix path leaks [#73](https://github.com/fsnotify/fsnotify/pull/73) (thanks @chamaken)
|
||||||
|
* kqueue: watch for rename events on subdirectories [#83](https://github.com/fsnotify/fsnotify/pull/83) (thanks @guotie)
|
||||||
|
* kqueue: avoid infinite loops from symlinks cycles [#101](https://github.com/fsnotify/fsnotify/pull/101) (thanks @illicitonion)
|
||||||
|
|
||||||
|
## v1.2.1 / 2015-10-14
|
||||||
|
|
||||||
|
* kqueue: don't watch named pipes [#98](https://github.com/fsnotify/fsnotify/pull/98) (thanks @evanphx)
|
||||||
|
|
||||||
|
## v1.2.0 / 2015-02-08
|
||||||
|
|
||||||
|
* inotify: use epoll to wake up readEvents [#66](https://github.com/fsnotify/fsnotify/pull/66) (thanks @PieterD)
|
||||||
|
* inotify: closing watcher should now always shut down goroutine [#63](https://github.com/fsnotify/fsnotify/pull/63) (thanks @PieterD)
|
||||||
|
* kqueue: close kqueue after removing watches, fixes [#59](https://github.com/fsnotify/fsnotify/issues/59)
|
||||||
|
|
||||||
|
## v1.1.1 / 2015-02-05
|
||||||
|
|
||||||
|
* inotify: Retry read on EINTR [#61](https://github.com/fsnotify/fsnotify/issues/61) (thanks @PieterD)
|
||||||
|
|
||||||
|
## v1.1.0 / 2014-12-12
|
||||||
|
|
||||||
|
* kqueue: rework internals [#43](https://github.com/fsnotify/fsnotify/pull/43)
|
||||||
|
* add low-level functions
|
||||||
|
* only need to store flags on directories
|
||||||
|
* less mutexes [#13](https://github.com/fsnotify/fsnotify/issues/13)
|
||||||
|
* done can be an unbuffered channel
|
||||||
|
* remove calls to os.NewSyscallError
|
||||||
|
* More efficient string concatenation for Event.String() [#52](https://github.com/fsnotify/fsnotify/pull/52) (thanks @mdlayher)
|
||||||
|
* kqueue: fix regression in rework causing subdirectories to be watched [#48](https://github.com/fsnotify/fsnotify/issues/48)
|
||||||
|
* kqueue: cleanup internal watch before sending remove event [#51](https://github.com/fsnotify/fsnotify/issues/51)
|
||||||
|
|
||||||
|
## v1.0.4 / 2014-09-07
|
||||||
|
|
||||||
|
* kqueue: add dragonfly to the build tags.
|
||||||
|
* Rename source code files, rearrange code so exported APIs are at the top.
|
||||||
|
* Add done channel to example code. [#37](https://github.com/fsnotify/fsnotify/pull/37) (thanks @chenyukang)
|
||||||
|
|
||||||
|
## v1.0.3 / 2014-08-19
|
||||||
|
|
||||||
|
* [Fix] Windows MOVED_TO now translates to Create like on BSD and Linux. [#36](https://github.com/fsnotify/fsnotify/issues/36)
|
||||||
|
|
||||||
|
## v1.0.2 / 2014-08-17
|
||||||
|
|
||||||
|
* [Fix] Missing create events on macOS. [#14](https://github.com/fsnotify/fsnotify/issues/14) (thanks @zhsso)
|
||||||
|
* [Fix] Make ./path and path equivalent. (thanks @zhsso)
|
||||||
|
|
||||||
|
## v1.0.0 / 2014-08-15
|
||||||
|
|
||||||
|
* [API] Remove AddWatch on Windows, use Add.
|
||||||
|
* Improve documentation for exported identifiers. [#30](https://github.com/fsnotify/fsnotify/issues/30)
|
||||||
|
* Minor updates based on feedback from golint.
|
||||||
|
|
||||||
|
## dev / 2014-07-09
|
||||||
|
|
||||||
|
* Moved to [github.com/fsnotify/fsnotify](https://github.com/fsnotify/fsnotify).
|
||||||
|
* Use os.NewSyscallError instead of returning errno (thanks @hariharan-uno)
|
||||||
|
|
||||||
|
## dev / 2014-07-04
|
||||||
|
|
||||||
|
* kqueue: fix incorrect mutex used in Close()
|
||||||
|
* Update example to demonstrate usage of Op.
|
||||||
|
|
||||||
|
## dev / 2014-06-28
|
||||||
|
|
||||||
|
* [API] Don't set the Write Op for attribute notifications [#4](https://github.com/fsnotify/fsnotify/issues/4)
|
||||||
|
* Fix for String() method on Event (thanks Alex Brainman)
|
||||||
|
* Don't build on Plan 9 or Solaris (thanks @4ad)
|
||||||
|
|
||||||
|
## dev / 2014-06-21
|
||||||
|
|
||||||
|
* Events channel of type Event rather than *Event.
|
||||||
|
* [internal] use syscall constants directly for inotify and kqueue.
|
||||||
|
* [internal] kqueue: rename events to kevents and fileEvent to event.
|
||||||
|
|
||||||
|
## dev / 2014-06-19
|
||||||
|
|
||||||
|
* Go 1.3+ required on Windows (uses syscall.ERROR_MORE_DATA internally).
|
||||||
|
* [internal] remove cookie from Event struct (unused).
|
||||||
|
* [internal] Event struct has the same definition across every OS.
|
||||||
|
* [internal] remove internal watch and removeWatch methods.
|
||||||
|
|
||||||
|
## dev / 2014-06-12
|
||||||
|
|
||||||
|
* [API] Renamed Watch() to Add() and RemoveWatch() to Remove().
|
||||||
|
* [API] Pluralized channel names: Events and Errors.
|
||||||
|
* [API] Renamed FileEvent struct to Event.
|
||||||
|
* [API] Op constants replace methods like IsCreate().
|
||||||
|
|
||||||
|
## dev / 2014-06-12
|
||||||
|
|
||||||
|
* Fix data race on kevent buffer (thanks @tilaks) [#98](https://github.com/howeyc/fsnotify/pull/98)
|
||||||
|
|
||||||
|
## dev / 2014-05-23
|
||||||
|
|
||||||
|
* [API] Remove current implementation of WatchFlags.
|
||||||
|
* current implementation doesn't take advantage of OS for efficiency
|
||||||
|
* provides little benefit over filtering events as they are received, but has extra bookkeeping and mutexes
|
||||||
|
* no tests for the current implementation
|
||||||
|
* not fully implemented on Windows [#93](https://github.com/howeyc/fsnotify/issues/93#issuecomment-39285195)
|
||||||
|
|
||||||
|
## v0.9.3 / 2014-12-31
|
||||||
|
|
||||||
|
* kqueue: cleanup internal watch before sending remove event [#51](https://github.com/fsnotify/fsnotify/issues/51)
|
||||||
|
|
||||||
|
## v0.9.2 / 2014-08-17
|
||||||
|
|
||||||
|
* [Backport] Fix missing create events on macOS. [#14](https://github.com/fsnotify/fsnotify/issues/14) (thanks @zhsso)
|
||||||
|
|
||||||
|
## v0.9.1 / 2014-06-12
|
||||||
|
|
||||||
|
* Fix data race on kevent buffer (thanks @tilaks) [#98](https://github.com/howeyc/fsnotify/pull/98)
|
||||||
|
|
||||||
|
## v0.9.0 / 2014-01-17
|
||||||
|
|
||||||
|
* IsAttrib() for events that only concern a file's metadata [#79][] (thanks @abustany)
|
||||||
|
* [Fix] kqueue: fix deadlock [#77][] (thanks @cespare)
|
||||||
|
* [NOTICE] Development has moved to `code.google.com/p/go.exp/fsnotify` in preparation for inclusion in the Go standard library.
|
||||||
|
|
||||||
|
## v0.8.12 / 2013-11-13
|
||||||
|
|
||||||
|
* [API] Remove FD_SET and friends from Linux adapter
|
||||||
|
|
||||||
|
## v0.8.11 / 2013-11-02
|
||||||
|
|
||||||
|
* [Doc] Add Changelog [#72][] (thanks @nathany)
|
||||||
|
* [Doc] Spotlight and double modify events on macOS [#62][] (reported by @paulhammond)
|
||||||
|
|
||||||
|
## v0.8.10 / 2013-10-19
|
||||||
|
|
||||||
|
* [Fix] kqueue: remove file watches when parent directory is removed [#71][] (reported by @mdwhatcott)
|
||||||
|
* [Fix] kqueue: race between Close and readEvents [#70][] (reported by @bernerdschaefer)
|
||||||
|
* [Doc] specify OS-specific limits in README (thanks @debrando)
|
||||||
|
|
||||||
|
## v0.8.9 / 2013-09-08
|
||||||
|
|
||||||
|
* [Doc] Contributing (thanks @nathany)
|
||||||
|
* [Doc] update package path in example code [#63][] (thanks @paulhammond)
|
||||||
|
* [Doc] GoCI badge in README (Linux only) [#60][]
|
||||||
|
* [Doc] Cross-platform testing with Vagrant [#59][] (thanks @nathany)
|
||||||
|
|
||||||
|
## v0.8.8 / 2013-06-17
|
||||||
|
|
||||||
|
* [Fix] Windows: handle `ERROR_MORE_DATA` on Windows [#49][] (thanks @jbowtie)
|
||||||
|
|
||||||
|
## v0.8.7 / 2013-06-03
|
||||||
|
|
||||||
|
* [API] Make syscall flags internal
|
||||||
|
* [Fix] inotify: ignore event changes
|
||||||
|
* [Fix] race in symlink test [#45][] (reported by @srid)
|
||||||
|
* [Fix] tests on Windows
|
||||||
|
* lower case error messages
|
||||||
|
|
||||||
|
## v0.8.6 / 2013-05-23
|
||||||
|
|
||||||
|
* kqueue: Use EVT_ONLY flag on Darwin
|
||||||
|
* [Doc] Update README with full example
|
||||||
|
|
||||||
|
## v0.8.5 / 2013-05-09
|
||||||
|
|
||||||
|
* [Fix] inotify: allow monitoring of "broken" symlinks (thanks @tsg)
|
||||||
|
|
||||||
|
## v0.8.4 / 2013-04-07
|
||||||
|
|
||||||
|
* [Fix] kqueue: watch all file events [#40][] (thanks @ChrisBuchholz)
|
||||||
|
|
||||||
|
## v0.8.3 / 2013-03-13
|
||||||
|
|
||||||
|
* [Fix] inoitfy/kqueue memory leak [#36][] (reported by @nbkolchin)
|
||||||
|
* [Fix] kqueue: use fsnFlags for watching a directory [#33][] (reported by @nbkolchin)
|
||||||
|
|
||||||
|
## v0.8.2 / 2013-02-07
|
||||||
|
|
||||||
|
* [Doc] add Authors
|
||||||
|
* [Fix] fix data races for map access [#29][] (thanks @fsouza)
|
||||||
|
|
||||||
|
## v0.8.1 / 2013-01-09
|
||||||
|
|
||||||
|
* [Fix] Windows path separators
|
||||||
|
* [Doc] BSD License
|
||||||
|
|
||||||
|
## v0.8.0 / 2012-11-09
|
||||||
|
|
||||||
|
* kqueue: directory watching improvements (thanks @vmirage)
|
||||||
|
* inotify: add `IN_MOVED_TO` [#25][] (requested by @cpisto)
|
||||||
|
* [Fix] kqueue: deleting watched directory [#24][] (reported by @jakerr)
|
||||||
|
|
||||||
|
## v0.7.4 / 2012-10-09
|
||||||
|
|
||||||
|
* [Fix] inotify: fixes from https://codereview.appspot.com/5418045/ (ugorji)
|
||||||
|
* [Fix] kqueue: preserve watch flags when watching for delete [#21][] (reported by @robfig)
|
||||||
|
* [Fix] kqueue: watch the directory even if it isn't a new watch (thanks @robfig)
|
||||||
|
* [Fix] kqueue: modify after recreation of file
|
||||||
|
|
||||||
|
## v0.7.3 / 2012-09-27
|
||||||
|
|
||||||
|
* [Fix] kqueue: watch with an existing folder inside the watched folder (thanks @vmirage)
|
||||||
|
* [Fix] kqueue: no longer get duplicate CREATE events
|
||||||
|
|
||||||
|
## v0.7.2 / 2012-09-01
|
||||||
|
|
||||||
|
* kqueue: events for created directories
|
||||||
|
|
||||||
|
## v0.7.1 / 2012-07-14
|
||||||
|
|
||||||
|
* [Fix] for renaming files
|
||||||
|
|
||||||
|
## v0.7.0 / 2012-07-02
|
||||||
|
|
||||||
|
* [Feature] FSNotify flags
|
||||||
|
* [Fix] inotify: Added file name back to event path
|
||||||
|
|
||||||
|
## v0.6.0 / 2012-06-06
|
||||||
|
|
||||||
|
* kqueue: watch files after directory created (thanks @tmc)
|
||||||
|
|
||||||
|
## v0.5.1 / 2012-05-22
|
||||||
|
|
||||||
|
* [Fix] inotify: remove all watches before Close()
|
||||||
|
|
||||||
|
## v0.5.0 / 2012-05-03
|
||||||
|
|
||||||
|
* [API] kqueue: return errors during watch instead of sending over channel
|
||||||
|
* kqueue: match symlink behavior on Linux
|
||||||
|
* inotify: add `DELETE_SELF` (requested by @taralx)
|
||||||
|
* [Fix] kqueue: handle EINTR (reported by @robfig)
|
||||||
|
* [Doc] Godoc example [#1][] (thanks @davecheney)
|
||||||
|
|
||||||
|
## v0.4.0 / 2012-03-30
|
||||||
|
|
||||||
|
* Go 1 released: build with go tool
|
||||||
|
* [Feature] Windows support using winfsnotify
|
||||||
|
* Windows does not have attribute change notifications
|
||||||
|
* Roll attribute notifications into IsModify
|
||||||
|
|
||||||
|
## v0.3.0 / 2012-02-19
|
||||||
|
|
||||||
|
* kqueue: add files when watch directory
|
||||||
|
|
||||||
|
## v0.2.0 / 2011-12-30
|
||||||
|
|
||||||
|
* update to latest Go weekly code
|
||||||
|
|
||||||
|
## v0.1.0 / 2011-10-19
|
||||||
|
|
||||||
|
* kqueue: add watch on file creation to match inotify
|
||||||
|
* kqueue: create file event
|
||||||
|
* inotify: ignore `IN_IGNORED` events
|
||||||
|
* event String()
|
||||||
|
* linux: common FileEvent functions
|
||||||
|
* initial commit
|
||||||
|
|
||||||
|
[#79]: https://github.com/howeyc/fsnotify/pull/79
|
||||||
|
[#77]: https://github.com/howeyc/fsnotify/pull/77
|
||||||
|
[#72]: https://github.com/howeyc/fsnotify/issues/72
|
||||||
|
[#71]: https://github.com/howeyc/fsnotify/issues/71
|
||||||
|
[#70]: https://github.com/howeyc/fsnotify/issues/70
|
||||||
|
[#63]: https://github.com/howeyc/fsnotify/issues/63
|
||||||
|
[#62]: https://github.com/howeyc/fsnotify/issues/62
|
||||||
|
[#60]: https://github.com/howeyc/fsnotify/issues/60
|
||||||
|
[#59]: https://github.com/howeyc/fsnotify/issues/59
|
||||||
|
[#49]: https://github.com/howeyc/fsnotify/issues/49
|
||||||
|
[#45]: https://github.com/howeyc/fsnotify/issues/45
|
||||||
|
[#40]: https://github.com/howeyc/fsnotify/issues/40
|
||||||
|
[#36]: https://github.com/howeyc/fsnotify/issues/36
|
||||||
|
[#33]: https://github.com/howeyc/fsnotify/issues/33
|
||||||
|
[#29]: https://github.com/howeyc/fsnotify/issues/29
|
||||||
|
[#25]: https://github.com/howeyc/fsnotify/issues/25
|
||||||
|
[#24]: https://github.com/howeyc/fsnotify/issues/24
|
||||||
|
[#21]: https://github.com/howeyc/fsnotify/issues/21
|
77
vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md
generated
vendored
Normal file
77
vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md
generated
vendored
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
# Contributing
|
||||||
|
|
||||||
|
## Issues
|
||||||
|
|
||||||
|
* Request features and report bugs using the [GitHub Issue Tracker](https://github.com/fsnotify/fsnotify/issues).
|
||||||
|
* Please indicate the platform you are using fsnotify on.
|
||||||
|
* A code example to reproduce the problem is appreciated.
|
||||||
|
|
||||||
|
## Pull Requests
|
||||||
|
|
||||||
|
### Contributor License Agreement
|
||||||
|
|
||||||
|
fsnotify is derived from code in the [golang.org/x/exp](https://godoc.org/golang.org/x/exp) package and it may be included [in the standard library](https://github.com/fsnotify/fsnotify/issues/1) in the future. Therefore fsnotify carries the same [LICENSE](https://github.com/fsnotify/fsnotify/blob/master/LICENSE) as Go. Contributors retain their copyright, so you need to fill out a short form before we can accept your contribution: [Google Individual Contributor License Agreement](https://developers.google.com/open-source/cla/individual).
|
||||||
|
|
||||||
|
Please indicate that you have signed the CLA in your pull request.
|
||||||
|
|
||||||
|
### How fsnotify is Developed
|
||||||
|
|
||||||
|
* Development is done on feature branches.
|
||||||
|
* Tests are run on BSD, Linux, macOS and Windows.
|
||||||
|
* Pull requests are reviewed and [applied to master][am] using [hub][].
|
||||||
|
* Maintainers may modify or squash commits rather than asking contributors to.
|
||||||
|
* To issue a new release, the maintainers will:
|
||||||
|
* Update the CHANGELOG
|
||||||
|
* Tag a version, which will become available through gopkg.in.
|
||||||
|
|
||||||
|
### How to Fork
|
||||||
|
|
||||||
|
For smooth sailing, always use the original import path. Installing with `go get` makes this easy.
|
||||||
|
|
||||||
|
1. Install from GitHub (`go get -u github.com/fsnotify/fsnotify`)
|
||||||
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
||||||
|
3. Ensure everything works and the tests pass (see below)
|
||||||
|
4. Commit your changes (`git commit -am 'Add some feature'`)
|
||||||
|
|
||||||
|
Contribute upstream:
|
||||||
|
|
||||||
|
1. Fork fsnotify on GitHub
|
||||||
|
2. Add your remote (`git remote add fork git@github.com:mycompany/repo.git`)
|
||||||
|
3. Push to the branch (`git push fork my-new-feature`)
|
||||||
|
4. Create a new Pull Request on GitHub
|
||||||
|
|
||||||
|
This workflow is [thoroughly explained by Katrina Owen](https://splice.com/blog/contributing-open-source-git-repositories-go/).
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
|
||||||
|
fsnotify uses build tags to compile different code on Linux, BSD, macOS, and Windows.
|
||||||
|
|
||||||
|
Before doing a pull request, please do your best to test your changes on multiple platforms, and list which platforms you were able/unable to test on.
|
||||||
|
|
||||||
|
To aid in cross-platform testing there is a Vagrantfile for Linux and BSD.
|
||||||
|
|
||||||
|
* Install [Vagrant](http://www.vagrantup.com/) and [VirtualBox](https://www.virtualbox.org/)
|
||||||
|
* Setup [Vagrant Gopher](https://github.com/nathany/vagrant-gopher) in your `src` folder.
|
||||||
|
* Run `vagrant up` from the project folder. You can also setup just one box with `vagrant up linux` or `vagrant up bsd` (note: the BSD box doesn't support Windows hosts at this time, and NFS may prompt for your host OS password)
|
||||||
|
* Once setup, you can run the test suite on a given OS with a single command `vagrant ssh linux -c 'cd fsnotify/fsnotify; go test'`.
|
||||||
|
* When you're done, you will want to halt or destroy the Vagrant boxes.
|
||||||
|
|
||||||
|
Notice: fsnotify file system events won't trigger in shared folders. The tests get around this limitation by using the /tmp directory.
|
||||||
|
|
||||||
|
Right now there is no equivalent solution for Windows and macOS, but there are Windows VMs [freely available from Microsoft](http://www.modern.ie/en-us/virtualization-tools#downloads).
|
||||||
|
|
||||||
|
### Maintainers
|
||||||
|
|
||||||
|
Help maintaining fsnotify is welcome. To be a maintainer:
|
||||||
|
|
||||||
|
* Submit a pull request and sign the CLA as above.
|
||||||
|
* You must be able to run the test suite on Mac, Windows, Linux and BSD.
|
||||||
|
|
||||||
|
To keep master clean, the fsnotify project uses the "apply mail" workflow outlined in Nathaniel Talbott's post ["Merge pull request" Considered Harmful][am]. This requires installing [hub][].
|
||||||
|
|
||||||
|
All code changes should be internal pull requests.
|
||||||
|
|
||||||
|
Releases are tagged using [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
|
[hub]: https://github.com/github/hub
|
||||||
|
[am]: http://blog.spreedly.com/2014/06/24/merge-pull-request-considered-harmful/#.VGa5yZPF_Zs
|
28
vendor/github.com/fsnotify/fsnotify/LICENSE
generated
vendored
Normal file
28
vendor/github.com/fsnotify/fsnotify/LICENSE
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||||
|
Copyright (c) 2012-2019 fsnotify 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.
|
130
vendor/github.com/fsnotify/fsnotify/README.md
generated
vendored
Normal file
130
vendor/github.com/fsnotify/fsnotify/README.md
generated
vendored
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
# File system notifications for Go
|
||||||
|
|
||||||
|
[](https://godoc.org/github.com/fsnotify/fsnotify) [](https://goreportcard.com/report/github.com/fsnotify/fsnotify)
|
||||||
|
|
||||||
|
fsnotify utilizes [golang.org/x/sys](https://godoc.org/golang.org/x/sys) rather than `syscall` from the standard library. Ensure you have the latest version installed by running:
|
||||||
|
|
||||||
|
```console
|
||||||
|
go get -u golang.org/x/sys/...
|
||||||
|
```
|
||||||
|
|
||||||
|
Cross platform: Windows, Linux, BSD and macOS.
|
||||||
|
|
||||||
|
| Adapter | OS | Status |
|
||||||
|
| --------------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
|
| inotify | Linux 2.6.27 or later, Android\* | Supported [](https://travis-ci.org/fsnotify/fsnotify) |
|
||||||
|
| kqueue | BSD, macOS, iOS\* | Supported [](https://travis-ci.org/fsnotify/fsnotify) |
|
||||||
|
| ReadDirectoryChangesW | Windows | Supported [](https://travis-ci.org/fsnotify/fsnotify) |
|
||||||
|
| FSEvents | macOS | [Planned](https://github.com/fsnotify/fsnotify/issues/11) |
|
||||||
|
| FEN | Solaris 11 | [In Progress](https://github.com/fsnotify/fsnotify/issues/12) |
|
||||||
|
| fanotify | Linux 2.6.37+ | [Planned](https://github.com/fsnotify/fsnotify/issues/114) |
|
||||||
|
| USN Journals | Windows | [Maybe](https://github.com/fsnotify/fsnotify/issues/53) |
|
||||||
|
| Polling | *All* | [Maybe](https://github.com/fsnotify/fsnotify/issues/9) |
|
||||||
|
|
||||||
|
\* Android and iOS are untested.
|
||||||
|
|
||||||
|
Please see [the documentation](https://godoc.org/github.com/fsnotify/fsnotify) and consult the [FAQ](#faq) for usage information.
|
||||||
|
|
||||||
|
## API stability
|
||||||
|
|
||||||
|
fsnotify is a fork of [howeyc/fsnotify](https://godoc.org/github.com/howeyc/fsnotify) with a new API as of v1.0. The API is based on [this design document](http://goo.gl/MrYxyA).
|
||||||
|
|
||||||
|
All [releases](https://github.com/fsnotify/fsnotify/releases) are tagged based on [Semantic Versioning](http://semver.org/). Further API changes are [planned](https://github.com/fsnotify/fsnotify/milestones), and will be tagged with a new major revision number.
|
||||||
|
|
||||||
|
Go 1.6 supports dependencies located in the `vendor/` folder. Unless you are creating a library, it is recommended that you copy fsnotify into `vendor/github.com/fsnotify/fsnotify` within your project, and likewise for `golang.org/x/sys`.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/fsnotify/fsnotify"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
watcher, err := fsnotify.NewWatcher()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer watcher.Close()
|
||||||
|
|
||||||
|
done := make(chan bool)
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case event, ok := <-watcher.Events:
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Println("event:", event)
|
||||||
|
if event.Op&fsnotify.Write == fsnotify.Write {
|
||||||
|
log.Println("modified file:", event.Name)
|
||||||
|
}
|
||||||
|
case err, ok := <-watcher.Errors:
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Println("error:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
err = watcher.Add("/tmp/foo")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
<-done
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Please refer to [CONTRIBUTING][] before opening an issue or pull request.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
See [example_test.go](https://github.com/fsnotify/fsnotify/blob/master/example_test.go).
|
||||||
|
|
||||||
|
## FAQ
|
||||||
|
|
||||||
|
**When a file is moved to another directory is it still being watched?**
|
||||||
|
|
||||||
|
No (it shouldn't be, unless you are watching where it was moved to).
|
||||||
|
|
||||||
|
**When I watch a directory, are all subdirectories watched as well?**
|
||||||
|
|
||||||
|
No, you must add watches for any directory you want to watch (a recursive watcher is on the roadmap [#18][]).
|
||||||
|
|
||||||
|
**Do I have to watch the Error and Event channels in a separate goroutine?**
|
||||||
|
|
||||||
|
As of now, yes. Looking into making this single-thread friendly (see [howeyc #7][#7])
|
||||||
|
|
||||||
|
**Why am I receiving multiple events for the same file on OS X?**
|
||||||
|
|
||||||
|
Spotlight indexing on OS X can result in multiple events (see [howeyc #62][#62]). A temporary workaround is to add your folder(s) to the *Spotlight Privacy settings* until we have a native FSEvents implementation (see [#11][]).
|
||||||
|
|
||||||
|
**How many files can be watched at once?**
|
||||||
|
|
||||||
|
There are OS-specific limits as to how many watches can be created:
|
||||||
|
* Linux: /proc/sys/fs/inotify/max_user_watches contains the limit, reaching this limit results in a "no space left on device" error.
|
||||||
|
* BSD / OSX: sysctl variables "kern.maxfiles" and "kern.maxfilesperproc", reaching these limits results in a "too many open files" error.
|
||||||
|
|
||||||
|
**Why don't notifications work with NFS filesystems or filesystem in userspace (FUSE)?**
|
||||||
|
|
||||||
|
fsnotify requires support from underlying OS to work. The current NFS protocol does not provide network level support for file notifications.
|
||||||
|
|
||||||
|
[#62]: https://github.com/howeyc/fsnotify/issues/62
|
||||||
|
[#18]: https://github.com/fsnotify/fsnotify/issues/18
|
||||||
|
[#11]: https://github.com/fsnotify/fsnotify/issues/11
|
||||||
|
[#7]: https://github.com/howeyc/fsnotify/issues/7
|
||||||
|
|
||||||
|
[contributing]: https://github.com/fsnotify/fsnotify/blob/master/CONTRIBUTING.md
|
||||||
|
|
||||||
|
## Related Projects
|
||||||
|
|
||||||
|
* [notify](https://github.com/rjeczalik/notify)
|
||||||
|
* [fsevents](https://github.com/fsnotify/fsevents)
|
||||||
|
|
37
vendor/github.com/fsnotify/fsnotify/fen.go
generated
vendored
Normal file
37
vendor/github.com/fsnotify/fsnotify/fen.go
generated
vendored
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
// +build solaris
|
||||||
|
|
||||||
|
package fsnotify
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Watcher watches a set of files, delivering events to a channel.
|
||||||
|
type Watcher struct {
|
||||||
|
Events chan Event
|
||||||
|
Errors chan error
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
|
||||||
|
func NewWatcher() (*Watcher, error) {
|
||||||
|
return nil, errors.New("FEN based watcher not yet supported for fsnotify\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close removes all watches and closes the events channel.
|
||||||
|
func (w *Watcher) Close() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add starts watching the named file or directory (non-recursively).
|
||||||
|
func (w *Watcher) Add(name string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove stops watching the the named file or directory (non-recursively).
|
||||||
|
func (w *Watcher) Remove(name string) error {
|
||||||
|
return nil
|
||||||
|
}
|
68
vendor/github.com/fsnotify/fsnotify/fsnotify.go
generated
vendored
Normal file
68
vendor/github.com/fsnotify/fsnotify/fsnotify.go
generated
vendored
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
// Copyright 2012 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !plan9
|
||||||
|
|
||||||
|
// Package fsnotify provides a platform-independent interface for file system notifications.
|
||||||
|
package fsnotify
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Event represents a single file system notification.
|
||||||
|
type Event struct {
|
||||||
|
Name string // Relative path to the file or directory.
|
||||||
|
Op Op // File operation that triggered the event.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Op describes a set of file operations.
|
||||||
|
type Op uint32
|
||||||
|
|
||||||
|
// These are the generalized file operations that can trigger a notification.
|
||||||
|
const (
|
||||||
|
Create Op = 1 << iota
|
||||||
|
Write
|
||||||
|
Remove
|
||||||
|
Rename
|
||||||
|
Chmod
|
||||||
|
)
|
||||||
|
|
||||||
|
func (op Op) String() string {
|
||||||
|
// Use a buffer for efficient string concatenation
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
|
||||||
|
if op&Create == Create {
|
||||||
|
buffer.WriteString("|CREATE")
|
||||||
|
}
|
||||||
|
if op&Remove == Remove {
|
||||||
|
buffer.WriteString("|REMOVE")
|
||||||
|
}
|
||||||
|
if op&Write == Write {
|
||||||
|
buffer.WriteString("|WRITE")
|
||||||
|
}
|
||||||
|
if op&Rename == Rename {
|
||||||
|
buffer.WriteString("|RENAME")
|
||||||
|
}
|
||||||
|
if op&Chmod == Chmod {
|
||||||
|
buffer.WriteString("|CHMOD")
|
||||||
|
}
|
||||||
|
if buffer.Len() == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return buffer.String()[1:] // Strip leading pipe
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns a string representation of the event in the form
|
||||||
|
// "file: REMOVE|WRITE|..."
|
||||||
|
func (e Event) String() string {
|
||||||
|
return fmt.Sprintf("%q: %s", e.Name, e.Op.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Common errors that can be reported by a watcher
|
||||||
|
var (
|
||||||
|
ErrEventOverflow = errors.New("fsnotify queue overflow")
|
||||||
|
)
|
337
vendor/github.com/fsnotify/fsnotify/inotify.go
generated
vendored
Normal file
337
vendor/github.com/fsnotify/fsnotify/inotify.go
generated
vendored
Normal file
@ -0,0 +1,337 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
// +build linux
|
||||||
|
|
||||||
|
package fsnotify
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Watcher watches a set of files, delivering events to a channel.
|
||||||
|
type Watcher struct {
|
||||||
|
Events chan Event
|
||||||
|
Errors chan error
|
||||||
|
mu sync.Mutex // Map access
|
||||||
|
fd int
|
||||||
|
poller *fdPoller
|
||||||
|
watches map[string]*watch // Map of inotify watches (key: path)
|
||||||
|
paths map[int]string // Map of watched paths (key: watch descriptor)
|
||||||
|
done chan struct{} // Channel for sending a "quit message" to the reader goroutine
|
||||||
|
doneResp chan struct{} // Channel to respond to Close
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
|
||||||
|
func NewWatcher() (*Watcher, error) {
|
||||||
|
// Create inotify fd
|
||||||
|
fd, errno := unix.InotifyInit1(unix.IN_CLOEXEC)
|
||||||
|
if fd == -1 {
|
||||||
|
return nil, errno
|
||||||
|
}
|
||||||
|
// Create epoll
|
||||||
|
poller, err := newFdPoller(fd)
|
||||||
|
if err != nil {
|
||||||
|
unix.Close(fd)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
w := &Watcher{
|
||||||
|
fd: fd,
|
||||||
|
poller: poller,
|
||||||
|
watches: make(map[string]*watch),
|
||||||
|
paths: make(map[int]string),
|
||||||
|
Events: make(chan Event),
|
||||||
|
Errors: make(chan error),
|
||||||
|
done: make(chan struct{}),
|
||||||
|
doneResp: make(chan struct{}),
|
||||||
|
}
|
||||||
|
|
||||||
|
go w.readEvents()
|
||||||
|
return w, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Watcher) isClosed() bool {
|
||||||
|
select {
|
||||||
|
case <-w.done:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close removes all watches and closes the events channel.
|
||||||
|
func (w *Watcher) Close() error {
|
||||||
|
if w.isClosed() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send 'close' signal to goroutine, and set the Watcher to closed.
|
||||||
|
close(w.done)
|
||||||
|
|
||||||
|
// Wake up goroutine
|
||||||
|
w.poller.wake()
|
||||||
|
|
||||||
|
// Wait for goroutine to close
|
||||||
|
<-w.doneResp
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add starts watching the named file or directory (non-recursively).
|
||||||
|
func (w *Watcher) Add(name string) error {
|
||||||
|
name = filepath.Clean(name)
|
||||||
|
if w.isClosed() {
|
||||||
|
return errors.New("inotify instance already closed")
|
||||||
|
}
|
||||||
|
|
||||||
|
const agnosticEvents = unix.IN_MOVED_TO | unix.IN_MOVED_FROM |
|
||||||
|
unix.IN_CREATE | unix.IN_ATTRIB | unix.IN_MODIFY |
|
||||||
|
unix.IN_MOVE_SELF | unix.IN_DELETE | unix.IN_DELETE_SELF
|
||||||
|
|
||||||
|
var flags uint32 = agnosticEvents
|
||||||
|
|
||||||
|
w.mu.Lock()
|
||||||
|
defer w.mu.Unlock()
|
||||||
|
watchEntry := w.watches[name]
|
||||||
|
if watchEntry != nil {
|
||||||
|
flags |= watchEntry.flags | unix.IN_MASK_ADD
|
||||||
|
}
|
||||||
|
wd, errno := unix.InotifyAddWatch(w.fd, name, flags)
|
||||||
|
if wd == -1 {
|
||||||
|
return errno
|
||||||
|
}
|
||||||
|
|
||||||
|
if watchEntry == nil {
|
||||||
|
w.watches[name] = &watch{wd: uint32(wd), flags: flags}
|
||||||
|
w.paths[wd] = name
|
||||||
|
} else {
|
||||||
|
watchEntry.wd = uint32(wd)
|
||||||
|
watchEntry.flags = flags
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove stops watching the named file or directory (non-recursively).
|
||||||
|
func (w *Watcher) Remove(name string) error {
|
||||||
|
name = filepath.Clean(name)
|
||||||
|
|
||||||
|
// Fetch the watch.
|
||||||
|
w.mu.Lock()
|
||||||
|
defer w.mu.Unlock()
|
||||||
|
watch, ok := w.watches[name]
|
||||||
|
|
||||||
|
// Remove it from inotify.
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("can't remove non-existent inotify watch for: %s", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We successfully removed the watch if InotifyRmWatch doesn't return an
|
||||||
|
// error, we need to clean up our internal state to ensure it matches
|
||||||
|
// inotify's kernel state.
|
||||||
|
delete(w.paths, int(watch.wd))
|
||||||
|
delete(w.watches, name)
|
||||||
|
|
||||||
|
// inotify_rm_watch will return EINVAL if the file has been deleted;
|
||||||
|
// the inotify will already have been removed.
|
||||||
|
// watches and pathes are deleted in ignoreLinux() implicitly and asynchronously
|
||||||
|
// by calling inotify_rm_watch() below. e.g. readEvents() goroutine receives IN_IGNORE
|
||||||
|
// so that EINVAL means that the wd is being rm_watch()ed or its file removed
|
||||||
|
// by another thread and we have not received IN_IGNORE event.
|
||||||
|
success, errno := unix.InotifyRmWatch(w.fd, watch.wd)
|
||||||
|
if success == -1 {
|
||||||
|
// TODO: Perhaps it's not helpful to return an error here in every case.
|
||||||
|
// the only two possible errors are:
|
||||||
|
// EBADF, which happens when w.fd is not a valid file descriptor of any kind.
|
||||||
|
// EINVAL, which is when fd is not an inotify descriptor or wd is not a valid watch descriptor.
|
||||||
|
// Watch descriptors are invalidated when they are removed explicitly or implicitly;
|
||||||
|
// explicitly by inotify_rm_watch, implicitly when the file they are watching is deleted.
|
||||||
|
return errno
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type watch struct {
|
||||||
|
wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall)
|
||||||
|
flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags)
|
||||||
|
}
|
||||||
|
|
||||||
|
// readEvents reads from the inotify file descriptor, converts the
|
||||||
|
// received events into Event objects and sends them via the Events channel
|
||||||
|
func (w *Watcher) readEvents() {
|
||||||
|
var (
|
||||||
|
buf [unix.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events
|
||||||
|
n int // Number of bytes read with read()
|
||||||
|
errno error // Syscall errno
|
||||||
|
ok bool // For poller.wait
|
||||||
|
)
|
||||||
|
|
||||||
|
defer close(w.doneResp)
|
||||||
|
defer close(w.Errors)
|
||||||
|
defer close(w.Events)
|
||||||
|
defer unix.Close(w.fd)
|
||||||
|
defer w.poller.close()
|
||||||
|
|
||||||
|
for {
|
||||||
|
// See if we have been closed.
|
||||||
|
if w.isClosed() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ok, errno = w.poller.wait()
|
||||||
|
if errno != nil {
|
||||||
|
select {
|
||||||
|
case w.Errors <- errno:
|
||||||
|
case <-w.done:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
n, errno = unix.Read(w.fd, buf[:])
|
||||||
|
// If a signal interrupted execution, see if we've been asked to close, and try again.
|
||||||
|
// http://man7.org/linux/man-pages/man7/signal.7.html :
|
||||||
|
// "Before Linux 3.8, reads from an inotify(7) file descriptor were not restartable"
|
||||||
|
if errno == unix.EINTR {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// unix.Read might have been woken up by Close. If so, we're done.
|
||||||
|
if w.isClosed() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if n < unix.SizeofInotifyEvent {
|
||||||
|
var err error
|
||||||
|
if n == 0 {
|
||||||
|
// If EOF is received. This should really never happen.
|
||||||
|
err = io.EOF
|
||||||
|
} else if n < 0 {
|
||||||
|
// If an error occurred while reading.
|
||||||
|
err = errno
|
||||||
|
} else {
|
||||||
|
// Read was too short.
|
||||||
|
err = errors.New("notify: short read in readEvents()")
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case w.Errors <- err:
|
||||||
|
case <-w.done:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var offset uint32
|
||||||
|
// We don't know how many events we just read into the buffer
|
||||||
|
// While the offset points to at least one whole event...
|
||||||
|
for offset <= uint32(n-unix.SizeofInotifyEvent) {
|
||||||
|
// Point "raw" to the event in the buffer
|
||||||
|
raw := (*unix.InotifyEvent)(unsafe.Pointer(&buf[offset]))
|
||||||
|
|
||||||
|
mask := uint32(raw.Mask)
|
||||||
|
nameLen := uint32(raw.Len)
|
||||||
|
|
||||||
|
if mask&unix.IN_Q_OVERFLOW != 0 {
|
||||||
|
select {
|
||||||
|
case w.Errors <- ErrEventOverflow:
|
||||||
|
case <-w.done:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the event happened to the watched directory or the watched file, the kernel
|
||||||
|
// doesn't append the filename to the event, but we would like to always fill the
|
||||||
|
// the "Name" field with a valid filename. We retrieve the path of the watch from
|
||||||
|
// the "paths" map.
|
||||||
|
w.mu.Lock()
|
||||||
|
name, ok := w.paths[int(raw.Wd)]
|
||||||
|
// IN_DELETE_SELF occurs when the file/directory being watched is removed.
|
||||||
|
// This is a sign to clean up the maps, otherwise we are no longer in sync
|
||||||
|
// with the inotify kernel state which has already deleted the watch
|
||||||
|
// automatically.
|
||||||
|
if ok && mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF {
|
||||||
|
delete(w.paths, int(raw.Wd))
|
||||||
|
delete(w.watches, name)
|
||||||
|
}
|
||||||
|
w.mu.Unlock()
|
||||||
|
|
||||||
|
if nameLen > 0 {
|
||||||
|
// Point "bytes" at the first byte of the filename
|
||||||
|
bytes := (*[unix.PathMax]byte)(unsafe.Pointer(&buf[offset+unix.SizeofInotifyEvent]))
|
||||||
|
// The filename is padded with NULL bytes. TrimRight() gets rid of those.
|
||||||
|
name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000")
|
||||||
|
}
|
||||||
|
|
||||||
|
event := newEvent(name, mask)
|
||||||
|
|
||||||
|
// Send the events that are not ignored on the events channel
|
||||||
|
if !event.ignoreLinux(mask) {
|
||||||
|
select {
|
||||||
|
case w.Events <- event:
|
||||||
|
case <-w.done:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move to the next event in the buffer
|
||||||
|
offset += unix.SizeofInotifyEvent + nameLen
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Certain types of events can be "ignored" and not sent over the Events
|
||||||
|
// channel. Such as events marked ignore by the kernel, or MODIFY events
|
||||||
|
// against files that do not exist.
|
||||||
|
func (e *Event) ignoreLinux(mask uint32) bool {
|
||||||
|
// Ignore anything the inotify API says to ignore
|
||||||
|
if mask&unix.IN_IGNORED == unix.IN_IGNORED {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the event is not a DELETE or RENAME, the file must exist.
|
||||||
|
// Otherwise the event is ignored.
|
||||||
|
// *Note*: this was put in place because it was seen that a MODIFY
|
||||||
|
// event was sent after the DELETE. This ignores that MODIFY and
|
||||||
|
// assumes a DELETE will come or has come if the file doesn't exist.
|
||||||
|
if !(e.Op&Remove == Remove || e.Op&Rename == Rename) {
|
||||||
|
_, statErr := os.Lstat(e.Name)
|
||||||
|
return os.IsNotExist(statErr)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// newEvent returns an platform-independent Event based on an inotify mask.
|
||||||
|
func newEvent(name string, mask uint32) Event {
|
||||||
|
e := Event{Name: name}
|
||||||
|
if mask&unix.IN_CREATE == unix.IN_CREATE || mask&unix.IN_MOVED_TO == unix.IN_MOVED_TO {
|
||||||
|
e.Op |= Create
|
||||||
|
}
|
||||||
|
if mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF || mask&unix.IN_DELETE == unix.IN_DELETE {
|
||||||
|
e.Op |= Remove
|
||||||
|
}
|
||||||
|
if mask&unix.IN_MODIFY == unix.IN_MODIFY {
|
||||||
|
e.Op |= Write
|
||||||
|
}
|
||||||
|
if mask&unix.IN_MOVE_SELF == unix.IN_MOVE_SELF || mask&unix.IN_MOVED_FROM == unix.IN_MOVED_FROM {
|
||||||
|
e.Op |= Rename
|
||||||
|
}
|
||||||
|
if mask&unix.IN_ATTRIB == unix.IN_ATTRIB {
|
||||||
|
e.Op |= Chmod
|
||||||
|
}
|
||||||
|
return e
|
||||||
|
}
|
187
vendor/github.com/fsnotify/fsnotify/inotify_poller.go
generated
vendored
Normal file
187
vendor/github.com/fsnotify/fsnotify/inotify_poller.go
generated
vendored
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build linux
|
||||||
|
|
||||||
|
package fsnotify
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
type fdPoller struct {
|
||||||
|
fd int // File descriptor (as returned by the inotify_init() syscall)
|
||||||
|
epfd int // Epoll file descriptor
|
||||||
|
pipe [2]int // Pipe for waking up
|
||||||
|
}
|
||||||
|
|
||||||
|
func emptyPoller(fd int) *fdPoller {
|
||||||
|
poller := new(fdPoller)
|
||||||
|
poller.fd = fd
|
||||||
|
poller.epfd = -1
|
||||||
|
poller.pipe[0] = -1
|
||||||
|
poller.pipe[1] = -1
|
||||||
|
return poller
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new inotify poller.
|
||||||
|
// This creates an inotify handler, and an epoll handler.
|
||||||
|
func newFdPoller(fd int) (*fdPoller, error) {
|
||||||
|
var errno error
|
||||||
|
poller := emptyPoller(fd)
|
||||||
|
defer func() {
|
||||||
|
if errno != nil {
|
||||||
|
poller.close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
poller.fd = fd
|
||||||
|
|
||||||
|
// Create epoll fd
|
||||||
|
poller.epfd, errno = unix.EpollCreate1(unix.EPOLL_CLOEXEC)
|
||||||
|
if poller.epfd == -1 {
|
||||||
|
return nil, errno
|
||||||
|
}
|
||||||
|
// Create pipe; pipe[0] is the read end, pipe[1] the write end.
|
||||||
|
errno = unix.Pipe2(poller.pipe[:], unix.O_NONBLOCK|unix.O_CLOEXEC)
|
||||||
|
if errno != nil {
|
||||||
|
return nil, errno
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register inotify fd with epoll
|
||||||
|
event := unix.EpollEvent{
|
||||||
|
Fd: int32(poller.fd),
|
||||||
|
Events: unix.EPOLLIN,
|
||||||
|
}
|
||||||
|
errno = unix.EpollCtl(poller.epfd, unix.EPOLL_CTL_ADD, poller.fd, &event)
|
||||||
|
if errno != nil {
|
||||||
|
return nil, errno
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register pipe fd with epoll
|
||||||
|
event = unix.EpollEvent{
|
||||||
|
Fd: int32(poller.pipe[0]),
|
||||||
|
Events: unix.EPOLLIN,
|
||||||
|
}
|
||||||
|
errno = unix.EpollCtl(poller.epfd, unix.EPOLL_CTL_ADD, poller.pipe[0], &event)
|
||||||
|
if errno != nil {
|
||||||
|
return nil, errno
|
||||||
|
}
|
||||||
|
|
||||||
|
return poller, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait using epoll.
|
||||||
|
// Returns true if something is ready to be read,
|
||||||
|
// false if there is not.
|
||||||
|
func (poller *fdPoller) wait() (bool, error) {
|
||||||
|
// 3 possible events per fd, and 2 fds, makes a maximum of 6 events.
|
||||||
|
// I don't know whether epoll_wait returns the number of events returned,
|
||||||
|
// or the total number of events ready.
|
||||||
|
// I decided to catch both by making the buffer one larger than the maximum.
|
||||||
|
events := make([]unix.EpollEvent, 7)
|
||||||
|
for {
|
||||||
|
n, errno := unix.EpollWait(poller.epfd, events, -1)
|
||||||
|
if n == -1 {
|
||||||
|
if errno == unix.EINTR {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return false, errno
|
||||||
|
}
|
||||||
|
if n == 0 {
|
||||||
|
// If there are no events, try again.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if n > 6 {
|
||||||
|
// This should never happen. More events were returned than should be possible.
|
||||||
|
return false, errors.New("epoll_wait returned more events than I know what to do with")
|
||||||
|
}
|
||||||
|
ready := events[:n]
|
||||||
|
epollhup := false
|
||||||
|
epollerr := false
|
||||||
|
epollin := false
|
||||||
|
for _, event := range ready {
|
||||||
|
if event.Fd == int32(poller.fd) {
|
||||||
|
if event.Events&unix.EPOLLHUP != 0 {
|
||||||
|
// This should not happen, but if it does, treat it as a wakeup.
|
||||||
|
epollhup = true
|
||||||
|
}
|
||||||
|
if event.Events&unix.EPOLLERR != 0 {
|
||||||
|
// If an error is waiting on the file descriptor, we should pretend
|
||||||
|
// something is ready to read, and let unix.Read pick up the error.
|
||||||
|
epollerr = true
|
||||||
|
}
|
||||||
|
if event.Events&unix.EPOLLIN != 0 {
|
||||||
|
// There is data to read.
|
||||||
|
epollin = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if event.Fd == int32(poller.pipe[0]) {
|
||||||
|
if event.Events&unix.EPOLLHUP != 0 {
|
||||||
|
// Write pipe descriptor was closed, by us. This means we're closing down the
|
||||||
|
// watcher, and we should wake up.
|
||||||
|
}
|
||||||
|
if event.Events&unix.EPOLLERR != 0 {
|
||||||
|
// If an error is waiting on the pipe file descriptor.
|
||||||
|
// This is an absolute mystery, and should never ever happen.
|
||||||
|
return false, errors.New("Error on the pipe descriptor.")
|
||||||
|
}
|
||||||
|
if event.Events&unix.EPOLLIN != 0 {
|
||||||
|
// This is a regular wakeup, so we have to clear the buffer.
|
||||||
|
err := poller.clearWake()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if epollhup || epollerr || epollin {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the write end of the poller.
|
||||||
|
func (poller *fdPoller) wake() error {
|
||||||
|
buf := make([]byte, 1)
|
||||||
|
n, errno := unix.Write(poller.pipe[1], buf)
|
||||||
|
if n == -1 {
|
||||||
|
if errno == unix.EAGAIN {
|
||||||
|
// Buffer is full, poller will wake.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errno
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (poller *fdPoller) clearWake() error {
|
||||||
|
// You have to be woken up a LOT in order to get to 100!
|
||||||
|
buf := make([]byte, 100)
|
||||||
|
n, errno := unix.Read(poller.pipe[0], buf)
|
||||||
|
if n == -1 {
|
||||||
|
if errno == unix.EAGAIN {
|
||||||
|
// Buffer is empty, someone else cleared our wake.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errno
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close all poller file descriptors, but not the one passed to it.
|
||||||
|
func (poller *fdPoller) close() {
|
||||||
|
if poller.pipe[1] != -1 {
|
||||||
|
unix.Close(poller.pipe[1])
|
||||||
|
}
|
||||||
|
if poller.pipe[0] != -1 {
|
||||||
|
unix.Close(poller.pipe[0])
|
||||||
|
}
|
||||||
|
if poller.epfd != -1 {
|
||||||
|
unix.Close(poller.epfd)
|
||||||
|
}
|
||||||
|
}
|
521
vendor/github.com/fsnotify/fsnotify/kqueue.go
generated
vendored
Normal file
521
vendor/github.com/fsnotify/fsnotify/kqueue.go
generated
vendored
Normal file
@ -0,0 +1,521 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
// +build freebsd openbsd netbsd dragonfly darwin
|
||||||
|
|
||||||
|
package fsnotify
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Watcher watches a set of files, delivering events to a channel.
|
||||||
|
type Watcher struct {
|
||||||
|
Events chan Event
|
||||||
|
Errors chan error
|
||||||
|
done chan struct{} // Channel for sending a "quit message" to the reader goroutine
|
||||||
|
|
||||||
|
kq int // File descriptor (as returned by the kqueue() syscall).
|
||||||
|
|
||||||
|
mu sync.Mutex // Protects access to watcher data
|
||||||
|
watches map[string]int // Map of watched file descriptors (key: path).
|
||||||
|
externalWatches map[string]bool // Map of watches added by user of the library.
|
||||||
|
dirFlags map[string]uint32 // Map of watched directories to fflags used in kqueue.
|
||||||
|
paths map[int]pathInfo // Map file descriptors to path names for processing kqueue events.
|
||||||
|
fileExists map[string]bool // Keep track of if we know this file exists (to stop duplicate create events).
|
||||||
|
isClosed bool // Set to true when Close() is first called
|
||||||
|
}
|
||||||
|
|
||||||
|
type pathInfo struct {
|
||||||
|
name string
|
||||||
|
isDir bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
|
||||||
|
func NewWatcher() (*Watcher, error) {
|
||||||
|
kq, err := kqueue()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
w := &Watcher{
|
||||||
|
kq: kq,
|
||||||
|
watches: make(map[string]int),
|
||||||
|
dirFlags: make(map[string]uint32),
|
||||||
|
paths: make(map[int]pathInfo),
|
||||||
|
fileExists: make(map[string]bool),
|
||||||
|
externalWatches: make(map[string]bool),
|
||||||
|
Events: make(chan Event),
|
||||||
|
Errors: make(chan error),
|
||||||
|
done: make(chan struct{}),
|
||||||
|
}
|
||||||
|
|
||||||
|
go w.readEvents()
|
||||||
|
return w, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close removes all watches and closes the events channel.
|
||||||
|
func (w *Watcher) Close() error {
|
||||||
|
w.mu.Lock()
|
||||||
|
if w.isClosed {
|
||||||
|
w.mu.Unlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
w.isClosed = true
|
||||||
|
|
||||||
|
// copy paths to remove while locked
|
||||||
|
var pathsToRemove = make([]string, 0, len(w.watches))
|
||||||
|
for name := range w.watches {
|
||||||
|
pathsToRemove = append(pathsToRemove, name)
|
||||||
|
}
|
||||||
|
w.mu.Unlock()
|
||||||
|
// unlock before calling Remove, which also locks
|
||||||
|
|
||||||
|
for _, name := range pathsToRemove {
|
||||||
|
w.Remove(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// send a "quit" message to the reader goroutine
|
||||||
|
close(w.done)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add starts watching the named file or directory (non-recursively).
|
||||||
|
func (w *Watcher) Add(name string) error {
|
||||||
|
w.mu.Lock()
|
||||||
|
w.externalWatches[name] = true
|
||||||
|
w.mu.Unlock()
|
||||||
|
_, err := w.addWatch(name, noteAllEvents)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove stops watching the the named file or directory (non-recursively).
|
||||||
|
func (w *Watcher) Remove(name string) error {
|
||||||
|
name = filepath.Clean(name)
|
||||||
|
w.mu.Lock()
|
||||||
|
watchfd, ok := w.watches[name]
|
||||||
|
w.mu.Unlock()
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("can't remove non-existent kevent watch for: %s", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
const registerRemove = unix.EV_DELETE
|
||||||
|
if err := register(w.kq, []int{watchfd}, registerRemove, 0); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
unix.Close(watchfd)
|
||||||
|
|
||||||
|
w.mu.Lock()
|
||||||
|
isDir := w.paths[watchfd].isDir
|
||||||
|
delete(w.watches, name)
|
||||||
|
delete(w.paths, watchfd)
|
||||||
|
delete(w.dirFlags, name)
|
||||||
|
w.mu.Unlock()
|
||||||
|
|
||||||
|
// Find all watched paths that are in this directory that are not external.
|
||||||
|
if isDir {
|
||||||
|
var pathsToRemove []string
|
||||||
|
w.mu.Lock()
|
||||||
|
for _, path := range w.paths {
|
||||||
|
wdir, _ := filepath.Split(path.name)
|
||||||
|
if filepath.Clean(wdir) == name {
|
||||||
|
if !w.externalWatches[path.name] {
|
||||||
|
pathsToRemove = append(pathsToRemove, path.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.mu.Unlock()
|
||||||
|
for _, name := range pathsToRemove {
|
||||||
|
// Since these are internal, not much sense in propagating error
|
||||||
|
// to the user, as that will just confuse them with an error about
|
||||||
|
// a path they did not explicitly watch themselves.
|
||||||
|
w.Remove(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Watch all events (except NOTE_EXTEND, NOTE_LINK, NOTE_REVOKE)
|
||||||
|
const noteAllEvents = unix.NOTE_DELETE | unix.NOTE_WRITE | unix.NOTE_ATTRIB | unix.NOTE_RENAME
|
||||||
|
|
||||||
|
// keventWaitTime to block on each read from kevent
|
||||||
|
var keventWaitTime = durationToTimespec(100 * time.Millisecond)
|
||||||
|
|
||||||
|
// addWatch adds name to the watched file set.
|
||||||
|
// The flags are interpreted as described in kevent(2).
|
||||||
|
// Returns the real path to the file which was added, if any, which may be different from the one passed in the case of symlinks.
|
||||||
|
func (w *Watcher) addWatch(name string, flags uint32) (string, error) {
|
||||||
|
var isDir bool
|
||||||
|
// Make ./name and name equivalent
|
||||||
|
name = filepath.Clean(name)
|
||||||
|
|
||||||
|
w.mu.Lock()
|
||||||
|
if w.isClosed {
|
||||||
|
w.mu.Unlock()
|
||||||
|
return "", errors.New("kevent instance already closed")
|
||||||
|
}
|
||||||
|
watchfd, alreadyWatching := w.watches[name]
|
||||||
|
// We already have a watch, but we can still override flags.
|
||||||
|
if alreadyWatching {
|
||||||
|
isDir = w.paths[watchfd].isDir
|
||||||
|
}
|
||||||
|
w.mu.Unlock()
|
||||||
|
|
||||||
|
if !alreadyWatching {
|
||||||
|
fi, err := os.Lstat(name)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't watch sockets.
|
||||||
|
if fi.Mode()&os.ModeSocket == os.ModeSocket {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't watch named pipes.
|
||||||
|
if fi.Mode()&os.ModeNamedPipe == os.ModeNamedPipe {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Follow Symlinks
|
||||||
|
// Unfortunately, Linux can add bogus symlinks to watch list without
|
||||||
|
// issue, and Windows can't do symlinks period (AFAIK). To maintain
|
||||||
|
// consistency, we will act like everything is fine. There will simply
|
||||||
|
// be no file events for broken symlinks.
|
||||||
|
// Hence the returns of nil on errors.
|
||||||
|
if fi.Mode()&os.ModeSymlink == os.ModeSymlink {
|
||||||
|
name, err = filepath.EvalSymlinks(name)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
w.mu.Lock()
|
||||||
|
_, alreadyWatching = w.watches[name]
|
||||||
|
w.mu.Unlock()
|
||||||
|
|
||||||
|
if alreadyWatching {
|
||||||
|
return name, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
fi, err = os.Lstat(name)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watchfd, err = unix.Open(name, openMode, 0700)
|
||||||
|
if watchfd == -1 {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
isDir = fi.IsDir()
|
||||||
|
}
|
||||||
|
|
||||||
|
const registerAdd = unix.EV_ADD | unix.EV_CLEAR | unix.EV_ENABLE
|
||||||
|
if err := register(w.kq, []int{watchfd}, registerAdd, flags); err != nil {
|
||||||
|
unix.Close(watchfd)
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !alreadyWatching {
|
||||||
|
w.mu.Lock()
|
||||||
|
w.watches[name] = watchfd
|
||||||
|
w.paths[watchfd] = pathInfo{name: name, isDir: isDir}
|
||||||
|
w.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
if isDir {
|
||||||
|
// Watch the directory if it has not been watched before,
|
||||||
|
// or if it was watched before, but perhaps only a NOTE_DELETE (watchDirectoryFiles)
|
||||||
|
w.mu.Lock()
|
||||||
|
|
||||||
|
watchDir := (flags&unix.NOTE_WRITE) == unix.NOTE_WRITE &&
|
||||||
|
(!alreadyWatching || (w.dirFlags[name]&unix.NOTE_WRITE) != unix.NOTE_WRITE)
|
||||||
|
// Store flags so this watch can be updated later
|
||||||
|
w.dirFlags[name] = flags
|
||||||
|
w.mu.Unlock()
|
||||||
|
|
||||||
|
if watchDir {
|
||||||
|
if err := w.watchDirectoryFiles(name); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return name, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// readEvents reads from kqueue and converts the received kevents into
|
||||||
|
// Event values that it sends down the Events channel.
|
||||||
|
func (w *Watcher) readEvents() {
|
||||||
|
eventBuffer := make([]unix.Kevent_t, 10)
|
||||||
|
|
||||||
|
loop:
|
||||||
|
for {
|
||||||
|
// See if there is a message on the "done" channel
|
||||||
|
select {
|
||||||
|
case <-w.done:
|
||||||
|
break loop
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get new events
|
||||||
|
kevents, err := read(w.kq, eventBuffer, &keventWaitTime)
|
||||||
|
// EINTR is okay, the syscall was interrupted before timeout expired.
|
||||||
|
if err != nil && err != unix.EINTR {
|
||||||
|
select {
|
||||||
|
case w.Errors <- err:
|
||||||
|
case <-w.done:
|
||||||
|
break loop
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flush the events we received to the Events channel
|
||||||
|
for len(kevents) > 0 {
|
||||||
|
kevent := &kevents[0]
|
||||||
|
watchfd := int(kevent.Ident)
|
||||||
|
mask := uint32(kevent.Fflags)
|
||||||
|
w.mu.Lock()
|
||||||
|
path := w.paths[watchfd]
|
||||||
|
w.mu.Unlock()
|
||||||
|
event := newEvent(path.name, mask)
|
||||||
|
|
||||||
|
if path.isDir && !(event.Op&Remove == Remove) {
|
||||||
|
// Double check to make sure the directory exists. This can happen when
|
||||||
|
// we do a rm -fr on a recursively watched folders and we receive a
|
||||||
|
// modification event first but the folder has been deleted and later
|
||||||
|
// receive the delete event
|
||||||
|
if _, err := os.Lstat(event.Name); os.IsNotExist(err) {
|
||||||
|
// mark is as delete event
|
||||||
|
event.Op |= Remove
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if event.Op&Rename == Rename || event.Op&Remove == Remove {
|
||||||
|
w.Remove(event.Name)
|
||||||
|
w.mu.Lock()
|
||||||
|
delete(w.fileExists, event.Name)
|
||||||
|
w.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
if path.isDir && event.Op&Write == Write && !(event.Op&Remove == Remove) {
|
||||||
|
w.sendDirectoryChangeEvents(event.Name)
|
||||||
|
} else {
|
||||||
|
// Send the event on the Events channel.
|
||||||
|
select {
|
||||||
|
case w.Events <- event:
|
||||||
|
case <-w.done:
|
||||||
|
break loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if event.Op&Remove == Remove {
|
||||||
|
// Look for a file that may have overwritten this.
|
||||||
|
// For example, mv f1 f2 will delete f2, then create f2.
|
||||||
|
if path.isDir {
|
||||||
|
fileDir := filepath.Clean(event.Name)
|
||||||
|
w.mu.Lock()
|
||||||
|
_, found := w.watches[fileDir]
|
||||||
|
w.mu.Unlock()
|
||||||
|
if found {
|
||||||
|
// make sure the directory exists before we watch for changes. When we
|
||||||
|
// do a recursive watch and perform rm -fr, the parent directory might
|
||||||
|
// have gone missing, ignore the missing directory and let the
|
||||||
|
// upcoming delete event remove the watch from the parent directory.
|
||||||
|
if _, err := os.Lstat(fileDir); err == nil {
|
||||||
|
w.sendDirectoryChangeEvents(fileDir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
filePath := filepath.Clean(event.Name)
|
||||||
|
if fileInfo, err := os.Lstat(filePath); err == nil {
|
||||||
|
w.sendFileCreatedEventIfNew(filePath, fileInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move to next event
|
||||||
|
kevents = kevents[1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// cleanup
|
||||||
|
err := unix.Close(w.kq)
|
||||||
|
if err != nil {
|
||||||
|
// only way the previous loop breaks is if w.done was closed so we need to async send to w.Errors.
|
||||||
|
select {
|
||||||
|
case w.Errors <- err:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(w.Events)
|
||||||
|
close(w.Errors)
|
||||||
|
}
|
||||||
|
|
||||||
|
// newEvent returns an platform-independent Event based on kqueue Fflags.
|
||||||
|
func newEvent(name string, mask uint32) Event {
|
||||||
|
e := Event{Name: name}
|
||||||
|
if mask&unix.NOTE_DELETE == unix.NOTE_DELETE {
|
||||||
|
e.Op |= Remove
|
||||||
|
}
|
||||||
|
if mask&unix.NOTE_WRITE == unix.NOTE_WRITE {
|
||||||
|
e.Op |= Write
|
||||||
|
}
|
||||||
|
if mask&unix.NOTE_RENAME == unix.NOTE_RENAME {
|
||||||
|
e.Op |= Rename
|
||||||
|
}
|
||||||
|
if mask&unix.NOTE_ATTRIB == unix.NOTE_ATTRIB {
|
||||||
|
e.Op |= Chmod
|
||||||
|
}
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
func newCreateEvent(name string) Event {
|
||||||
|
return Event{Name: name, Op: Create}
|
||||||
|
}
|
||||||
|
|
||||||
|
// watchDirectoryFiles to mimic inotify when adding a watch on a directory
|
||||||
|
func (w *Watcher) watchDirectoryFiles(dirPath string) error {
|
||||||
|
// Get all files
|
||||||
|
files, err := ioutil.ReadDir(dirPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, fileInfo := range files {
|
||||||
|
filePath := filepath.Join(dirPath, fileInfo.Name())
|
||||||
|
filePath, err = w.internalWatch(filePath, fileInfo)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
w.mu.Lock()
|
||||||
|
w.fileExists[filePath] = true
|
||||||
|
w.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// sendDirectoryEvents searches the directory for newly created files
|
||||||
|
// and sends them over the event channel. This functionality is to have
|
||||||
|
// the BSD version of fsnotify match Linux inotify which provides a
|
||||||
|
// create event for files created in a watched directory.
|
||||||
|
func (w *Watcher) sendDirectoryChangeEvents(dirPath string) {
|
||||||
|
// Get all files
|
||||||
|
files, err := ioutil.ReadDir(dirPath)
|
||||||
|
if err != nil {
|
||||||
|
select {
|
||||||
|
case w.Errors <- err:
|
||||||
|
case <-w.done:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search for new files
|
||||||
|
for _, fileInfo := range files {
|
||||||
|
filePath := filepath.Join(dirPath, fileInfo.Name())
|
||||||
|
err := w.sendFileCreatedEventIfNew(filePath, fileInfo)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sendFileCreatedEvent sends a create event if the file isn't already being tracked.
|
||||||
|
func (w *Watcher) sendFileCreatedEventIfNew(filePath string, fileInfo os.FileInfo) (err error) {
|
||||||
|
w.mu.Lock()
|
||||||
|
_, doesExist := w.fileExists[filePath]
|
||||||
|
w.mu.Unlock()
|
||||||
|
if !doesExist {
|
||||||
|
// Send create event
|
||||||
|
select {
|
||||||
|
case w.Events <- newCreateEvent(filePath):
|
||||||
|
case <-w.done:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// like watchDirectoryFiles (but without doing another ReadDir)
|
||||||
|
filePath, err = w.internalWatch(filePath, fileInfo)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
w.mu.Lock()
|
||||||
|
w.fileExists[filePath] = true
|
||||||
|
w.mu.Unlock()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Watcher) internalWatch(name string, fileInfo os.FileInfo) (string, error) {
|
||||||
|
if fileInfo.IsDir() {
|
||||||
|
// mimic Linux providing delete events for subdirectories
|
||||||
|
// but preserve the flags used if currently watching subdirectory
|
||||||
|
w.mu.Lock()
|
||||||
|
flags := w.dirFlags[name]
|
||||||
|
w.mu.Unlock()
|
||||||
|
|
||||||
|
flags |= unix.NOTE_DELETE | unix.NOTE_RENAME
|
||||||
|
return w.addWatch(name, flags)
|
||||||
|
}
|
||||||
|
|
||||||
|
// watch file to mimic Linux inotify
|
||||||
|
return w.addWatch(name, noteAllEvents)
|
||||||
|
}
|
||||||
|
|
||||||
|
// kqueue creates a new kernel event queue and returns a descriptor.
|
||||||
|
func kqueue() (kq int, err error) {
|
||||||
|
kq, err = unix.Kqueue()
|
||||||
|
if kq == -1 {
|
||||||
|
return kq, err
|
||||||
|
}
|
||||||
|
return kq, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// register events with the queue
|
||||||
|
func register(kq int, fds []int, flags int, fflags uint32) error {
|
||||||
|
changes := make([]unix.Kevent_t, len(fds))
|
||||||
|
|
||||||
|
for i, fd := range fds {
|
||||||
|
// SetKevent converts int to the platform-specific types:
|
||||||
|
unix.SetKevent(&changes[i], fd, unix.EVFILT_VNODE, flags)
|
||||||
|
changes[i].Fflags = fflags
|
||||||
|
}
|
||||||
|
|
||||||
|
// register the events
|
||||||
|
success, err := unix.Kevent(kq, changes, nil, nil)
|
||||||
|
if success == -1 {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// read retrieves pending events, or waits until an event occurs.
|
||||||
|
// A timeout of nil blocks indefinitely, while 0 polls the queue.
|
||||||
|
func read(kq int, events []unix.Kevent_t, timeout *unix.Timespec) ([]unix.Kevent_t, error) {
|
||||||
|
n, err := unix.Kevent(kq, nil, events, timeout)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return events[0:n], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// durationToTimespec prepares a timeout value
|
||||||
|
func durationToTimespec(d time.Duration) unix.Timespec {
|
||||||
|
return unix.NsecToTimespec(d.Nanoseconds())
|
||||||
|
}
|
11
vendor/github.com/fsnotify/fsnotify/open_mode_bsd.go
generated
vendored
Normal file
11
vendor/github.com/fsnotify/fsnotify/open_mode_bsd.go
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// Copyright 2013 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build freebsd openbsd netbsd dragonfly
|
||||||
|
|
||||||
|
package fsnotify
|
||||||
|
|
||||||
|
import "golang.org/x/sys/unix"
|
||||||
|
|
||||||
|
const openMode = unix.O_NONBLOCK | unix.O_RDONLY | unix.O_CLOEXEC
|
12
vendor/github.com/fsnotify/fsnotify/open_mode_darwin.go
generated
vendored
Normal file
12
vendor/github.com/fsnotify/fsnotify/open_mode_darwin.go
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// Copyright 2013 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build darwin
|
||||||
|
|
||||||
|
package fsnotify
|
||||||
|
|
||||||
|
import "golang.org/x/sys/unix"
|
||||||
|
|
||||||
|
// note: this constant is not defined on BSD
|
||||||
|
const openMode = unix.O_EVTONLY | unix.O_CLOEXEC
|
561
vendor/github.com/fsnotify/fsnotify/windows.go
generated
vendored
Normal file
561
vendor/github.com/fsnotify/fsnotify/windows.go
generated
vendored
Normal file
@ -0,0 +1,561 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package fsnotify
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"sync"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Watcher watches a set of files, delivering events to a channel.
|
||||||
|
type Watcher struct {
|
||||||
|
Events chan Event
|
||||||
|
Errors chan error
|
||||||
|
isClosed bool // Set to true when Close() is first called
|
||||||
|
mu sync.Mutex // Map access
|
||||||
|
port syscall.Handle // Handle to completion port
|
||||||
|
watches watchMap // Map of watches (key: i-number)
|
||||||
|
input chan *input // Inputs to the reader are sent on this channel
|
||||||
|
quit chan chan<- error
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
|
||||||
|
func NewWatcher() (*Watcher, error) {
|
||||||
|
port, e := syscall.CreateIoCompletionPort(syscall.InvalidHandle, 0, 0, 0)
|
||||||
|
if e != nil {
|
||||||
|
return nil, os.NewSyscallError("CreateIoCompletionPort", e)
|
||||||
|
}
|
||||||
|
w := &Watcher{
|
||||||
|
port: port,
|
||||||
|
watches: make(watchMap),
|
||||||
|
input: make(chan *input, 1),
|
||||||
|
Events: make(chan Event, 50),
|
||||||
|
Errors: make(chan error),
|
||||||
|
quit: make(chan chan<- error, 1),
|
||||||
|
}
|
||||||
|
go w.readEvents()
|
||||||
|
return w, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close removes all watches and closes the events channel.
|
||||||
|
func (w *Watcher) Close() error {
|
||||||
|
if w.isClosed {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
w.isClosed = true
|
||||||
|
|
||||||
|
// Send "quit" message to the reader goroutine
|
||||||
|
ch := make(chan error)
|
||||||
|
w.quit <- ch
|
||||||
|
if err := w.wakeupReader(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return <-ch
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add starts watching the named file or directory (non-recursively).
|
||||||
|
func (w *Watcher) Add(name string) error {
|
||||||
|
if w.isClosed {
|
||||||
|
return errors.New("watcher already closed")
|
||||||
|
}
|
||||||
|
in := &input{
|
||||||
|
op: opAddWatch,
|
||||||
|
path: filepath.Clean(name),
|
||||||
|
flags: sysFSALLEVENTS,
|
||||||
|
reply: make(chan error),
|
||||||
|
}
|
||||||
|
w.input <- in
|
||||||
|
if err := w.wakeupReader(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return <-in.reply
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove stops watching the the named file or directory (non-recursively).
|
||||||
|
func (w *Watcher) Remove(name string) error {
|
||||||
|
in := &input{
|
||||||
|
op: opRemoveWatch,
|
||||||
|
path: filepath.Clean(name),
|
||||||
|
reply: make(chan error),
|
||||||
|
}
|
||||||
|
w.input <- in
|
||||||
|
if err := w.wakeupReader(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return <-in.reply
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Options for AddWatch
|
||||||
|
sysFSONESHOT = 0x80000000
|
||||||
|
sysFSONLYDIR = 0x1000000
|
||||||
|
|
||||||
|
// Events
|
||||||
|
sysFSACCESS = 0x1
|
||||||
|
sysFSALLEVENTS = 0xfff
|
||||||
|
sysFSATTRIB = 0x4
|
||||||
|
sysFSCLOSE = 0x18
|
||||||
|
sysFSCREATE = 0x100
|
||||||
|
sysFSDELETE = 0x200
|
||||||
|
sysFSDELETESELF = 0x400
|
||||||
|
sysFSMODIFY = 0x2
|
||||||
|
sysFSMOVE = 0xc0
|
||||||
|
sysFSMOVEDFROM = 0x40
|
||||||
|
sysFSMOVEDTO = 0x80
|
||||||
|
sysFSMOVESELF = 0x800
|
||||||
|
|
||||||
|
// Special events
|
||||||
|
sysFSIGNORED = 0x8000
|
||||||
|
sysFSQOVERFLOW = 0x4000
|
||||||
|
)
|
||||||
|
|
||||||
|
func newEvent(name string, mask uint32) Event {
|
||||||
|
e := Event{Name: name}
|
||||||
|
if mask&sysFSCREATE == sysFSCREATE || mask&sysFSMOVEDTO == sysFSMOVEDTO {
|
||||||
|
e.Op |= Create
|
||||||
|
}
|
||||||
|
if mask&sysFSDELETE == sysFSDELETE || mask&sysFSDELETESELF == sysFSDELETESELF {
|
||||||
|
e.Op |= Remove
|
||||||
|
}
|
||||||
|
if mask&sysFSMODIFY == sysFSMODIFY {
|
||||||
|
e.Op |= Write
|
||||||
|
}
|
||||||
|
if mask&sysFSMOVE == sysFSMOVE || mask&sysFSMOVESELF == sysFSMOVESELF || mask&sysFSMOVEDFROM == sysFSMOVEDFROM {
|
||||||
|
e.Op |= Rename
|
||||||
|
}
|
||||||
|
if mask&sysFSATTRIB == sysFSATTRIB {
|
||||||
|
e.Op |= Chmod
|
||||||
|
}
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
opAddWatch = iota
|
||||||
|
opRemoveWatch
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
provisional uint64 = 1 << (32 + iota)
|
||||||
|
)
|
||||||
|
|
||||||
|
type input struct {
|
||||||
|
op int
|
||||||
|
path string
|
||||||
|
flags uint32
|
||||||
|
reply chan error
|
||||||
|
}
|
||||||
|
|
||||||
|
type inode struct {
|
||||||
|
handle syscall.Handle
|
||||||
|
volume uint32
|
||||||
|
index uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type watch struct {
|
||||||
|
ov syscall.Overlapped
|
||||||
|
ino *inode // i-number
|
||||||
|
path string // Directory path
|
||||||
|
mask uint64 // Directory itself is being watched with these notify flags
|
||||||
|
names map[string]uint64 // Map of names being watched and their notify flags
|
||||||
|
rename string // Remembers the old name while renaming a file
|
||||||
|
buf [4096]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type indexMap map[uint64]*watch
|
||||||
|
type watchMap map[uint32]indexMap
|
||||||
|
|
||||||
|
func (w *Watcher) wakeupReader() error {
|
||||||
|
e := syscall.PostQueuedCompletionStatus(w.port, 0, 0, nil)
|
||||||
|
if e != nil {
|
||||||
|
return os.NewSyscallError("PostQueuedCompletionStatus", e)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getDir(pathname string) (dir string, err error) {
|
||||||
|
attr, e := syscall.GetFileAttributes(syscall.StringToUTF16Ptr(pathname))
|
||||||
|
if e != nil {
|
||||||
|
return "", os.NewSyscallError("GetFileAttributes", e)
|
||||||
|
}
|
||||||
|
if attr&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
|
||||||
|
dir = pathname
|
||||||
|
} else {
|
||||||
|
dir, _ = filepath.Split(pathname)
|
||||||
|
dir = filepath.Clean(dir)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func getIno(path string) (ino *inode, err error) {
|
||||||
|
h, e := syscall.CreateFile(syscall.StringToUTF16Ptr(path),
|
||||||
|
syscall.FILE_LIST_DIRECTORY,
|
||||||
|
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
|
||||||
|
nil, syscall.OPEN_EXISTING,
|
||||||
|
syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OVERLAPPED, 0)
|
||||||
|
if e != nil {
|
||||||
|
return nil, os.NewSyscallError("CreateFile", e)
|
||||||
|
}
|
||||||
|
var fi syscall.ByHandleFileInformation
|
||||||
|
if e = syscall.GetFileInformationByHandle(h, &fi); e != nil {
|
||||||
|
syscall.CloseHandle(h)
|
||||||
|
return nil, os.NewSyscallError("GetFileInformationByHandle", e)
|
||||||
|
}
|
||||||
|
ino = &inode{
|
||||||
|
handle: h,
|
||||||
|
volume: fi.VolumeSerialNumber,
|
||||||
|
index: uint64(fi.FileIndexHigh)<<32 | uint64(fi.FileIndexLow),
|
||||||
|
}
|
||||||
|
return ino, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must run within the I/O thread.
|
||||||
|
func (m watchMap) get(ino *inode) *watch {
|
||||||
|
if i := m[ino.volume]; i != nil {
|
||||||
|
return i[ino.index]
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must run within the I/O thread.
|
||||||
|
func (m watchMap) set(ino *inode, watch *watch) {
|
||||||
|
i := m[ino.volume]
|
||||||
|
if i == nil {
|
||||||
|
i = make(indexMap)
|
||||||
|
m[ino.volume] = i
|
||||||
|
}
|
||||||
|
i[ino.index] = watch
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must run within the I/O thread.
|
||||||
|
func (w *Watcher) addWatch(pathname string, flags uint64) error {
|
||||||
|
dir, err := getDir(pathname)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if flags&sysFSONLYDIR != 0 && pathname != dir {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
ino, err := getIno(dir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
w.mu.Lock()
|
||||||
|
watchEntry := w.watches.get(ino)
|
||||||
|
w.mu.Unlock()
|
||||||
|
if watchEntry == nil {
|
||||||
|
if _, e := syscall.CreateIoCompletionPort(ino.handle, w.port, 0, 0); e != nil {
|
||||||
|
syscall.CloseHandle(ino.handle)
|
||||||
|
return os.NewSyscallError("CreateIoCompletionPort", e)
|
||||||
|
}
|
||||||
|
watchEntry = &watch{
|
||||||
|
ino: ino,
|
||||||
|
path: dir,
|
||||||
|
names: make(map[string]uint64),
|
||||||
|
}
|
||||||
|
w.mu.Lock()
|
||||||
|
w.watches.set(ino, watchEntry)
|
||||||
|
w.mu.Unlock()
|
||||||
|
flags |= provisional
|
||||||
|
} else {
|
||||||
|
syscall.CloseHandle(ino.handle)
|
||||||
|
}
|
||||||
|
if pathname == dir {
|
||||||
|
watchEntry.mask |= flags
|
||||||
|
} else {
|
||||||
|
watchEntry.names[filepath.Base(pathname)] |= flags
|
||||||
|
}
|
||||||
|
if err = w.startRead(watchEntry); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if pathname == dir {
|
||||||
|
watchEntry.mask &= ^provisional
|
||||||
|
} else {
|
||||||
|
watchEntry.names[filepath.Base(pathname)] &= ^provisional
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must run within the I/O thread.
|
||||||
|
func (w *Watcher) remWatch(pathname string) error {
|
||||||
|
dir, err := getDir(pathname)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ino, err := getIno(dir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
w.mu.Lock()
|
||||||
|
watch := w.watches.get(ino)
|
||||||
|
w.mu.Unlock()
|
||||||
|
if watch == nil {
|
||||||
|
return fmt.Errorf("can't remove non-existent watch for: %s", pathname)
|
||||||
|
}
|
||||||
|
if pathname == dir {
|
||||||
|
w.sendEvent(watch.path, watch.mask&sysFSIGNORED)
|
||||||
|
watch.mask = 0
|
||||||
|
} else {
|
||||||
|
name := filepath.Base(pathname)
|
||||||
|
w.sendEvent(filepath.Join(watch.path, name), watch.names[name]&sysFSIGNORED)
|
||||||
|
delete(watch.names, name)
|
||||||
|
}
|
||||||
|
return w.startRead(watch)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must run within the I/O thread.
|
||||||
|
func (w *Watcher) deleteWatch(watch *watch) {
|
||||||
|
for name, mask := range watch.names {
|
||||||
|
if mask&provisional == 0 {
|
||||||
|
w.sendEvent(filepath.Join(watch.path, name), mask&sysFSIGNORED)
|
||||||
|
}
|
||||||
|
delete(watch.names, name)
|
||||||
|
}
|
||||||
|
if watch.mask != 0 {
|
||||||
|
if watch.mask&provisional == 0 {
|
||||||
|
w.sendEvent(watch.path, watch.mask&sysFSIGNORED)
|
||||||
|
}
|
||||||
|
watch.mask = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must run within the I/O thread.
|
||||||
|
func (w *Watcher) startRead(watch *watch) error {
|
||||||
|
if e := syscall.CancelIo(watch.ino.handle); e != nil {
|
||||||
|
w.Errors <- os.NewSyscallError("CancelIo", e)
|
||||||
|
w.deleteWatch(watch)
|
||||||
|
}
|
||||||
|
mask := toWindowsFlags(watch.mask)
|
||||||
|
for _, m := range watch.names {
|
||||||
|
mask |= toWindowsFlags(m)
|
||||||
|
}
|
||||||
|
if mask == 0 {
|
||||||
|
if e := syscall.CloseHandle(watch.ino.handle); e != nil {
|
||||||
|
w.Errors <- os.NewSyscallError("CloseHandle", e)
|
||||||
|
}
|
||||||
|
w.mu.Lock()
|
||||||
|
delete(w.watches[watch.ino.volume], watch.ino.index)
|
||||||
|
w.mu.Unlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
e := syscall.ReadDirectoryChanges(watch.ino.handle, &watch.buf[0],
|
||||||
|
uint32(unsafe.Sizeof(watch.buf)), false, mask, nil, &watch.ov, 0)
|
||||||
|
if e != nil {
|
||||||
|
err := os.NewSyscallError("ReadDirectoryChanges", e)
|
||||||
|
if e == syscall.ERROR_ACCESS_DENIED && watch.mask&provisional == 0 {
|
||||||
|
// Watched directory was probably removed
|
||||||
|
if w.sendEvent(watch.path, watch.mask&sysFSDELETESELF) {
|
||||||
|
if watch.mask&sysFSONESHOT != 0 {
|
||||||
|
watch.mask = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
w.deleteWatch(watch)
|
||||||
|
w.startRead(watch)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// readEvents reads from the I/O completion port, converts the
|
||||||
|
// received events into Event objects and sends them via the Events channel.
|
||||||
|
// Entry point to the I/O thread.
|
||||||
|
func (w *Watcher) readEvents() {
|
||||||
|
var (
|
||||||
|
n, key uint32
|
||||||
|
ov *syscall.Overlapped
|
||||||
|
)
|
||||||
|
runtime.LockOSThread()
|
||||||
|
|
||||||
|
for {
|
||||||
|
e := syscall.GetQueuedCompletionStatus(w.port, &n, &key, &ov, syscall.INFINITE)
|
||||||
|
watch := (*watch)(unsafe.Pointer(ov))
|
||||||
|
|
||||||
|
if watch == nil {
|
||||||
|
select {
|
||||||
|
case ch := <-w.quit:
|
||||||
|
w.mu.Lock()
|
||||||
|
var indexes []indexMap
|
||||||
|
for _, index := range w.watches {
|
||||||
|
indexes = append(indexes, index)
|
||||||
|
}
|
||||||
|
w.mu.Unlock()
|
||||||
|
for _, index := range indexes {
|
||||||
|
for _, watch := range index {
|
||||||
|
w.deleteWatch(watch)
|
||||||
|
w.startRead(watch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
if e := syscall.CloseHandle(w.port); e != nil {
|
||||||
|
err = os.NewSyscallError("CloseHandle", e)
|
||||||
|
}
|
||||||
|
close(w.Events)
|
||||||
|
close(w.Errors)
|
||||||
|
ch <- err
|
||||||
|
return
|
||||||
|
case in := <-w.input:
|
||||||
|
switch in.op {
|
||||||
|
case opAddWatch:
|
||||||
|
in.reply <- w.addWatch(in.path, uint64(in.flags))
|
||||||
|
case opRemoveWatch:
|
||||||
|
in.reply <- w.remWatch(in.path)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
switch e {
|
||||||
|
case syscall.ERROR_MORE_DATA:
|
||||||
|
if watch == nil {
|
||||||
|
w.Errors <- errors.New("ERROR_MORE_DATA has unexpectedly null lpOverlapped buffer")
|
||||||
|
} else {
|
||||||
|
// The i/o succeeded but the buffer is full.
|
||||||
|
// In theory we should be building up a full packet.
|
||||||
|
// In practice we can get away with just carrying on.
|
||||||
|
n = uint32(unsafe.Sizeof(watch.buf))
|
||||||
|
}
|
||||||
|
case syscall.ERROR_ACCESS_DENIED:
|
||||||
|
// Watched directory was probably removed
|
||||||
|
w.sendEvent(watch.path, watch.mask&sysFSDELETESELF)
|
||||||
|
w.deleteWatch(watch)
|
||||||
|
w.startRead(watch)
|
||||||
|
continue
|
||||||
|
case syscall.ERROR_OPERATION_ABORTED:
|
||||||
|
// CancelIo was called on this handle
|
||||||
|
continue
|
||||||
|
default:
|
||||||
|
w.Errors <- os.NewSyscallError("GetQueuedCompletionPort", e)
|
||||||
|
continue
|
||||||
|
case nil:
|
||||||
|
}
|
||||||
|
|
||||||
|
var offset uint32
|
||||||
|
for {
|
||||||
|
if n == 0 {
|
||||||
|
w.Events <- newEvent("", sysFSQOVERFLOW)
|
||||||
|
w.Errors <- errors.New("short read in readEvents()")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Point "raw" to the event in the buffer
|
||||||
|
raw := (*syscall.FileNotifyInformation)(unsafe.Pointer(&watch.buf[offset]))
|
||||||
|
buf := (*[syscall.MAX_PATH]uint16)(unsafe.Pointer(&raw.FileName))
|
||||||
|
name := syscall.UTF16ToString(buf[:raw.FileNameLength/2])
|
||||||
|
fullname := filepath.Join(watch.path, name)
|
||||||
|
|
||||||
|
var mask uint64
|
||||||
|
switch raw.Action {
|
||||||
|
case syscall.FILE_ACTION_REMOVED:
|
||||||
|
mask = sysFSDELETESELF
|
||||||
|
case syscall.FILE_ACTION_MODIFIED:
|
||||||
|
mask = sysFSMODIFY
|
||||||
|
case syscall.FILE_ACTION_RENAMED_OLD_NAME:
|
||||||
|
watch.rename = name
|
||||||
|
case syscall.FILE_ACTION_RENAMED_NEW_NAME:
|
||||||
|
if watch.names[watch.rename] != 0 {
|
||||||
|
watch.names[name] |= watch.names[watch.rename]
|
||||||
|
delete(watch.names, watch.rename)
|
||||||
|
mask = sysFSMOVESELF
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sendNameEvent := func() {
|
||||||
|
if w.sendEvent(fullname, watch.names[name]&mask) {
|
||||||
|
if watch.names[name]&sysFSONESHOT != 0 {
|
||||||
|
delete(watch.names, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if raw.Action != syscall.FILE_ACTION_RENAMED_NEW_NAME {
|
||||||
|
sendNameEvent()
|
||||||
|
}
|
||||||
|
if raw.Action == syscall.FILE_ACTION_REMOVED {
|
||||||
|
w.sendEvent(fullname, watch.names[name]&sysFSIGNORED)
|
||||||
|
delete(watch.names, name)
|
||||||
|
}
|
||||||
|
if w.sendEvent(fullname, watch.mask&toFSnotifyFlags(raw.Action)) {
|
||||||
|
if watch.mask&sysFSONESHOT != 0 {
|
||||||
|
watch.mask = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if raw.Action == syscall.FILE_ACTION_RENAMED_NEW_NAME {
|
||||||
|
fullname = filepath.Join(watch.path, watch.rename)
|
||||||
|
sendNameEvent()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move to the next event in the buffer
|
||||||
|
if raw.NextEntryOffset == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
offset += raw.NextEntryOffset
|
||||||
|
|
||||||
|
// Error!
|
||||||
|
if offset >= n {
|
||||||
|
w.Errors <- errors.New("Windows system assumed buffer larger than it is, events have likely been missed.")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := w.startRead(watch); err != nil {
|
||||||
|
w.Errors <- err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Watcher) sendEvent(name string, mask uint64) bool {
|
||||||
|
if mask == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
event := newEvent(name, uint32(mask))
|
||||||
|
select {
|
||||||
|
case ch := <-w.quit:
|
||||||
|
w.quit <- ch
|
||||||
|
case w.Events <- event:
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func toWindowsFlags(mask uint64) uint32 {
|
||||||
|
var m uint32
|
||||||
|
if mask&sysFSACCESS != 0 {
|
||||||
|
m |= syscall.FILE_NOTIFY_CHANGE_LAST_ACCESS
|
||||||
|
}
|
||||||
|
if mask&sysFSMODIFY != 0 {
|
||||||
|
m |= syscall.FILE_NOTIFY_CHANGE_LAST_WRITE
|
||||||
|
}
|
||||||
|
if mask&sysFSATTRIB != 0 {
|
||||||
|
m |= syscall.FILE_NOTIFY_CHANGE_ATTRIBUTES
|
||||||
|
}
|
||||||
|
if mask&(sysFSMOVE|sysFSCREATE|sysFSDELETE) != 0 {
|
||||||
|
m |= syscall.FILE_NOTIFY_CHANGE_FILE_NAME | syscall.FILE_NOTIFY_CHANGE_DIR_NAME
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func toFSnotifyFlags(action uint32) uint64 {
|
||||||
|
switch action {
|
||||||
|
case syscall.FILE_ACTION_ADDED:
|
||||||
|
return sysFSCREATE
|
||||||
|
case syscall.FILE_ACTION_REMOVED:
|
||||||
|
return sysFSDELETE
|
||||||
|
case syscall.FILE_ACTION_MODIFIED:
|
||||||
|
return sysFSMODIFY
|
||||||
|
case syscall.FILE_ACTION_RENAMED_OLD_NAME:
|
||||||
|
return sysFSMOVEDFROM
|
||||||
|
case syscall.FILE_ACTION_RENAMED_NEW_NAME:
|
||||||
|
return sysFSMOVEDTO
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
3
vendor/github.com/golang/protobuf/AUTHORS
generated
vendored
Normal file
3
vendor/github.com/golang/protobuf/AUTHORS
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# 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
Normal file
3
vendor/github.com/golang/protobuf/CONTRIBUTORS
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# 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
Normal file
28
vendor/github.com/golang/protobuf/LICENSE
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
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
Normal file
324
vendor/github.com/golang/protobuf/proto/buffer.go
generated
vendored
Normal file
@ -0,0 +1,324 @@
|
|||||||
|
// 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
Normal file
63
vendor/github.com/golang/protobuf/proto/defaults.go
generated
vendored
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
// 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
Normal file
113
vendor/github.com/golang/protobuf/proto/deprecated.go
generated
vendored
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
// 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
Normal file
58
vendor/github.com/golang/protobuf/proto/discard.go
generated
vendored
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
// 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
Normal file
356
vendor/github.com/golang/protobuf/proto/extensions.go
generated
vendored
Normal file
@ -0,0 +1,356 @@
|
|||||||
|
// 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
Normal file
306
vendor/github.com/golang/protobuf/proto/properties.go
generated
vendored
Normal file
@ -0,0 +1,306 @@
|
|||||||
|
// 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
Normal file
167
vendor/github.com/golang/protobuf/proto/proto.go
generated
vendored
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
// 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()
|
||||||
|
}
|
317
vendor/github.com/golang/protobuf/proto/registry.go
generated
vendored
Normal file
317
vendor/github.com/golang/protobuf/proto/registry.go
generated
vendored
Normal file
@ -0,0 +1,317 @@
|
|||||||
|
// 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/protodesc"
|
||||||
|
"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 {
|
||||||
|
b, _ = Marshal(protodesc.ToFileDescriptorProto(fd))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
Normal file
801
vendor/github.com/golang/protobuf/proto/text_decode.go
generated
vendored
Normal file
@ -0,0 +1,801 @@
|
|||||||
|
// 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(rune(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
Normal file
560
vendor/github.com/golang/protobuf/proto/text_encode.go
generated
vendored
Normal file
@ -0,0 +1,560 @@
|
|||||||
|
// 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
Normal file
78
vendor/github.com/golang/protobuf/proto/wire.go
generated
vendored
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
// 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
Normal file
34
vendor/github.com/golang/protobuf/proto/wrappers.go
generated
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// 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 }
|
64
vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go
generated
vendored
Normal file
64
vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go
generated
vendored
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
// 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
|
||||||
|
}
|
201
vendor/github.com/matttproud/golang_protobuf_extensions/LICENSE
generated
vendored
Normal file
201
vendor/github.com/matttproud/golang_protobuf_extensions/LICENSE
generated
vendored
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
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
Normal file
1
vendor/github.com/matttproud/golang_protobuf_extensions/NOTICE
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
Copyright 2012 Matt T. Proud (matt.proud@gmail.com)
|
1
vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/.gitignore
generated
vendored
Normal file
1
vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/.gitignore
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
cover.dat
|
7
vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/Makefile
generated
vendored
Normal file
7
vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/Makefile
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
all:
|
||||||
|
|
||||||
|
cover:
|
||||||
|
go test -cover -v -coverprofile=cover.dat ./...
|
||||||
|
go tool cover -func cover.dat
|
||||||
|
|
||||||
|
.PHONY: cover
|
75
vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/decode.go
generated
vendored
Normal file
75
vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/decode.go
generated
vendored
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
// Copyright 2013 Matt T. Proud
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package pbutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
var errInvalidVarint = errors.New("invalid varint32 encountered")
|
||||||
|
|
||||||
|
// ReadDelimited decodes a message from the provided length-delimited stream,
|
||||||
|
// where the length is encoded as 32-bit varint prefix to the message body.
|
||||||
|
// It returns the total number of bytes read and any applicable error. This is
|
||||||
|
// roughly equivalent to the companion Java API's
|
||||||
|
// MessageLite#parseDelimitedFrom. As per the reader contract, this function
|
||||||
|
// calls r.Read repeatedly as required until exactly one message including its
|
||||||
|
// prefix is read and decoded (or an error has occurred). The function never
|
||||||
|
// reads more bytes from the stream than required. The function never returns
|
||||||
|
// an error if a message has been read and decoded correctly, even if the end
|
||||||
|
// of the stream has been reached in doing so. In that case, any subsequent
|
||||||
|
// calls return (0, io.EOF).
|
||||||
|
func ReadDelimited(r io.Reader, m proto.Message) (n int, err error) {
|
||||||
|
// Per AbstractParser#parsePartialDelimitedFrom with
|
||||||
|
// CodedInputStream#readRawVarint32.
|
||||||
|
var headerBuf [binary.MaxVarintLen32]byte
|
||||||
|
var bytesRead, varIntBytes int
|
||||||
|
var messageLength uint64
|
||||||
|
for varIntBytes == 0 { // i.e. no varint has been decoded yet.
|
||||||
|
if bytesRead >= len(headerBuf) {
|
||||||
|
return bytesRead, errInvalidVarint
|
||||||
|
}
|
||||||
|
// We have to read byte by byte here to avoid reading more bytes
|
||||||
|
// than required. Each read byte is appended to what we have
|
||||||
|
// read before.
|
||||||
|
newBytesRead, err := r.Read(headerBuf[bytesRead : bytesRead+1])
|
||||||
|
if newBytesRead == 0 {
|
||||||
|
if err != nil {
|
||||||
|
return bytesRead, err
|
||||||
|
}
|
||||||
|
// A Reader should not return (0, nil), but if it does,
|
||||||
|
// it should be treated as no-op (according to the
|
||||||
|
// Reader contract). So let's go on...
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
bytesRead += newBytesRead
|
||||||
|
// Now present everything read so far to the varint decoder and
|
||||||
|
// see if a varint can be decoded already.
|
||||||
|
messageLength, varIntBytes = proto.DecodeVarint(headerBuf[:bytesRead])
|
||||||
|
}
|
||||||
|
|
||||||
|
messageBuf := make([]byte, messageLength)
|
||||||
|
newBytesRead, err := io.ReadFull(r, messageBuf)
|
||||||
|
bytesRead += newBytesRead
|
||||||
|
if err != nil {
|
||||||
|
return bytesRead, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytesRead, proto.Unmarshal(messageBuf, m)
|
||||||
|
}
|
16
vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/doc.go
generated
vendored
Normal file
16
vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/doc.go
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// Copyright 2013 Matt T. Proud
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Package pbutil provides record length-delimited Protocol Buffer streaming.
|
||||||
|
package pbutil
|
46
vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/encode.go
generated
vendored
Normal file
46
vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/encode.go
generated
vendored
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// Copyright 2013 Matt T. Proud
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package pbutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WriteDelimited encodes and dumps a message to the provided writer prefixed
|
||||||
|
// with a 32-bit varint indicating the length of the encoded message, producing
|
||||||
|
// a length-delimited record stream, which can be used to chain together
|
||||||
|
// encoded messages of the same type together in a file. It returns the total
|
||||||
|
// number of bytes written and any applicable error. This is roughly
|
||||||
|
// equivalent to the companion Java API's MessageLite#writeDelimitedTo.
|
||||||
|
func WriteDelimited(w io.Writer, m proto.Message) (n int, err error) {
|
||||||
|
buffer, err := proto.Marshal(m)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf [binary.MaxVarintLen32]byte
|
||||||
|
encodedLength := binary.PutUvarint(buf[:], uint64(len(buffer)))
|
||||||
|
|
||||||
|
sync, err := w.Write(buf[:encodedLength])
|
||||||
|
if err != nil {
|
||||||
|
return sync, err
|
||||||
|
}
|
||||||
|
|
||||||
|
n, err = w.Write(buffer)
|
||||||
|
return n + sync, err
|
||||||
|
}
|
3
vendor/github.com/nxadm/tail/.gitignore
generated
vendored
Normal file
3
vendor/github.com/nxadm/tail/.gitignore
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.idea/
|
||||||
|
.test/
|
||||||
|
examples/_*
|
56
vendor/github.com/nxadm/tail/CHANGES.md
generated
vendored
Normal file
56
vendor/github.com/nxadm/tail/CHANGES.md
generated
vendored
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
# Version v1.4.7-v1.4.8
|
||||||
|
* Documentation updates.
|
||||||
|
* Small linter cleanups.
|
||||||
|
* Added example in test.
|
||||||
|
|
||||||
|
# Version v1.4.6
|
||||||
|
|
||||||
|
* Document the usage of Cleanup when re-reading a file (thanks to @lesovsky) for issue #18.
|
||||||
|
* Add example directories with example and tests for issues.
|
||||||
|
|
||||||
|
# Version v1.4.4-v1.4.5
|
||||||
|
|
||||||
|
* Fix of checksum problem because of forced tag. No changes to the code.
|
||||||
|
|
||||||
|
# Version v1.4.1
|
||||||
|
|
||||||
|
* Incorporated PR 162 by by Mohammed902: "Simplify non-Windows build tag".
|
||||||
|
|
||||||
|
# Version v1.4.0
|
||||||
|
|
||||||
|
* Incorporated PR 9 by mschneider82: "Added seekinfo to Tail".
|
||||||
|
|
||||||
|
# Version v1.3.1
|
||||||
|
|
||||||
|
* Incorporated PR 7: "Fix deadlock when stopping on non-empty file/buffer",
|
||||||
|
fixes upstream issue 93.
|
||||||
|
|
||||||
|
|
||||||
|
# Version v1.3.0
|
||||||
|
|
||||||
|
* Incorporated changes of unmerged upstream PR 149 by mezzi: "added line num
|
||||||
|
to Line struct".
|
||||||
|
|
||||||
|
# Version v1.2.1
|
||||||
|
|
||||||
|
* Incorporated changes of unmerged upstream PR 128 by jadekler: "Compile-able
|
||||||
|
code in readme".
|
||||||
|
* Incorporated changes of unmerged upstream PR 130 by fgeller: "small change
|
||||||
|
to comment wording".
|
||||||
|
* Incorporated changes of unmerged upstream PR 133 by sm3142: "removed
|
||||||
|
spurious newlines from log messages".
|
||||||
|
|
||||||
|
# Version v1.2.0
|
||||||
|
|
||||||
|
* Incorporated changes of unmerged upstream PR 126 by Code-Hex: "Solved the
|
||||||
|
problem for never return the last line if it's not followed by a newline".
|
||||||
|
* Incorporated changes of unmerged upstream PR 131 by StoicPerlman: "Remove
|
||||||
|
deprecated os.SEEK consts". The changes bumped the minimal supported Go
|
||||||
|
release to 1.9.
|
||||||
|
|
||||||
|
# Version v1.1.0
|
||||||
|
|
||||||
|
* migration to go modules.
|
||||||
|
* release of master branch of the dormant upstream, because it contains
|
||||||
|
fixes and improvement no present in the tagged release.
|
||||||
|
|
19
vendor/github.com/nxadm/tail/Dockerfile
generated
vendored
Normal file
19
vendor/github.com/nxadm/tail/Dockerfile
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
FROM golang
|
||||||
|
|
||||||
|
RUN mkdir -p $GOPATH/src/github.com/nxadm/tail/
|
||||||
|
ADD . $GOPATH/src/github.com/nxadm/tail/
|
||||||
|
|
||||||
|
# expecting to fetch dependencies successfully.
|
||||||
|
RUN go get -v github.com/nxadm/tail
|
||||||
|
|
||||||
|
# expecting to run the test successfully.
|
||||||
|
RUN go test -v github.com/nxadm/tail
|
||||||
|
|
||||||
|
# expecting to install successfully
|
||||||
|
RUN go install -v github.com/nxadm/tail
|
||||||
|
RUN go install -v github.com/nxadm/tail/cmd/gotail
|
||||||
|
|
||||||
|
RUN $GOPATH/bin/gotail -h || true
|
||||||
|
|
||||||
|
ENV PATH $GOPATH/bin:$PATH
|
||||||
|
CMD ["gotail"]
|
21
vendor/github.com/nxadm/tail/LICENSE
generated
vendored
Normal file
21
vendor/github.com/nxadm/tail/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# The MIT License (MIT)
|
||||||
|
|
||||||
|
# © Copyright 2015 Hewlett Packard Enterprise Development LP
|
||||||
|
Copyright (c) 2014 ActiveState
|
||||||
|
|
||||||
|
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.
|
44
vendor/github.com/nxadm/tail/README.md
generated
vendored
Normal file
44
vendor/github.com/nxadm/tail/README.md
generated
vendored
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
[](https://pkg.go.dev/github.com/nxadm/tail)
|
||||||
|
|
||||||
|
# tail functionality in Go
|
||||||
|
|
||||||
|
nxadm/tail provides a Go library that emulates the features of the BSD `tail`
|
||||||
|
program. The library comes with full support for truncation/move detection as
|
||||||
|
it is designed to work with log rotation tools. The library works on all
|
||||||
|
operating systems supported by Go, including POSIX systems like Linux and
|
||||||
|
*BSD, and MS Windows. Go 1.9 is the oldest compiler release supported.
|
||||||
|
|
||||||
|
A simple example:
|
||||||
|
|
||||||
|
```Go
|
||||||
|
// Create a tail
|
||||||
|
t, err := tail.TailFile(
|
||||||
|
"/var/log/nginx.log", tail.Config{Follow: true, ReOpen: true})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print the text of each received line
|
||||||
|
for line := range t.Lines {
|
||||||
|
fmt.Println(line.Text)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
See [API documentation](https://pkg.go.dev/github.com/nxadm/tail).
|
||||||
|
|
||||||
|
## Installing
|
||||||
|
|
||||||
|
go get github.com/nxadm/tail/...
|
||||||
|
|
||||||
|
## History
|
||||||
|
|
||||||
|
This project is an active, drop-in replacement for the
|
||||||
|
[abandoned](https://en.wikipedia.org/wiki/HPE_Helion) Go tail library at
|
||||||
|
[hpcloud](https://github.com/hpcloud/tail). Next to
|
||||||
|
[addressing open issues/PRs of the original project](https://github.com/nxadm/tail/issues/6),
|
||||||
|
nxadm/tail continues the development by keeping up to date with the Go toolchain
|
||||||
|
(e.g. go modules) and dependencies, completing the documentation, adding features
|
||||||
|
and fixing bugs.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
Examples, e.g. used to debug an issue, are kept in the [examples directory](/examples).
|
7
vendor/github.com/nxadm/tail/ratelimiter/Licence
generated
vendored
Normal file
7
vendor/github.com/nxadm/tail/ratelimiter/Licence
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
Copyright (C) 2013 99designs
|
||||||
|
|
||||||
|
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.
|
97
vendor/github.com/nxadm/tail/ratelimiter/leakybucket.go
generated
vendored
Normal file
97
vendor/github.com/nxadm/tail/ratelimiter/leakybucket.go
generated
vendored
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
// Package ratelimiter implements the Leaky Bucket ratelimiting algorithm with memcached and in-memory backends.
|
||||||
|
package ratelimiter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LeakyBucket struct {
|
||||||
|
Size uint16
|
||||||
|
Fill float64
|
||||||
|
LeakInterval time.Duration // time.Duration for 1 unit of size to leak
|
||||||
|
Lastupdate time.Time
|
||||||
|
Now func() time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLeakyBucket(size uint16, leakInterval time.Duration) *LeakyBucket {
|
||||||
|
bucket := LeakyBucket{
|
||||||
|
Size: size,
|
||||||
|
Fill: 0,
|
||||||
|
LeakInterval: leakInterval,
|
||||||
|
Now: time.Now,
|
||||||
|
Lastupdate: time.Now(),
|
||||||
|
}
|
||||||
|
|
||||||
|
return &bucket
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *LeakyBucket) updateFill() {
|
||||||
|
now := b.Now()
|
||||||
|
if b.Fill > 0 {
|
||||||
|
elapsed := now.Sub(b.Lastupdate)
|
||||||
|
|
||||||
|
b.Fill -= float64(elapsed) / float64(b.LeakInterval)
|
||||||
|
if b.Fill < 0 {
|
||||||
|
b.Fill = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b.Lastupdate = now
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *LeakyBucket) Pour(amount uint16) bool {
|
||||||
|
b.updateFill()
|
||||||
|
|
||||||
|
var newfill float64 = b.Fill + float64(amount)
|
||||||
|
|
||||||
|
if newfill > float64(b.Size) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
b.Fill = newfill
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// The time at which this bucket will be completely drained
|
||||||
|
func (b *LeakyBucket) DrainedAt() time.Time {
|
||||||
|
return b.Lastupdate.Add(time.Duration(b.Fill * float64(b.LeakInterval)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// The duration until this bucket is completely drained
|
||||||
|
func (b *LeakyBucket) TimeToDrain() time.Duration {
|
||||||
|
return b.DrainedAt().Sub(b.Now())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *LeakyBucket) TimeSinceLastUpdate() time.Duration {
|
||||||
|
return b.Now().Sub(b.Lastupdate)
|
||||||
|
}
|
||||||
|
|
||||||
|
type LeakyBucketSer struct {
|
||||||
|
Size uint16
|
||||||
|
Fill float64
|
||||||
|
LeakInterval time.Duration // time.Duration for 1 unit of size to leak
|
||||||
|
Lastupdate time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *LeakyBucket) Serialise() *LeakyBucketSer {
|
||||||
|
bucket := LeakyBucketSer{
|
||||||
|
Size: b.Size,
|
||||||
|
Fill: b.Fill,
|
||||||
|
LeakInterval: b.LeakInterval,
|
||||||
|
Lastupdate: b.Lastupdate,
|
||||||
|
}
|
||||||
|
|
||||||
|
return &bucket
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *LeakyBucketSer) DeSerialise() *LeakyBucket {
|
||||||
|
bucket := LeakyBucket{
|
||||||
|
Size: b.Size,
|
||||||
|
Fill: b.Fill,
|
||||||
|
LeakInterval: b.LeakInterval,
|
||||||
|
Lastupdate: b.Lastupdate,
|
||||||
|
Now: time.Now,
|
||||||
|
}
|
||||||
|
|
||||||
|
return &bucket
|
||||||
|
}
|
60
vendor/github.com/nxadm/tail/ratelimiter/memory.go
generated
vendored
Normal file
60
vendor/github.com/nxadm/tail/ratelimiter/memory.go
generated
vendored
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package ratelimiter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
GC_SIZE int = 100
|
||||||
|
GC_PERIOD time.Duration = 60 * time.Second
|
||||||
|
)
|
||||||
|
|
||||||
|
type Memory struct {
|
||||||
|
store map[string]LeakyBucket
|
||||||
|
lastGCCollected time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMemory() *Memory {
|
||||||
|
m := new(Memory)
|
||||||
|
m.store = make(map[string]LeakyBucket)
|
||||||
|
m.lastGCCollected = time.Now()
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Memory) GetBucketFor(key string) (*LeakyBucket, error) {
|
||||||
|
|
||||||
|
bucket, ok := m.store[key]
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("miss")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &bucket, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Memory) SetBucketFor(key string, bucket LeakyBucket) error {
|
||||||
|
|
||||||
|
if len(m.store) > GC_SIZE {
|
||||||
|
m.GarbageCollect()
|
||||||
|
}
|
||||||
|
|
||||||
|
m.store[key] = bucket
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Memory) GarbageCollect() {
|
||||||
|
now := time.Now()
|
||||||
|
|
||||||
|
// rate limit GC to once per minute
|
||||||
|
if now.Unix() >= m.lastGCCollected.Add(GC_PERIOD).Unix() {
|
||||||
|
for key, bucket := range m.store {
|
||||||
|
// if the bucket is drained, then GC
|
||||||
|
if bucket.DrainedAt().Unix() < now.Unix() {
|
||||||
|
delete(m.store, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m.lastGCCollected = now
|
||||||
|
}
|
||||||
|
}
|
6
vendor/github.com/nxadm/tail/ratelimiter/storage.go
generated
vendored
Normal file
6
vendor/github.com/nxadm/tail/ratelimiter/storage.go
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package ratelimiter
|
||||||
|
|
||||||
|
type Storage interface {
|
||||||
|
GetBucketFor(string) (*LeakyBucket, error)
|
||||||
|
SetBucketFor(string, LeakyBucket) error
|
||||||
|
}
|
455
vendor/github.com/nxadm/tail/tail.go
generated
vendored
Normal file
455
vendor/github.com/nxadm/tail/tail.go
generated
vendored
Normal file
@ -0,0 +1,455 @@
|
|||||||
|
// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail
|
||||||
|
// Copyright (c) 2015 HPE Software Inc. All rights reserved.
|
||||||
|
// Copyright (c) 2013 ActiveState Software Inc. All rights reserved.
|
||||||
|
|
||||||
|
//nxadm/tail provides a Go library that emulates the features of the BSD `tail`
|
||||||
|
//program. The library comes with full support for truncation/move detection as
|
||||||
|
//it is designed to work with log rotation tools. The library works on all
|
||||||
|
//operating systems supported by Go, including POSIX systems like Linux and
|
||||||
|
//*BSD, and MS Windows. Go 1.9 is the oldest compiler release supported.
|
||||||
|
package tail
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/nxadm/tail/ratelimiter"
|
||||||
|
"github.com/nxadm/tail/util"
|
||||||
|
"github.com/nxadm/tail/watch"
|
||||||
|
"gopkg.in/tomb.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrStop is returned when the tail of a file has been marked to be stopped.
|
||||||
|
ErrStop = errors.New("tail should now stop")
|
||||||
|
)
|
||||||
|
|
||||||
|
type Line struct {
|
||||||
|
Text string // The contents of the file
|
||||||
|
Num int // The line number
|
||||||
|
SeekInfo SeekInfo // SeekInfo
|
||||||
|
Time time.Time // Present time
|
||||||
|
Err error // Error from tail
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: this function is no longer used internally and it has little of no
|
||||||
|
// use in the API. As such, it will be removed from the API in a future major
|
||||||
|
// release.
|
||||||
|
//
|
||||||
|
// NewLine returns a * pointer to a Line struct.
|
||||||
|
func NewLine(text string, lineNum int) *Line {
|
||||||
|
return &Line{text, lineNum, SeekInfo{}, time.Now(), nil}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SeekInfo represents arguments to io.Seek. See: https://golang.org/pkg/io/#SectionReader.Seek
|
||||||
|
type SeekInfo struct {
|
||||||
|
Offset int64
|
||||||
|
Whence int
|
||||||
|
}
|
||||||
|
|
||||||
|
type logger interface {
|
||||||
|
Fatal(v ...interface{})
|
||||||
|
Fatalf(format string, v ...interface{})
|
||||||
|
Fatalln(v ...interface{})
|
||||||
|
Panic(v ...interface{})
|
||||||
|
Panicf(format string, v ...interface{})
|
||||||
|
Panicln(v ...interface{})
|
||||||
|
Print(v ...interface{})
|
||||||
|
Printf(format string, v ...interface{})
|
||||||
|
Println(v ...interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Config is used to specify how a file must be tailed.
|
||||||
|
type Config struct {
|
||||||
|
// File-specifc
|
||||||
|
Location *SeekInfo // Tail from this location. If nil, start at the beginning of the file
|
||||||
|
ReOpen bool // Reopen recreated files (tail -F)
|
||||||
|
MustExist bool // Fail early if the file does not exist
|
||||||
|
Poll bool // Poll for file changes instead of using the default inotify
|
||||||
|
Pipe bool // The file is a named pipe (mkfifo)
|
||||||
|
|
||||||
|
// Generic IO
|
||||||
|
Follow bool // Continue looking for new lines (tail -f)
|
||||||
|
MaxLineSize int // If non-zero, split longer lines into multiple lines
|
||||||
|
|
||||||
|
// Optionally, use a ratelimiter (e.g. created by the ratelimiter/NewLeakyBucket function)
|
||||||
|
RateLimiter *ratelimiter.LeakyBucket
|
||||||
|
|
||||||
|
// Optionally use a Logger. When nil, the Logger is set to tail.DefaultLogger.
|
||||||
|
// To disable logging, set it to tail.DiscardingLogger
|
||||||
|
Logger logger
|
||||||
|
}
|
||||||
|
|
||||||
|
type Tail struct {
|
||||||
|
Filename string // The filename
|
||||||
|
Lines chan *Line // A consumable channel of *Line
|
||||||
|
Config // Tail.Configuration
|
||||||
|
|
||||||
|
file *os.File
|
||||||
|
reader *bufio.Reader
|
||||||
|
lineNum int
|
||||||
|
|
||||||
|
watcher watch.FileWatcher
|
||||||
|
changes *watch.FileChanges
|
||||||
|
|
||||||
|
tomb.Tomb // provides: Done, Kill, Dying
|
||||||
|
|
||||||
|
lk sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// DefaultLogger logs to os.Stderr and it is used when Config.Logger == nil
|
||||||
|
DefaultLogger = log.New(os.Stderr, "", log.LstdFlags)
|
||||||
|
// DiscardingLogger can be used to disable logging output
|
||||||
|
DiscardingLogger = log.New(ioutil.Discard, "", 0)
|
||||||
|
)
|
||||||
|
|
||||||
|
// TailFile begins tailing the file. And returns a pointer to a Tail struct
|
||||||
|
// and an error. An output stream is made available via the Tail.Lines
|
||||||
|
// channel (e.g. to be looped and printed). To handle errors during tailing,
|
||||||
|
// after finishing reading from the Lines channel, invoke the `Wait` or `Err`
|
||||||
|
// method on the returned *Tail.
|
||||||
|
func TailFile(filename string, config Config) (*Tail, error) {
|
||||||
|
if config.ReOpen && !config.Follow {
|
||||||
|
util.Fatal("cannot set ReOpen without Follow.")
|
||||||
|
}
|
||||||
|
|
||||||
|
t := &Tail{
|
||||||
|
Filename: filename,
|
||||||
|
Lines: make(chan *Line),
|
||||||
|
Config: config,
|
||||||
|
}
|
||||||
|
|
||||||
|
// when Logger was not specified in config, use default logger
|
||||||
|
if t.Logger == nil {
|
||||||
|
t.Logger = DefaultLogger
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.Poll {
|
||||||
|
t.watcher = watch.NewPollingFileWatcher(filename)
|
||||||
|
} else {
|
||||||
|
t.watcher = watch.NewInotifyFileWatcher(filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.MustExist {
|
||||||
|
var err error
|
||||||
|
t.file, err = OpenFile(t.Filename)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
go t.tailFileSync()
|
||||||
|
|
||||||
|
return t, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tell returns the file's current position, like stdio's ftell() and an error.
|
||||||
|
// Beware that this value may not be completely accurate because one line from
|
||||||
|
// the chan(tail.Lines) may have been read already.
|
||||||
|
func (tail *Tail) Tell() (offset int64, err error) {
|
||||||
|
if tail.file == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
offset, err = tail.file.Seek(0, io.SeekCurrent)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tail.lk.Lock()
|
||||||
|
defer tail.lk.Unlock()
|
||||||
|
if tail.reader == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
offset -= int64(tail.reader.Buffered())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop stops the tailing activity.
|
||||||
|
func (tail *Tail) Stop() error {
|
||||||
|
tail.Kill(nil)
|
||||||
|
return tail.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
// StopAtEOF stops tailing as soon as the end of the file is reached. The function
|
||||||
|
// returns an error,
|
||||||
|
func (tail *Tail) StopAtEOF() error {
|
||||||
|
tail.Kill(errStopAtEOF)
|
||||||
|
return tail.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
var errStopAtEOF = errors.New("tail: stop at eof")
|
||||||
|
|
||||||
|
func (tail *Tail) close() {
|
||||||
|
close(tail.Lines)
|
||||||
|
tail.closeFile()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tail *Tail) closeFile() {
|
||||||
|
if tail.file != nil {
|
||||||
|
tail.file.Close()
|
||||||
|
tail.file = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tail *Tail) reopen() error {
|
||||||
|
tail.closeFile()
|
||||||
|
tail.lineNum = 0
|
||||||
|
for {
|
||||||
|
var err error
|
||||||
|
tail.file, err = OpenFile(tail.Filename)
|
||||||
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
tail.Logger.Printf("Waiting for %s to appear...", tail.Filename)
|
||||||
|
if err := tail.watcher.BlockUntilExists(&tail.Tomb); err != nil {
|
||||||
|
if err == tomb.ErrDying {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return fmt.Errorf("Failed to detect creation of %s: %s", tail.Filename, err)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return fmt.Errorf("Unable to open file %s: %s", tail.Filename, err)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tail *Tail) readLine() (string, error) {
|
||||||
|
tail.lk.Lock()
|
||||||
|
line, err := tail.reader.ReadString('\n')
|
||||||
|
tail.lk.Unlock()
|
||||||
|
if err != nil {
|
||||||
|
// Note ReadString "returns the data read before the error" in
|
||||||
|
// case of an error, including EOF, so we return it as is. The
|
||||||
|
// caller is expected to process it if err is EOF.
|
||||||
|
return line, err
|
||||||
|
}
|
||||||
|
|
||||||
|
line = strings.TrimRight(line, "\n")
|
||||||
|
|
||||||
|
return line, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tail *Tail) tailFileSync() {
|
||||||
|
defer tail.Done()
|
||||||
|
defer tail.close()
|
||||||
|
|
||||||
|
if !tail.MustExist {
|
||||||
|
// deferred first open.
|
||||||
|
err := tail.reopen()
|
||||||
|
if err != nil {
|
||||||
|
if err != tomb.ErrDying {
|
||||||
|
tail.Kill(err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Seek to requested location on first open of the file.
|
||||||
|
if tail.Location != nil {
|
||||||
|
_, err := tail.file.Seek(tail.Location.Offset, tail.Location.Whence)
|
||||||
|
if err != nil {
|
||||||
|
tail.Killf("Seek error on %s: %s", tail.Filename, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tail.openReader()
|
||||||
|
|
||||||
|
// Read line by line.
|
||||||
|
for {
|
||||||
|
// do not seek in named pipes
|
||||||
|
if !tail.Pipe {
|
||||||
|
// grab the position in case we need to back up in the event of a half-line
|
||||||
|
if _, err := tail.Tell(); err != nil {
|
||||||
|
tail.Kill(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
line, err := tail.readLine()
|
||||||
|
|
||||||
|
// Process `line` even if err is EOF.
|
||||||
|
if err == nil {
|
||||||
|
cooloff := !tail.sendLine(line)
|
||||||
|
if cooloff {
|
||||||
|
// Wait a second before seeking till the end of
|
||||||
|
// file when rate limit is reached.
|
||||||
|
msg := ("Too much log activity; waiting a second before resuming tailing")
|
||||||
|
offset, _ := tail.Tell()
|
||||||
|
tail.Lines <- &Line{msg, tail.lineNum, SeekInfo{Offset: offset}, time.Now(), errors.New(msg)}
|
||||||
|
select {
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
case <-tail.Dying():
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := tail.seekEnd(); err != nil {
|
||||||
|
tail.Kill(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if err == io.EOF {
|
||||||
|
if !tail.Follow {
|
||||||
|
if line != "" {
|
||||||
|
tail.sendLine(line)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if tail.Follow && line != "" {
|
||||||
|
tail.sendLine(line)
|
||||||
|
if err := tail.seekEnd(); err != nil {
|
||||||
|
tail.Kill(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// When EOF is reached, wait for more data to become
|
||||||
|
// available. Wait strategy is based on the `tail.watcher`
|
||||||
|
// implementation (inotify or polling).
|
||||||
|
err := tail.waitForChanges()
|
||||||
|
if err != nil {
|
||||||
|
if err != ErrStop {
|
||||||
|
tail.Kill(err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// non-EOF error
|
||||||
|
tail.Killf("Error reading %s: %s", tail.Filename, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-tail.Dying():
|
||||||
|
if tail.Err() == errStopAtEOF {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// waitForChanges waits until the file has been appended, deleted,
|
||||||
|
// moved or truncated. When moved or deleted - the file will be
|
||||||
|
// reopened if ReOpen is true. Truncated files are always reopened.
|
||||||
|
func (tail *Tail) waitForChanges() error {
|
||||||
|
if tail.changes == nil {
|
||||||
|
pos, err := tail.file.Seek(0, io.SeekCurrent)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
tail.changes, err = tail.watcher.ChangeEvents(&tail.Tomb, pos)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-tail.changes.Modified:
|
||||||
|
return nil
|
||||||
|
case <-tail.changes.Deleted:
|
||||||
|
tail.changes = nil
|
||||||
|
if tail.ReOpen {
|
||||||
|
// XXX: we must not log from a library.
|
||||||
|
tail.Logger.Printf("Re-opening moved/deleted file %s ...", tail.Filename)
|
||||||
|
if err := tail.reopen(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
tail.Logger.Printf("Successfully reopened %s", tail.Filename)
|
||||||
|
tail.openReader()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
tail.Logger.Printf("Stopping tail as file no longer exists: %s", tail.Filename)
|
||||||
|
return ErrStop
|
||||||
|
case <-tail.changes.Truncated:
|
||||||
|
// Always reopen truncated files (Follow is true)
|
||||||
|
tail.Logger.Printf("Re-opening truncated file %s ...", tail.Filename)
|
||||||
|
if err := tail.reopen(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
tail.Logger.Printf("Successfully reopened truncated %s", tail.Filename)
|
||||||
|
tail.openReader()
|
||||||
|
return nil
|
||||||
|
case <-tail.Dying():
|
||||||
|
return ErrStop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tail *Tail) openReader() {
|
||||||
|
tail.lk.Lock()
|
||||||
|
if tail.MaxLineSize > 0 {
|
||||||
|
// add 2 to account for newline characters
|
||||||
|
tail.reader = bufio.NewReaderSize(tail.file, tail.MaxLineSize+2)
|
||||||
|
} else {
|
||||||
|
tail.reader = bufio.NewReader(tail.file)
|
||||||
|
}
|
||||||
|
tail.lk.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tail *Tail) seekEnd() error {
|
||||||
|
return tail.seekTo(SeekInfo{Offset: 0, Whence: io.SeekEnd})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tail *Tail) seekTo(pos SeekInfo) error {
|
||||||
|
_, err := tail.file.Seek(pos.Offset, pos.Whence)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Seek error on %s: %s", tail.Filename, err)
|
||||||
|
}
|
||||||
|
// Reset the read buffer whenever the file is re-seek'ed
|
||||||
|
tail.reader.Reset(tail.file)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// sendLine sends the line(s) to Lines channel, splitting longer lines
|
||||||
|
// if necessary. Return false if rate limit is reached.
|
||||||
|
func (tail *Tail) sendLine(line string) bool {
|
||||||
|
now := time.Now()
|
||||||
|
lines := []string{line}
|
||||||
|
|
||||||
|
// Split longer lines
|
||||||
|
if tail.MaxLineSize > 0 && len(line) > tail.MaxLineSize {
|
||||||
|
lines = util.PartitionString(line, tail.MaxLineSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, line := range lines {
|
||||||
|
tail.lineNum++
|
||||||
|
offset, _ := tail.Tell()
|
||||||
|
select {
|
||||||
|
case tail.Lines <- &Line{line, tail.lineNum, SeekInfo{Offset: offset}, now, nil}:
|
||||||
|
case <-tail.Dying():
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if tail.Config.RateLimiter != nil {
|
||||||
|
ok := tail.Config.RateLimiter.Pour(uint16(len(lines)))
|
||||||
|
if !ok {
|
||||||
|
tail.Logger.Printf("Leaky bucket full (%v); entering 1s cooloff period.",
|
||||||
|
tail.Filename)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup removes inotify watches added by the tail package. This function is
|
||||||
|
// meant to be invoked from a process's exit handler. Linux kernel may not
|
||||||
|
// automatically remove inotify watches after the process exits.
|
||||||
|
// If you plan to re-read a file, don't call Cleanup in between.
|
||||||
|
func (tail *Tail) Cleanup() {
|
||||||
|
watch.Cleanup(tail.Filename)
|
||||||
|
}
|
17
vendor/github.com/nxadm/tail/tail_posix.go
generated
vendored
Normal file
17
vendor/github.com/nxadm/tail/tail_posix.go
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package tail
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Deprecated: this function is only useful internally and, as such,
|
||||||
|
// it will be removed from the API in a future major release.
|
||||||
|
//
|
||||||
|
// OpenFile proxies a os.Open call for a file so it can be correctly tailed
|
||||||
|
// on POSIX and non-POSIX OSes like MS Windows.
|
||||||
|
func OpenFile(name string) (file *os.File, err error) {
|
||||||
|
return os.Open(name)
|
||||||
|
}
|
19
vendor/github.com/nxadm/tail/tail_windows.go
generated
vendored
Normal file
19
vendor/github.com/nxadm/tail/tail_windows.go
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package tail
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/nxadm/tail/winfile"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Deprecated: this function is only useful internally and, as such,
|
||||||
|
// it will be removed from the API in a future major release.
|
||||||
|
//
|
||||||
|
// OpenFile proxies a os.Open call for a file so it can be correctly tailed
|
||||||
|
// on POSIX and non-POSIX OSes like MS Windows.
|
||||||
|
func OpenFile(name string) (file *os.File, err error) {
|
||||||
|
return winfile.OpenFile(name, os.O_RDONLY, 0)
|
||||||
|
}
|
49
vendor/github.com/nxadm/tail/util/util.go
generated
vendored
Normal file
49
vendor/github.com/nxadm/tail/util/util.go
generated
vendored
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail
|
||||||
|
// Copyright (c) 2015 HPE Software Inc. All rights reserved.
|
||||||
|
// Copyright (c) 2013 ActiveState Software Inc. All rights reserved.
|
||||||
|
|
||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"runtime/debug"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Logger struct {
|
||||||
|
*log.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
var LOGGER = &Logger{log.New(os.Stderr, "", log.LstdFlags)}
|
||||||
|
|
||||||
|
// fatal is like panic except it displays only the current goroutine's stack.
|
||||||
|
func Fatal(format string, v ...interface{}) {
|
||||||
|
// https://github.com/nxadm/log/blob/master/log.go#L45
|
||||||
|
LOGGER.Output(2, fmt.Sprintf("FATAL -- "+format, v...)+"\n"+string(debug.Stack()))
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// partitionString partitions the string into chunks of given size,
|
||||||
|
// with the last chunk of variable size.
|
||||||
|
func PartitionString(s string, chunkSize int) []string {
|
||||||
|
if chunkSize <= 0 {
|
||||||
|
panic("invalid chunkSize")
|
||||||
|
}
|
||||||
|
length := len(s)
|
||||||
|
chunks := 1 + length/chunkSize
|
||||||
|
start := 0
|
||||||
|
end := chunkSize
|
||||||
|
parts := make([]string, 0, chunks)
|
||||||
|
for {
|
||||||
|
if end > length {
|
||||||
|
end = length
|
||||||
|
}
|
||||||
|
parts = append(parts, s[start:end])
|
||||||
|
if end == length {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
start, end = end, end+chunkSize
|
||||||
|
}
|
||||||
|
return parts
|
||||||
|
}
|
37
vendor/github.com/nxadm/tail/watch/filechanges.go
generated
vendored
Normal file
37
vendor/github.com/nxadm/tail/watch/filechanges.go
generated
vendored
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail
|
||||||
|
package watch
|
||||||
|
|
||||||
|
type FileChanges struct {
|
||||||
|
Modified chan bool // Channel to get notified of modifications
|
||||||
|
Truncated chan bool // Channel to get notified of truncations
|
||||||
|
Deleted chan bool // Channel to get notified of deletions/renames
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFileChanges() *FileChanges {
|
||||||
|
return &FileChanges{
|
||||||
|
make(chan bool, 1), make(chan bool, 1), make(chan bool, 1)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fc *FileChanges) NotifyModified() {
|
||||||
|
sendOnlyIfEmpty(fc.Modified)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fc *FileChanges) NotifyTruncated() {
|
||||||
|
sendOnlyIfEmpty(fc.Truncated)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fc *FileChanges) NotifyDeleted() {
|
||||||
|
sendOnlyIfEmpty(fc.Deleted)
|
||||||
|
}
|
||||||
|
|
||||||
|
// sendOnlyIfEmpty sends on a bool channel only if the channel has no
|
||||||
|
// backlog to be read by other goroutines. This concurrency pattern
|
||||||
|
// can be used to notify other goroutines if and only if they are
|
||||||
|
// looking for it (i.e., subsequent notifications can be compressed
|
||||||
|
// into one).
|
||||||
|
func sendOnlyIfEmpty(ch chan bool) {
|
||||||
|
select {
|
||||||
|
case ch <- true:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
136
vendor/github.com/nxadm/tail/watch/inotify.go
generated
vendored
Normal file
136
vendor/github.com/nxadm/tail/watch/inotify.go
generated
vendored
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail
|
||||||
|
// Copyright (c) 2015 HPE Software Inc. All rights reserved.
|
||||||
|
// Copyright (c) 2013 ActiveState Software Inc. All rights reserved.
|
||||||
|
|
||||||
|
package watch
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/nxadm/tail/util"
|
||||||
|
|
||||||
|
"github.com/fsnotify/fsnotify"
|
||||||
|
"gopkg.in/tomb.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// InotifyFileWatcher uses inotify to monitor file changes.
|
||||||
|
type InotifyFileWatcher struct {
|
||||||
|
Filename string
|
||||||
|
Size int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewInotifyFileWatcher(filename string) *InotifyFileWatcher {
|
||||||
|
fw := &InotifyFileWatcher{filepath.Clean(filename), 0}
|
||||||
|
return fw
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fw *InotifyFileWatcher) BlockUntilExists(t *tomb.Tomb) error {
|
||||||
|
err := WatchCreate(fw.Filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer RemoveWatchCreate(fw.Filename)
|
||||||
|
|
||||||
|
// Do a real check now as the file might have been created before
|
||||||
|
// calling `WatchFlags` above.
|
||||||
|
if _, err = os.Stat(fw.Filename); !os.IsNotExist(err) {
|
||||||
|
// file exists, or stat returned an error.
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
events := Events(fw.Filename)
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case evt, ok := <-events:
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("inotify watcher has been closed")
|
||||||
|
}
|
||||||
|
evtName, err := filepath.Abs(evt.Name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fwFilename, err := filepath.Abs(fw.Filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if evtName == fwFilename {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case <-t.Dying():
|
||||||
|
return tomb.ErrDying
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fw *InotifyFileWatcher) ChangeEvents(t *tomb.Tomb, pos int64) (*FileChanges, error) {
|
||||||
|
err := Watch(fw.Filename)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
changes := NewFileChanges()
|
||||||
|
fw.Size = pos
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
|
||||||
|
events := Events(fw.Filename)
|
||||||
|
|
||||||
|
for {
|
||||||
|
prevSize := fw.Size
|
||||||
|
|
||||||
|
var evt fsnotify.Event
|
||||||
|
var ok bool
|
||||||
|
|
||||||
|
select {
|
||||||
|
case evt, ok = <-events:
|
||||||
|
if !ok {
|
||||||
|
RemoveWatch(fw.Filename)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case <-t.Dying():
|
||||||
|
RemoveWatch(fw.Filename)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case evt.Op&fsnotify.Remove == fsnotify.Remove:
|
||||||
|
fallthrough
|
||||||
|
|
||||||
|
case evt.Op&fsnotify.Rename == fsnotify.Rename:
|
||||||
|
RemoveWatch(fw.Filename)
|
||||||
|
changes.NotifyDeleted()
|
||||||
|
return
|
||||||
|
|
||||||
|
//With an open fd, unlink(fd) - inotify returns IN_ATTRIB (==fsnotify.Chmod)
|
||||||
|
case evt.Op&fsnotify.Chmod == fsnotify.Chmod:
|
||||||
|
fallthrough
|
||||||
|
|
||||||
|
case evt.Op&fsnotify.Write == fsnotify.Write:
|
||||||
|
fi, err := os.Stat(fw.Filename)
|
||||||
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
RemoveWatch(fw.Filename)
|
||||||
|
changes.NotifyDeleted()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// XXX: report this error back to the user
|
||||||
|
util.Fatal("Failed to stat file %v: %v", fw.Filename, err)
|
||||||
|
}
|
||||||
|
fw.Size = fi.Size()
|
||||||
|
|
||||||
|
if prevSize > 0 && prevSize > fw.Size {
|
||||||
|
changes.NotifyTruncated()
|
||||||
|
} else {
|
||||||
|
changes.NotifyModified()
|
||||||
|
}
|
||||||
|
prevSize = fw.Size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return changes, nil
|
||||||
|
}
|
249
vendor/github.com/nxadm/tail/watch/inotify_tracker.go
generated
vendored
Normal file
249
vendor/github.com/nxadm/tail/watch/inotify_tracker.go
generated
vendored
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail
|
||||||
|
// Copyright (c) 2015 HPE Software Inc. All rights reserved.
|
||||||
|
// Copyright (c) 2013 ActiveState Software Inc. All rights reserved.
|
||||||
|
|
||||||
|
package watch
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"sync"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/nxadm/tail/util"
|
||||||
|
|
||||||
|
"github.com/fsnotify/fsnotify"
|
||||||
|
)
|
||||||
|
|
||||||
|
type InotifyTracker struct {
|
||||||
|
mux sync.Mutex
|
||||||
|
watcher *fsnotify.Watcher
|
||||||
|
chans map[string]chan fsnotify.Event
|
||||||
|
done map[string]chan bool
|
||||||
|
watchNums map[string]int
|
||||||
|
watch chan *watchInfo
|
||||||
|
remove chan *watchInfo
|
||||||
|
error chan error
|
||||||
|
}
|
||||||
|
|
||||||
|
type watchInfo struct {
|
||||||
|
op fsnotify.Op
|
||||||
|
fname string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *watchInfo) isCreate() bool {
|
||||||
|
return this.op == fsnotify.Create
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// globally shared InotifyTracker; ensures only one fsnotify.Watcher is used
|
||||||
|
shared *InotifyTracker
|
||||||
|
|
||||||
|
// these are used to ensure the shared InotifyTracker is run exactly once
|
||||||
|
once = sync.Once{}
|
||||||
|
goRun = func() {
|
||||||
|
shared = &InotifyTracker{
|
||||||
|
mux: sync.Mutex{},
|
||||||
|
chans: make(map[string]chan fsnotify.Event),
|
||||||
|
done: make(map[string]chan bool),
|
||||||
|
watchNums: make(map[string]int),
|
||||||
|
watch: make(chan *watchInfo),
|
||||||
|
remove: make(chan *watchInfo),
|
||||||
|
error: make(chan error),
|
||||||
|
}
|
||||||
|
go shared.run()
|
||||||
|
}
|
||||||
|
|
||||||
|
logger = log.New(os.Stderr, "", log.LstdFlags)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Watch signals the run goroutine to begin watching the input filename
|
||||||
|
func Watch(fname string) error {
|
||||||
|
return watch(&watchInfo{
|
||||||
|
fname: fname,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Watch create signals the run goroutine to begin watching the input filename
|
||||||
|
// if call the WatchCreate function, don't call the Cleanup, call the RemoveWatchCreate
|
||||||
|
func WatchCreate(fname string) error {
|
||||||
|
return watch(&watchInfo{
|
||||||
|
op: fsnotify.Create,
|
||||||
|
fname: fname,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func watch(winfo *watchInfo) error {
|
||||||
|
// start running the shared InotifyTracker if not already running
|
||||||
|
once.Do(goRun)
|
||||||
|
|
||||||
|
winfo.fname = filepath.Clean(winfo.fname)
|
||||||
|
shared.watch <- winfo
|
||||||
|
return <-shared.error
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveWatch signals the run goroutine to remove the watch for the input filename
|
||||||
|
func RemoveWatch(fname string) error {
|
||||||
|
return remove(&watchInfo{
|
||||||
|
fname: fname,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveWatch create signals the run goroutine to remove the watch for the input filename
|
||||||
|
func RemoveWatchCreate(fname string) error {
|
||||||
|
return remove(&watchInfo{
|
||||||
|
op: fsnotify.Create,
|
||||||
|
fname: fname,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func remove(winfo *watchInfo) error {
|
||||||
|
// start running the shared InotifyTracker if not already running
|
||||||
|
once.Do(goRun)
|
||||||
|
|
||||||
|
winfo.fname = filepath.Clean(winfo.fname)
|
||||||
|
shared.mux.Lock()
|
||||||
|
done := shared.done[winfo.fname]
|
||||||
|
if done != nil {
|
||||||
|
delete(shared.done, winfo.fname)
|
||||||
|
close(done)
|
||||||
|
}
|
||||||
|
shared.mux.Unlock()
|
||||||
|
|
||||||
|
shared.remove <- winfo
|
||||||
|
return <-shared.error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Events returns a channel to which FileEvents corresponding to the input filename
|
||||||
|
// will be sent. This channel will be closed when removeWatch is called on this
|
||||||
|
// filename.
|
||||||
|
func Events(fname string) <-chan fsnotify.Event {
|
||||||
|
shared.mux.Lock()
|
||||||
|
defer shared.mux.Unlock()
|
||||||
|
|
||||||
|
return shared.chans[fname]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup removes the watch for the input filename if necessary.
|
||||||
|
func Cleanup(fname string) error {
|
||||||
|
return RemoveWatch(fname)
|
||||||
|
}
|
||||||
|
|
||||||
|
// watchFlags calls fsnotify.WatchFlags for the input filename and flags, creating
|
||||||
|
// a new Watcher if the previous Watcher was closed.
|
||||||
|
func (shared *InotifyTracker) addWatch(winfo *watchInfo) error {
|
||||||
|
shared.mux.Lock()
|
||||||
|
defer shared.mux.Unlock()
|
||||||
|
|
||||||
|
if shared.chans[winfo.fname] == nil {
|
||||||
|
shared.chans[winfo.fname] = make(chan fsnotify.Event)
|
||||||
|
}
|
||||||
|
if shared.done[winfo.fname] == nil {
|
||||||
|
shared.done[winfo.fname] = make(chan bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
fname := winfo.fname
|
||||||
|
if winfo.isCreate() {
|
||||||
|
// Watch for new files to be created in the parent directory.
|
||||||
|
fname = filepath.Dir(fname)
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
// already in inotify watch
|
||||||
|
if shared.watchNums[fname] == 0 {
|
||||||
|
err = shared.watcher.Add(fname)
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
shared.watchNums[fname]++
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// removeWatch calls fsnotify.RemoveWatch for the input filename and closes the
|
||||||
|
// corresponding events channel.
|
||||||
|
func (shared *InotifyTracker) removeWatch(winfo *watchInfo) error {
|
||||||
|
shared.mux.Lock()
|
||||||
|
|
||||||
|
ch := shared.chans[winfo.fname]
|
||||||
|
if ch != nil {
|
||||||
|
delete(shared.chans, winfo.fname)
|
||||||
|
close(ch)
|
||||||
|
}
|
||||||
|
|
||||||
|
fname := winfo.fname
|
||||||
|
if winfo.isCreate() {
|
||||||
|
// Watch for new files to be created in the parent directory.
|
||||||
|
fname = filepath.Dir(fname)
|
||||||
|
}
|
||||||
|
shared.watchNums[fname]--
|
||||||
|
watchNum := shared.watchNums[fname]
|
||||||
|
if watchNum == 0 {
|
||||||
|
delete(shared.watchNums, fname)
|
||||||
|
}
|
||||||
|
shared.mux.Unlock()
|
||||||
|
|
||||||
|
var err error
|
||||||
|
// If we were the last ones to watch this file, unsubscribe from inotify.
|
||||||
|
// This needs to happen after releasing the lock because fsnotify waits
|
||||||
|
// synchronously for the kernel to acknowledge the removal of the watch
|
||||||
|
// for this file, which causes us to deadlock if we still held the lock.
|
||||||
|
if watchNum == 0 {
|
||||||
|
err = shared.watcher.Remove(fname)
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// sendEvent sends the input event to the appropriate Tail.
|
||||||
|
func (shared *InotifyTracker) sendEvent(event fsnotify.Event) {
|
||||||
|
name := filepath.Clean(event.Name)
|
||||||
|
|
||||||
|
shared.mux.Lock()
|
||||||
|
ch := shared.chans[name]
|
||||||
|
done := shared.done[name]
|
||||||
|
shared.mux.Unlock()
|
||||||
|
|
||||||
|
if ch != nil && done != nil {
|
||||||
|
select {
|
||||||
|
case ch <- event:
|
||||||
|
case <-done:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// run starts the goroutine in which the shared struct reads events from its
|
||||||
|
// Watcher's Event channel and sends the events to the appropriate Tail.
|
||||||
|
func (shared *InotifyTracker) run() {
|
||||||
|
watcher, err := fsnotify.NewWatcher()
|
||||||
|
if err != nil {
|
||||||
|
util.Fatal("failed to create Watcher")
|
||||||
|
}
|
||||||
|
shared.watcher = watcher
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case winfo := <-shared.watch:
|
||||||
|
shared.error <- shared.addWatch(winfo)
|
||||||
|
|
||||||
|
case winfo := <-shared.remove:
|
||||||
|
shared.error <- shared.removeWatch(winfo)
|
||||||
|
|
||||||
|
case event, open := <-shared.watcher.Events:
|
||||||
|
if !open {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
shared.sendEvent(event)
|
||||||
|
|
||||||
|
case err, open := <-shared.watcher.Errors:
|
||||||
|
if !open {
|
||||||
|
return
|
||||||
|
} else if err != nil {
|
||||||
|
sysErr, ok := err.(*os.SyscallError)
|
||||||
|
if !ok || sysErr.Err != syscall.EINTR {
|
||||||
|
logger.Printf("Error in Watcher Error channel: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
119
vendor/github.com/nxadm/tail/watch/polling.go
generated
vendored
Normal file
119
vendor/github.com/nxadm/tail/watch/polling.go
generated
vendored
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail
|
||||||
|
// Copyright (c) 2015 HPE Software Inc. All rights reserved.
|
||||||
|
// Copyright (c) 2013 ActiveState Software Inc. All rights reserved.
|
||||||
|
|
||||||
|
package watch
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/nxadm/tail/util"
|
||||||
|
"gopkg.in/tomb.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PollingFileWatcher polls the file for changes.
|
||||||
|
type PollingFileWatcher struct {
|
||||||
|
Filename string
|
||||||
|
Size int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPollingFileWatcher(filename string) *PollingFileWatcher {
|
||||||
|
fw := &PollingFileWatcher{filename, 0}
|
||||||
|
return fw
|
||||||
|
}
|
||||||
|
|
||||||
|
var POLL_DURATION time.Duration
|
||||||
|
|
||||||
|
func (fw *PollingFileWatcher) BlockUntilExists(t *tomb.Tomb) error {
|
||||||
|
for {
|
||||||
|
if _, err := os.Stat(fw.Filename); err == nil {
|
||||||
|
return nil
|
||||||
|
} else if !os.IsNotExist(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-time.After(POLL_DURATION):
|
||||||
|
continue
|
||||||
|
case <-t.Dying():
|
||||||
|
return tomb.ErrDying
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fw *PollingFileWatcher) ChangeEvents(t *tomb.Tomb, pos int64) (*FileChanges, error) {
|
||||||
|
origFi, err := os.Stat(fw.Filename)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
changes := NewFileChanges()
|
||||||
|
var prevModTime time.Time
|
||||||
|
|
||||||
|
// XXX: use tomb.Tomb to cleanly manage these goroutines. replace
|
||||||
|
// the fatal (below) with tomb's Kill.
|
||||||
|
|
||||||
|
fw.Size = pos
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
prevSize := fw.Size
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-t.Dying():
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(POLL_DURATION)
|
||||||
|
fi, err := os.Stat(fw.Filename)
|
||||||
|
if err != nil {
|
||||||
|
// Windows cannot delete a file if a handle is still open (tail keeps one open)
|
||||||
|
// so it gives access denied to anything trying to read it until all handles are released.
|
||||||
|
if os.IsNotExist(err) || (runtime.GOOS == "windows" && os.IsPermission(err)) {
|
||||||
|
// File does not exist (has been deleted).
|
||||||
|
changes.NotifyDeleted()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXX: report this error back to the user
|
||||||
|
util.Fatal("Failed to stat file %v: %v", fw.Filename, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// File got moved/renamed?
|
||||||
|
if !os.SameFile(origFi, fi) {
|
||||||
|
changes.NotifyDeleted()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// File got truncated?
|
||||||
|
fw.Size = fi.Size()
|
||||||
|
if prevSize > 0 && prevSize > fw.Size {
|
||||||
|
changes.NotifyTruncated()
|
||||||
|
prevSize = fw.Size
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// File got bigger?
|
||||||
|
if prevSize > 0 && prevSize < fw.Size {
|
||||||
|
changes.NotifyModified()
|
||||||
|
prevSize = fw.Size
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
prevSize = fw.Size
|
||||||
|
|
||||||
|
// File was appended to (changed)?
|
||||||
|
modTime := fi.ModTime()
|
||||||
|
if modTime != prevModTime {
|
||||||
|
prevModTime = modTime
|
||||||
|
changes.NotifyModified()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return changes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
POLL_DURATION = 250 * time.Millisecond
|
||||||
|
}
|
21
vendor/github.com/nxadm/tail/watch/watch.go
generated
vendored
Normal file
21
vendor/github.com/nxadm/tail/watch/watch.go
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail
|
||||||
|
// Copyright (c) 2015 HPE Software Inc. All rights reserved.
|
||||||
|
// Copyright (c) 2013 ActiveState Software Inc. All rights reserved.
|
||||||
|
|
||||||
|
package watch
|
||||||
|
|
||||||
|
import "gopkg.in/tomb.v1"
|
||||||
|
|
||||||
|
// FileWatcher monitors file-level events.
|
||||||
|
type FileWatcher interface {
|
||||||
|
// BlockUntilExists blocks until the file comes into existence.
|
||||||
|
BlockUntilExists(*tomb.Tomb) error
|
||||||
|
|
||||||
|
// ChangeEvents reports on changes to a file, be it modification,
|
||||||
|
// deletion, renames or truncations. Returned FileChanges group of
|
||||||
|
// channels will be closed, thus become unusable, after a deletion
|
||||||
|
// or truncation event.
|
||||||
|
// In order to properly report truncations, ChangeEvents requires
|
||||||
|
// the caller to pass their current offset in the file.
|
||||||
|
ChangeEvents(*tomb.Tomb, int64) (*FileChanges, error)
|
||||||
|
}
|
93
vendor/github.com/nxadm/tail/winfile/winfile.go
generated
vendored
Normal file
93
vendor/github.com/nxadm/tail/winfile/winfile.go
generated
vendored
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package winfile
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// issue also described here
|
||||||
|
//https://codereview.appspot.com/8203043/
|
||||||
|
|
||||||
|
// https://github.com/jnwhiteh/golang/blob/master/src/pkg/syscall/syscall_windows.go#L218
|
||||||
|
func Open(path string, mode int, perm uint32) (fd syscall.Handle, err error) {
|
||||||
|
if len(path) == 0 {
|
||||||
|
return syscall.InvalidHandle, syscall.ERROR_FILE_NOT_FOUND
|
||||||
|
}
|
||||||
|
pathp, err := syscall.UTF16PtrFromString(path)
|
||||||
|
if err != nil {
|
||||||
|
return syscall.InvalidHandle, err
|
||||||
|
}
|
||||||
|
var access uint32
|
||||||
|
switch mode & (syscall.O_RDONLY | syscall.O_WRONLY | syscall.O_RDWR) {
|
||||||
|
case syscall.O_RDONLY:
|
||||||
|
access = syscall.GENERIC_READ
|
||||||
|
case syscall.O_WRONLY:
|
||||||
|
access = syscall.GENERIC_WRITE
|
||||||
|
case syscall.O_RDWR:
|
||||||
|
access = syscall.GENERIC_READ | syscall.GENERIC_WRITE
|
||||||
|
}
|
||||||
|
if mode&syscall.O_CREAT != 0 {
|
||||||
|
access |= syscall.GENERIC_WRITE
|
||||||
|
}
|
||||||
|
if mode&syscall.O_APPEND != 0 {
|
||||||
|
access &^= syscall.GENERIC_WRITE
|
||||||
|
access |= syscall.FILE_APPEND_DATA
|
||||||
|
}
|
||||||
|
sharemode := uint32(syscall.FILE_SHARE_READ | syscall.FILE_SHARE_WRITE | syscall.FILE_SHARE_DELETE)
|
||||||
|
var sa *syscall.SecurityAttributes
|
||||||
|
if mode&syscall.O_CLOEXEC == 0 {
|
||||||
|
sa = makeInheritSa()
|
||||||
|
}
|
||||||
|
var createmode uint32
|
||||||
|
switch {
|
||||||
|
case mode&(syscall.O_CREAT|syscall.O_EXCL) == (syscall.O_CREAT | syscall.O_EXCL):
|
||||||
|
createmode = syscall.CREATE_NEW
|
||||||
|
case mode&(syscall.O_CREAT|syscall.O_TRUNC) == (syscall.O_CREAT | syscall.O_TRUNC):
|
||||||
|
createmode = syscall.CREATE_ALWAYS
|
||||||
|
case mode&syscall.O_CREAT == syscall.O_CREAT:
|
||||||
|
createmode = syscall.OPEN_ALWAYS
|
||||||
|
case mode&syscall.O_TRUNC == syscall.O_TRUNC:
|
||||||
|
createmode = syscall.TRUNCATE_EXISTING
|
||||||
|
default:
|
||||||
|
createmode = syscall.OPEN_EXISTING
|
||||||
|
}
|
||||||
|
h, e := syscall.CreateFile(pathp, access, sharemode, sa, createmode, syscall.FILE_ATTRIBUTE_NORMAL, 0)
|
||||||
|
return h, e
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://github.com/jnwhiteh/golang/blob/master/src/pkg/syscall/syscall_windows.go#L211
|
||||||
|
func makeInheritSa() *syscall.SecurityAttributes {
|
||||||
|
var sa syscall.SecurityAttributes
|
||||||
|
sa.Length = uint32(unsafe.Sizeof(sa))
|
||||||
|
sa.InheritHandle = 1
|
||||||
|
return &sa
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://github.com/jnwhiteh/golang/blob/master/src/pkg/os/file_windows.go#L133
|
||||||
|
func OpenFile(name string, flag int, perm os.FileMode) (file *os.File, err error) {
|
||||||
|
r, e := Open(name, flag|syscall.O_CLOEXEC, syscallMode(perm))
|
||||||
|
if e != nil {
|
||||||
|
return nil, e
|
||||||
|
}
|
||||||
|
return os.NewFile(uintptr(r), name), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://github.com/jnwhiteh/golang/blob/master/src/pkg/os/file_posix.go#L61
|
||||||
|
func syscallMode(i os.FileMode) (o uint32) {
|
||||||
|
o |= uint32(i.Perm())
|
||||||
|
if i&os.ModeSetuid != 0 {
|
||||||
|
o |= syscall.S_ISUID
|
||||||
|
}
|
||||||
|
if i&os.ModeSetgid != 0 {
|
||||||
|
o |= syscall.S_ISGID
|
||||||
|
}
|
||||||
|
if i&os.ModeSticky != 0 {
|
||||||
|
o |= syscall.S_ISVTX
|
||||||
|
}
|
||||||
|
// No mapping for Go's ModeTemporary (plan9 only).
|
||||||
|
return
|
||||||
|
}
|
201
vendor/github.com/prometheus/client_golang/LICENSE
generated
vendored
Normal file
201
vendor/github.com/prometheus/client_golang/LICENSE
generated
vendored
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
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.
|
23
vendor/github.com/prometheus/client_golang/NOTICE
generated
vendored
Normal file
23
vendor/github.com/prometheus/client_golang/NOTICE
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
Prometheus instrumentation library for Go applications
|
||||||
|
Copyright 2012-2015 The Prometheus Authors
|
||||||
|
|
||||||
|
This product includes software developed at
|
||||||
|
SoundCloud Ltd. (http://soundcloud.com/).
|
||||||
|
|
||||||
|
|
||||||
|
The following components are included in this product:
|
||||||
|
|
||||||
|
perks - a fork of https://github.com/bmizerany/perks
|
||||||
|
https://github.com/beorn7/perks
|
||||||
|
Copyright 2013-2015 Blake Mizerany, Björn Rabenstein
|
||||||
|
See https://github.com/beorn7/perks/blob/master/README.md for license details.
|
||||||
|
|
||||||
|
Go support for Protocol Buffers - Google's data interchange format
|
||||||
|
http://github.com/golang/protobuf/
|
||||||
|
Copyright 2010 The Go Authors
|
||||||
|
See source code for license details.
|
||||||
|
|
||||||
|
Support for streaming Protocol Buffer messages for the Go language (golang).
|
||||||
|
https://github.com/matttproud/golang_protobuf_extensions
|
||||||
|
Copyright 2013 Matt T. Proud
|
||||||
|
Licensed under the Apache License, Version 2.0
|
1
vendor/github.com/prometheus/client_golang/prometheus/.gitignore
generated
vendored
Normal file
1
vendor/github.com/prometheus/client_golang/prometheus/.gitignore
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
command-line-arguments.test
|
1
vendor/github.com/prometheus/client_golang/prometheus/README.md
generated
vendored
Normal file
1
vendor/github.com/prometheus/client_golang/prometheus/README.md
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
See [](https://pkg.go.dev/github.com/prometheus/client_golang/prometheus).
|
38
vendor/github.com/prometheus/client_golang/prometheus/build_info_collector.go
generated
vendored
Normal file
38
vendor/github.com/prometheus/client_golang/prometheus/build_info_collector.go
generated
vendored
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
// Copyright 2021 The Prometheus Authors
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package prometheus
|
||||||
|
|
||||||
|
import "runtime/debug"
|
||||||
|
|
||||||
|
// NewBuildInfoCollector is the obsolete version of collectors.NewBuildInfoCollector.
|
||||||
|
// See there for documentation.
|
||||||
|
//
|
||||||
|
// Deprecated: Use collectors.NewBuildInfoCollector instead.
|
||||||
|
func NewBuildInfoCollector() Collector {
|
||||||
|
path, version, sum := "unknown", "unknown", "unknown"
|
||||||
|
if bi, ok := debug.ReadBuildInfo(); ok {
|
||||||
|
path = bi.Main.Path
|
||||||
|
version = bi.Main.Version
|
||||||
|
sum = bi.Main.Sum
|
||||||
|
}
|
||||||
|
c := &selfCollector{MustNewConstMetric(
|
||||||
|
NewDesc(
|
||||||
|
"go_build_info",
|
||||||
|
"Build information about the main Go module.",
|
||||||
|
nil, Labels{"path": path, "version": version, "checksum": sum},
|
||||||
|
),
|
||||||
|
GaugeValue, 1)}
|
||||||
|
c.init(c.self)
|
||||||
|
return c
|
||||||
|
}
|
128
vendor/github.com/prometheus/client_golang/prometheus/collector.go
generated
vendored
Normal file
128
vendor/github.com/prometheus/client_golang/prometheus/collector.go
generated
vendored
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
// Copyright 2014 The Prometheus Authors
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package prometheus
|
||||||
|
|
||||||
|
// Collector is the interface implemented by anything that can be used by
|
||||||
|
// Prometheus to collect metrics. A Collector has to be registered for
|
||||||
|
// collection. See Registerer.Register.
|
||||||
|
//
|
||||||
|
// The stock metrics provided by this package (Gauge, Counter, Summary,
|
||||||
|
// Histogram, Untyped) are also Collectors (which only ever collect one metric,
|
||||||
|
// namely itself). An implementer of Collector may, however, collect multiple
|
||||||
|
// metrics in a coordinated fashion and/or create metrics on the fly. Examples
|
||||||
|
// for collectors already implemented in this library are the metric vectors
|
||||||
|
// (i.e. collection of multiple instances of the same Metric but with different
|
||||||
|
// label values) like GaugeVec or SummaryVec, and the ExpvarCollector.
|
||||||
|
type Collector interface {
|
||||||
|
// Describe sends the super-set of all possible descriptors of metrics
|
||||||
|
// collected by this Collector to the provided channel and returns once
|
||||||
|
// the last descriptor has been sent. The sent descriptors fulfill the
|
||||||
|
// consistency and uniqueness requirements described in the Desc
|
||||||
|
// documentation.
|
||||||
|
//
|
||||||
|
// It is valid if one and the same Collector sends duplicate
|
||||||
|
// descriptors. Those duplicates are simply ignored. However, two
|
||||||
|
// different Collectors must not send duplicate descriptors.
|
||||||
|
//
|
||||||
|
// Sending no descriptor at all marks the Collector as “unchecked”,
|
||||||
|
// i.e. no checks will be performed at registration time, and the
|
||||||
|
// Collector may yield any Metric it sees fit in its Collect method.
|
||||||
|
//
|
||||||
|
// This method idempotently sends the same descriptors throughout the
|
||||||
|
// lifetime of the Collector. It may be called concurrently and
|
||||||
|
// therefore must be implemented in a concurrency safe way.
|
||||||
|
//
|
||||||
|
// If a Collector encounters an error while executing this method, it
|
||||||
|
// must send an invalid descriptor (created with NewInvalidDesc) to
|
||||||
|
// signal the error to the registry.
|
||||||
|
Describe(chan<- *Desc)
|
||||||
|
// Collect is called by the Prometheus registry when collecting
|
||||||
|
// metrics. The implementation sends each collected metric via the
|
||||||
|
// provided channel and returns once the last metric has been sent. The
|
||||||
|
// descriptor of each sent metric is one of those returned by Describe
|
||||||
|
// (unless the Collector is unchecked, see above). Returned metrics that
|
||||||
|
// share the same descriptor must differ in their variable label
|
||||||
|
// values.
|
||||||
|
//
|
||||||
|
// This method may be called concurrently and must therefore be
|
||||||
|
// implemented in a concurrency safe way. Blocking occurs at the expense
|
||||||
|
// of total performance of rendering all registered metrics. Ideally,
|
||||||
|
// Collector implementations support concurrent readers.
|
||||||
|
Collect(chan<- Metric)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DescribeByCollect is a helper to implement the Describe method of a custom
|
||||||
|
// Collector. It collects the metrics from the provided Collector and sends
|
||||||
|
// their descriptors to the provided channel.
|
||||||
|
//
|
||||||
|
// If a Collector collects the same metrics throughout its lifetime, its
|
||||||
|
// Describe method can simply be implemented as:
|
||||||
|
//
|
||||||
|
// func (c customCollector) Describe(ch chan<- *Desc) {
|
||||||
|
// DescribeByCollect(c, ch)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// However, this will not work if the metrics collected change dynamically over
|
||||||
|
// the lifetime of the Collector in a way that their combined set of descriptors
|
||||||
|
// changes as well. The shortcut implementation will then violate the contract
|
||||||
|
// of the Describe method. If a Collector sometimes collects no metrics at all
|
||||||
|
// (for example vectors like CounterVec, GaugeVec, etc., which only collect
|
||||||
|
// metrics after a metric with a fully specified label set has been accessed),
|
||||||
|
// it might even get registered as an unchecked Collector (cf. the Register
|
||||||
|
// method of the Registerer interface). Hence, only use this shortcut
|
||||||
|
// implementation of Describe if you are certain to fulfill the contract.
|
||||||
|
//
|
||||||
|
// The Collector example demonstrates a use of DescribeByCollect.
|
||||||
|
func DescribeByCollect(c Collector, descs chan<- *Desc) {
|
||||||
|
metrics := make(chan Metric)
|
||||||
|
go func() {
|
||||||
|
c.Collect(metrics)
|
||||||
|
close(metrics)
|
||||||
|
}()
|
||||||
|
for m := range metrics {
|
||||||
|
descs <- m.Desc()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// selfCollector implements Collector for a single Metric so that the Metric
|
||||||
|
// collects itself. Add it as an anonymous field to a struct that implements
|
||||||
|
// Metric, and call init with the Metric itself as an argument.
|
||||||
|
type selfCollector struct {
|
||||||
|
self Metric
|
||||||
|
}
|
||||||
|
|
||||||
|
// init provides the selfCollector with a reference to the metric it is supposed
|
||||||
|
// to collect. It is usually called within the factory function to create a
|
||||||
|
// metric. See example.
|
||||||
|
func (c *selfCollector) init(self Metric) {
|
||||||
|
c.self = self
|
||||||
|
}
|
||||||
|
|
||||||
|
// Describe implements Collector.
|
||||||
|
func (c *selfCollector) Describe(ch chan<- *Desc) {
|
||||||
|
ch <- c.self.Desc()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect implements Collector.
|
||||||
|
func (c *selfCollector) Collect(ch chan<- Metric) {
|
||||||
|
ch <- c.self
|
||||||
|
}
|
||||||
|
|
||||||
|
// collectorMetric is a metric that is also a collector.
|
||||||
|
// Because of selfCollector, most (if not all) Metrics in
|
||||||
|
// this package are also collectors.
|
||||||
|
type collectorMetric interface {
|
||||||
|
Metric
|
||||||
|
Collector
|
||||||
|
}
|
325
vendor/github.com/prometheus/client_golang/prometheus/counter.go
generated
vendored
Normal file
325
vendor/github.com/prometheus/client_golang/prometheus/counter.go
generated
vendored
Normal file
@ -0,0 +1,325 @@
|
|||||||
|
// Copyright 2014 The Prometheus Authors
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package prometheus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"math"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
dto "github.com/prometheus/client_model/go"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Counter is a Metric that represents a single numerical value that only ever
|
||||||
|
// goes up. That implies that it cannot be used to count items whose number can
|
||||||
|
// also go down, e.g. the number of currently running goroutines. Those
|
||||||
|
// "counters" are represented by Gauges.
|
||||||
|
//
|
||||||
|
// A Counter is typically used to count requests served, tasks completed, errors
|
||||||
|
// occurred, etc.
|
||||||
|
//
|
||||||
|
// To create Counter instances, use NewCounter.
|
||||||
|
type Counter interface {
|
||||||
|
Metric
|
||||||
|
Collector
|
||||||
|
|
||||||
|
// Inc increments the counter by 1. Use Add to increment it by arbitrary
|
||||||
|
// non-negative values.
|
||||||
|
Inc()
|
||||||
|
// Add adds the given value to the counter. It panics if the value is <
|
||||||
|
// 0.
|
||||||
|
Add(float64)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExemplarAdder is implemented by Counters that offer the option of adding a
|
||||||
|
// value to the Counter together with an exemplar. Its AddWithExemplar method
|
||||||
|
// works like the Add method of the Counter interface but also replaces the
|
||||||
|
// currently saved exemplar (if any) with a new one, created from the provided
|
||||||
|
// value, the current time as timestamp, and the provided labels. Empty Labels
|
||||||
|
// will lead to a valid (label-less) exemplar. But if Labels is nil, the current
|
||||||
|
// exemplar is left in place. AddWithExemplar panics if the value is < 0, if any
|
||||||
|
// of the provided labels are invalid, or if the provided labels contain more
|
||||||
|
// than 128 runes in total.
|
||||||
|
type ExemplarAdder interface {
|
||||||
|
AddWithExemplar(value float64, exemplar Labels)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CounterOpts is an alias for Opts. See there for doc comments.
|
||||||
|
type CounterOpts Opts
|
||||||
|
|
||||||
|
// NewCounter creates a new Counter based on the provided CounterOpts.
|
||||||
|
//
|
||||||
|
// The returned implementation also implements ExemplarAdder. It is safe to
|
||||||
|
// perform the corresponding type assertion.
|
||||||
|
//
|
||||||
|
// The returned implementation tracks the counter value in two separate
|
||||||
|
// variables, a float64 and a uint64. The latter is used to track calls of the
|
||||||
|
// Inc method and calls of the Add method with a value that can be represented
|
||||||
|
// as a uint64. This allows atomic increments of the counter with optimal
|
||||||
|
// performance. (It is common to have an Inc call in very hot execution paths.)
|
||||||
|
// Both internal tracking values are added up in the Write method. This has to
|
||||||
|
// be taken into account when it comes to precision and overflow behavior.
|
||||||
|
func NewCounter(opts CounterOpts) Counter {
|
||||||
|
desc := NewDesc(
|
||||||
|
BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
|
||||||
|
opts.Help,
|
||||||
|
nil,
|
||||||
|
opts.ConstLabels,
|
||||||
|
)
|
||||||
|
result := &counter{desc: desc, labelPairs: desc.constLabelPairs, now: time.Now}
|
||||||
|
result.init(result) // Init self-collection.
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
type counter struct {
|
||||||
|
// valBits contains the bits of the represented float64 value, while
|
||||||
|
// valInt stores values that are exact integers. Both have to go first
|
||||||
|
// in the struct to guarantee alignment for atomic operations.
|
||||||
|
// http://golang.org/pkg/sync/atomic/#pkg-note-BUG
|
||||||
|
valBits uint64
|
||||||
|
valInt uint64
|
||||||
|
|
||||||
|
selfCollector
|
||||||
|
desc *Desc
|
||||||
|
|
||||||
|
labelPairs []*dto.LabelPair
|
||||||
|
exemplar atomic.Value // Containing nil or a *dto.Exemplar.
|
||||||
|
|
||||||
|
now func() time.Time // To mock out time.Now() for testing.
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *counter) Desc() *Desc {
|
||||||
|
return c.desc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *counter) Add(v float64) {
|
||||||
|
if v < 0 {
|
||||||
|
panic(errors.New("counter cannot decrease in value"))
|
||||||
|
}
|
||||||
|
|
||||||
|
ival := uint64(v)
|
||||||
|
if float64(ival) == v {
|
||||||
|
atomic.AddUint64(&c.valInt, ival)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
oldBits := atomic.LoadUint64(&c.valBits)
|
||||||
|
newBits := math.Float64bits(math.Float64frombits(oldBits) + v)
|
||||||
|
if atomic.CompareAndSwapUint64(&c.valBits, oldBits, newBits) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *counter) AddWithExemplar(v float64, e Labels) {
|
||||||
|
c.Add(v)
|
||||||
|
c.updateExemplar(v, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *counter) Inc() {
|
||||||
|
atomic.AddUint64(&c.valInt, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *counter) get() float64 {
|
||||||
|
fval := math.Float64frombits(atomic.LoadUint64(&c.valBits))
|
||||||
|
ival := atomic.LoadUint64(&c.valInt)
|
||||||
|
return fval + float64(ival)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *counter) Write(out *dto.Metric) error {
|
||||||
|
val := c.get()
|
||||||
|
|
||||||
|
var exemplar *dto.Exemplar
|
||||||
|
if e := c.exemplar.Load(); e != nil {
|
||||||
|
exemplar = e.(*dto.Exemplar)
|
||||||
|
}
|
||||||
|
|
||||||
|
return populateMetric(CounterValue, val, c.labelPairs, exemplar, out)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *counter) updateExemplar(v float64, l Labels) {
|
||||||
|
if l == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e, err := newExemplar(v, c.now(), l)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
c.exemplar.Store(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CounterVec is a Collector that bundles a set of Counters that all share the
|
||||||
|
// same Desc, but have different values for their variable labels. This is used
|
||||||
|
// if you want to count the same thing partitioned by various dimensions
|
||||||
|
// (e.g. number of HTTP requests, partitioned by response code and
|
||||||
|
// method). Create instances with NewCounterVec.
|
||||||
|
type CounterVec struct {
|
||||||
|
*MetricVec
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCounterVec creates a new CounterVec based on the provided CounterOpts and
|
||||||
|
// partitioned by the given label names.
|
||||||
|
func NewCounterVec(opts CounterOpts, labelNames []string) *CounterVec {
|
||||||
|
desc := NewDesc(
|
||||||
|
BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
|
||||||
|
opts.Help,
|
||||||
|
labelNames,
|
||||||
|
opts.ConstLabels,
|
||||||
|
)
|
||||||
|
return &CounterVec{
|
||||||
|
MetricVec: NewMetricVec(desc, func(lvs ...string) Metric {
|
||||||
|
if len(lvs) != len(desc.variableLabels) {
|
||||||
|
panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, lvs))
|
||||||
|
}
|
||||||
|
result := &counter{desc: desc, labelPairs: MakeLabelPairs(desc, lvs), now: time.Now}
|
||||||
|
result.init(result) // Init self-collection.
|
||||||
|
return result
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMetricWithLabelValues returns the Counter for the given slice of label
|
||||||
|
// values (same order as the variable labels in Desc). If that combination of
|
||||||
|
// label values is accessed for the first time, a new Counter is created.
|
||||||
|
//
|
||||||
|
// It is possible to call this method without using the returned Counter to only
|
||||||
|
// create the new Counter but leave it at its starting value 0. See also the
|
||||||
|
// SummaryVec example.
|
||||||
|
//
|
||||||
|
// Keeping the Counter for later use is possible (and should be considered if
|
||||||
|
// performance is critical), but keep in mind that Reset, DeleteLabelValues and
|
||||||
|
// Delete can be used to delete the Counter from the CounterVec. In that case,
|
||||||
|
// the Counter will still exist, but it will not be exported anymore, even if a
|
||||||
|
// Counter with the same label values is created later.
|
||||||
|
//
|
||||||
|
// An error is returned if the number of label values is not the same as the
|
||||||
|
// number of variable labels in Desc (minus any curried labels).
|
||||||
|
//
|
||||||
|
// Note that for more than one label value, this method is prone to mistakes
|
||||||
|
// caused by an incorrect order of arguments. Consider GetMetricWith(Labels) as
|
||||||
|
// an alternative to avoid that type of mistake. For higher label numbers, the
|
||||||
|
// latter has a much more readable (albeit more verbose) syntax, but it comes
|
||||||
|
// with a performance overhead (for creating and processing the Labels map).
|
||||||
|
// See also the GaugeVec example.
|
||||||
|
func (v *CounterVec) GetMetricWithLabelValues(lvs ...string) (Counter, error) {
|
||||||
|
metric, err := v.MetricVec.GetMetricWithLabelValues(lvs...)
|
||||||
|
if metric != nil {
|
||||||
|
return metric.(Counter), err
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMetricWith returns the Counter for the given Labels map (the label names
|
||||||
|
// must match those of the variable labels in Desc). If that label map is
|
||||||
|
// accessed for the first time, a new Counter is created. Implications of
|
||||||
|
// creating a Counter without using it and keeping the Counter for later use are
|
||||||
|
// the same as for GetMetricWithLabelValues.
|
||||||
|
//
|
||||||
|
// An error is returned if the number and names of the Labels are inconsistent
|
||||||
|
// with those of the variable labels in Desc (minus any curried labels).
|
||||||
|
//
|
||||||
|
// This method is used for the same purpose as
|
||||||
|
// GetMetricWithLabelValues(...string). See there for pros and cons of the two
|
||||||
|
// methods.
|
||||||
|
func (v *CounterVec) GetMetricWith(labels Labels) (Counter, error) {
|
||||||
|
metric, err := v.MetricVec.GetMetricWith(labels)
|
||||||
|
if metric != nil {
|
||||||
|
return metric.(Counter), err
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithLabelValues works as GetMetricWithLabelValues, but panics where
|
||||||
|
// GetMetricWithLabelValues would have returned an error. Not returning an
|
||||||
|
// error allows shortcuts like
|
||||||
|
// myVec.WithLabelValues("404", "GET").Add(42)
|
||||||
|
func (v *CounterVec) WithLabelValues(lvs ...string) Counter {
|
||||||
|
c, err := v.GetMetricWithLabelValues(lvs...)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// With works as GetMetricWith, but panics where GetMetricWithLabels would have
|
||||||
|
// returned an error. Not returning an error allows shortcuts like
|
||||||
|
// myVec.With(prometheus.Labels{"code": "404", "method": "GET"}).Add(42)
|
||||||
|
func (v *CounterVec) With(labels Labels) Counter {
|
||||||
|
c, err := v.GetMetricWith(labels)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// CurryWith returns a vector curried with the provided labels, i.e. the
|
||||||
|
// returned vector has those labels pre-set for all labeled operations performed
|
||||||
|
// on it. The cardinality of the curried vector is reduced accordingly. The
|
||||||
|
// order of the remaining labels stays the same (just with the curried labels
|
||||||
|
// taken out of the sequence – which is relevant for the
|
||||||
|
// (GetMetric)WithLabelValues methods). It is possible to curry a curried
|
||||||
|
// vector, but only with labels not yet used for currying before.
|
||||||
|
//
|
||||||
|
// The metrics contained in the CounterVec are shared between the curried and
|
||||||
|
// uncurried vectors. They are just accessed differently. Curried and uncurried
|
||||||
|
// vectors behave identically in terms of collection. Only one must be
|
||||||
|
// registered with a given registry (usually the uncurried version). The Reset
|
||||||
|
// method deletes all metrics, even if called on a curried vector.
|
||||||
|
func (v *CounterVec) CurryWith(labels Labels) (*CounterVec, error) {
|
||||||
|
vec, err := v.MetricVec.CurryWith(labels)
|
||||||
|
if vec != nil {
|
||||||
|
return &CounterVec{vec}, err
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustCurryWith works as CurryWith but panics where CurryWith would have
|
||||||
|
// returned an error.
|
||||||
|
func (v *CounterVec) MustCurryWith(labels Labels) *CounterVec {
|
||||||
|
vec, err := v.CurryWith(labels)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return vec
|
||||||
|
}
|
||||||
|
|
||||||
|
// CounterFunc is a Counter whose value is determined at collect time by calling a
|
||||||
|
// provided function.
|
||||||
|
//
|
||||||
|
// To create CounterFunc instances, use NewCounterFunc.
|
||||||
|
type CounterFunc interface {
|
||||||
|
Metric
|
||||||
|
Collector
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCounterFunc creates a new CounterFunc based on the provided
|
||||||
|
// CounterOpts. The value reported is determined by calling the given function
|
||||||
|
// from within the Write method. Take into account that metric collection may
|
||||||
|
// happen concurrently. If that results in concurrent calls to Write, like in
|
||||||
|
// the case where a CounterFunc is directly registered with Prometheus, the
|
||||||
|
// provided function must be concurrency-safe. The function should also honor
|
||||||
|
// the contract for a Counter (values only go up, not down), but compliance will
|
||||||
|
// not be checked.
|
||||||
|
//
|
||||||
|
// Check out the ExampleGaugeFunc examples for the similar GaugeFunc.
|
||||||
|
func NewCounterFunc(opts CounterOpts, function func() float64) CounterFunc {
|
||||||
|
return newValueFunc(NewDesc(
|
||||||
|
BuildFQName(opts.Namespace, opts.Subsystem, opts.Name),
|
||||||
|
opts.Help,
|
||||||
|
nil,
|
||||||
|
opts.ConstLabels,
|
||||||
|
), CounterValue, function)
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user